blob: 86bdd535f2c02d215135cfbd105990b9c202ef9a [file] [log] [blame]
Keir Mierle866cff42020-04-28 22:24:44 -07001// Copyright 2020 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14
15#include "pw_ring_buffer/prefixed_entry_ring_buffer.h"
16
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -080017#include <algorithm>
Keir Mierle866cff42020-04-28 22:24:44 -070018#include <cstring>
19
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -080020#include "pw_assert/light.h"
Keir Mierle866cff42020-04-28 22:24:44 -070021#include "pw_varint/varint.h"
22
23namespace pw {
24namespace ring_buffer {
25
26using std::byte;
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -080027using Reader = PrefixedEntryRingBufferMulti::Reader;
Keir Mierle866cff42020-04-28 22:24:44 -070028
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -080029void PrefixedEntryRingBufferMulti::Clear() {
Keir Mierle866cff42020-04-28 22:24:44 -070030 write_idx_ = 0;
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -080031 for (Reader& reader : readers_) {
32 reader.read_idx = 0;
33 reader.entry_count = 0;
34 }
Keir Mierle866cff42020-04-28 22:24:44 -070035}
36
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -080037Status PrefixedEntryRingBufferMulti::SetBuffer(std::span<byte> buffer) {
Keir Mierle866cff42020-04-28 22:24:44 -070038 if ((buffer.data() == nullptr) || //
39 (buffer.size_bytes() == 0) || //
40 (buffer.size_bytes() > kMaxBufferBytes)) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -070041 return Status::InvalidArgument();
Keir Mierle866cff42020-04-28 22:24:44 -070042 }
43
44 buffer_ = buffer.data();
45 buffer_bytes_ = buffer.size_bytes();
46
47 Clear();
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080048 return OkStatus();
Keir Mierle866cff42020-04-28 22:24:44 -070049}
50
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -080051Status PrefixedEntryRingBufferMulti::AttachReader(Reader& reader) {
52 if (reader.buffer != nullptr) {
53 return Status::InvalidArgument();
54 }
55 reader.buffer = this;
56
57 // Note that a newly attached reader sees the buffer as empty,
58 // and is not privy to entries pushed before being attached.
59 reader.read_idx = write_idx_;
60 reader.entry_count = 0;
61 readers_.push_back(reader);
62 return OkStatus();
63}
64
65Status PrefixedEntryRingBufferMulti::DetachReader(Reader& reader) {
66 if (reader.buffer != this) {
67 return Status::InvalidArgument();
68 }
69 reader.buffer = nullptr;
70 reader.read_idx = 0;
71 reader.entry_count = 0;
72 readers_.remove(reader);
73 return OkStatus();
74}
75
76Status PrefixedEntryRingBufferMulti::InternalPushBack(
77 std::span<const byte> data,
Prashanth Swaminathan44202c92021-03-03 13:23:54 -080078 uint32_t user_preamble_data,
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -080079 bool drop_elements_if_needed) {
Keir Mierle866cff42020-04-28 22:24:44 -070080 if (buffer_ == nullptr) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -070081 return Status::FailedPrecondition();
Keir Mierle866cff42020-04-28 22:24:44 -070082 }
83 if (data.size_bytes() == 0) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -070084 return Status::InvalidArgument();
Keir Mierle866cff42020-04-28 22:24:44 -070085 }
86
Prashanth Swaminathand240cbd2021-03-04 17:31:33 -080087 // Prepare a single buffer that can hold both the user preamble and entry
88 // length.
89 byte preamble_buf[varint::kMaxVarint32SizeBytes * 2];
Prashanth Swaminathan44202c92021-03-03 13:23:54 -080090 size_t user_preamble_bytes = 0;
91 if (user_preamble_) {
92 user_preamble_bytes =
93 varint::Encode<uint32_t>(user_preamble_data, preamble_buf);
94 }
Prashanth Swaminathand240cbd2021-03-04 17:31:33 -080095 size_t length_bytes = varint::Encode<uint32_t>(
96 data.size_bytes(), std::span(preamble_buf).subspan(user_preamble_bytes));
Keir Mierle866cff42020-04-28 22:24:44 -070097 size_t total_write_bytes =
Prashanth Swaminathan44202c92021-03-03 13:23:54 -080098 user_preamble_bytes + length_bytes + data.size_bytes();
Keir Mierle866cff42020-04-28 22:24:44 -070099 if (buffer_bytes_ < total_write_bytes) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700100 return Status::OutOfRange();
Keir Mierle866cff42020-04-28 22:24:44 -0700101 }
102
Keir Mierlebcdf4602020-05-07 11:39:45 -0700103 if (drop_elements_if_needed) {
104 // PushBack() case: evict items as needed.
105 // Drop old entries until we have space for the new entry.
106 while (RawAvailableBytes() < total_write_bytes) {
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -0800107 InternalPopFrontAll();
Keir Mierlebcdf4602020-05-07 11:39:45 -0700108 }
109 } else if (RawAvailableBytes() < total_write_bytes) {
110 // TryPushBack() case: don't evict items.
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700111 return Status::ResourceExhausted();
Keir Mierle866cff42020-04-28 22:24:44 -0700112 }
113
114 // Write the new entry into the ring buffer.
Prashanth Swaminathand240cbd2021-03-04 17:31:33 -0800115 RawWrite(std::span(preamble_buf, user_preamble_bytes + length_bytes));
Keir Mierle866cff42020-04-28 22:24:44 -0700116 RawWrite(data);
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -0800117
118 // Update all readers of the new count.
119 for (Reader& reader : readers_) {
120 reader.entry_count++;
121 }
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800122 return OkStatus();
Keir Mierle866cff42020-04-28 22:24:44 -0700123}
124
Wyatt Heplere2cbadf2020-06-22 11:21:45 -0700125auto GetOutput(std::span<byte> data_out, size_t* write_index) {
126 return [data_out, write_index](std::span<const byte> src) -> Status {
Keir Mierle866cff42020-04-28 22:24:44 -0700127 size_t copy_size = std::min(data_out.size_bytes(), src.size_bytes());
128
129 memcpy(data_out.data() + *write_index, src.data(), copy_size);
130 *write_index += copy_size;
131
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800132 return (copy_size == src.size_bytes()) ? OkStatus()
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700133 : Status::ResourceExhausted();
Keir Mierle866cff42020-04-28 22:24:44 -0700134 };
135}
136
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -0800137Status PrefixedEntryRingBufferMulti::InternalPeekFront(Reader& reader,
138 std::span<byte> data,
Prashanth Swaminathand9be1132021-03-10 14:55:23 -0800139 size_t* bytes_read_out) {
140 *bytes_read_out = 0;
141 return InternalRead(reader, GetOutput(data, bytes_read_out), false);
Keir Mierle866cff42020-04-28 22:24:44 -0700142}
143
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -0800144Status PrefixedEntryRingBufferMulti::InternalPeekFront(Reader& reader,
145 ReadOutput output) {
146 return InternalRead(reader, output, false);
Keir Mierle866cff42020-04-28 22:24:44 -0700147}
148
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -0800149Status PrefixedEntryRingBufferMulti::InternalPeekFrontWithPreamble(
Prashanth Swaminathand9be1132021-03-10 14:55:23 -0800150 Reader& reader, std::span<byte> data, size_t* bytes_read_out) {
151 *bytes_read_out = 0;
152 return InternalRead(reader, GetOutput(data, bytes_read_out), true);
Keir Mierle866cff42020-04-28 22:24:44 -0700153}
154
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -0800155Status PrefixedEntryRingBufferMulti::InternalPeekFrontWithPreamble(
156 Reader& reader, ReadOutput output) {
157 return InternalRead(reader, output, true);
Keir Mierle866cff42020-04-28 22:24:44 -0700158}
159
Prashanth Swaminathand9be1132021-03-10 14:55:23 -0800160// TODO(pwbug/339): Consider whether this internal templating is required, or if
161// we can simply promote GetOutput to a static function and remove the template.
Wyatt Heplere2cbadf2020-06-22 11:21:45 -0700162// T should be similar to Status (*read_output)(std::span<const byte>)
Keir Mierle866cff42020-04-28 22:24:44 -0700163template <typename T>
Prashanth Swaminathand9be1132021-03-10 14:55:23 -0800164Status PrefixedEntryRingBufferMulti::InternalRead(
165 Reader& reader,
166 T read_output,
167 bool include_preamble_in_output,
168 uint32_t* user_preamble_out) {
Keir Mierle866cff42020-04-28 22:24:44 -0700169 if (buffer_ == nullptr) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700170 return Status::FailedPrecondition();
Keir Mierle866cff42020-04-28 22:24:44 -0700171 }
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -0800172 if (reader.entry_count == 0) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700173 return Status::OutOfRange();
Keir Mierle866cff42020-04-28 22:24:44 -0700174 }
175
176 // Figure out where to start reading (wrapped); accounting for preamble.
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -0800177 EntryInfo info = FrontEntryInfo(reader);
Keir Mierle866cff42020-04-28 22:24:44 -0700178 size_t read_bytes = info.data_bytes;
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -0800179 size_t data_read_idx = reader.read_idx;
Prashanth Swaminathand9be1132021-03-10 14:55:23 -0800180 if (user_preamble_out) {
181 *user_preamble_out = info.user_preamble;
182 }
183 if (include_preamble_in_output) {
Keir Mierle866cff42020-04-28 22:24:44 -0700184 read_bytes += info.preamble_bytes;
185 } else {
186 data_read_idx = IncrementIndex(data_read_idx, info.preamble_bytes);
187 }
188
189 // Read bytes, stopping at the end of the buffer if this entry wraps.
190 size_t bytes_until_wrap = buffer_bytes_ - data_read_idx;
191 size_t bytes_to_copy = std::min(read_bytes, bytes_until_wrap);
Wyatt Heplere2cbadf2020-06-22 11:21:45 -0700192 Status status =
193 read_output(std::span(buffer_ + data_read_idx, bytes_to_copy));
Keir Mierle866cff42020-04-28 22:24:44 -0700194
195 // If the entry wrapped, read the remaining bytes.
196 if (status.ok() && (bytes_to_copy < read_bytes)) {
Wyatt Heplere2cbadf2020-06-22 11:21:45 -0700197 status = read_output(std::span(buffer_, read_bytes - bytes_to_copy));
Keir Mierle866cff42020-04-28 22:24:44 -0700198 }
199 return status;
200}
201
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -0800202void PrefixedEntryRingBufferMulti::InternalPopFrontAll() {
203 // Forcefully pop all readers. Find the slowest reader, which must have
204 // the highest entry count, then pop all readers that have the same count.
Prashanth Swaminathan3c81ec22021-02-22 13:21:26 -0800205 //
206 // It is expected that InternalPopFrontAll is called only when there is
207 // something to pop from at least one reader. If no readers exist, or all
208 // readers are caught up, this function will assert.
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -0800209 size_t entry_count = GetSlowestReader().entry_count;
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -0800210 PW_DASSERT(entry_count != 0);
211 // Otherwise, pop the readers that have the largest value.
212 for (Reader& reader : readers_) {
213 if (reader.entry_count == entry_count) {
214 reader.PopFront();
215 }
Keir Mierle866cff42020-04-28 22:24:44 -0700216 }
Keir Mierle866cff42020-04-28 22:24:44 -0700217}
218
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -0800219Reader& PrefixedEntryRingBufferMulti::GetSlowestReader() {
220 // Readers are guaranteed to be before the writer pointer (the class enforces
221 // this on every read/write operation that forces the write pointer ahead of
222 // an existing reader). To determine the slowest reader, we consider three
223 // scenarios:
224 //
Prashanth Swaminathan3c81ec22021-02-22 13:21:26 -0800225 // In all below cases, WH is the write-head, and R# are readers, with R1
226 // representing the slowest reader.
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -0800227 // [[R1 R2 R3 WH]] => Right-hand writer, slowest reader is left-most reader.
228 // [[WH R1 R2 R3]] => Left-hand writer, slowest reader is left-most reader.
229 // [[R3 WH R1 R2]] => Middle-writer, slowest reader is left-most reader after
230 // writer.
231 //
232 // Formally, choose the left-most reader after the writer (ex.2,3), but if
233 // that doesn't exist, choose the left-most reader before the writer (ex.1).
234 PW_DASSERT(readers_.size() > 0);
235 Reader* slowest_reader_after_writer = nullptr;
236 Reader* slowest_reader_before_writer = nullptr;
237 for (Reader& reader : readers_) {
238 if (reader.read_idx < write_idx_) {
239 if (!slowest_reader_before_writer ||
240 reader.read_idx < slowest_reader_before_writer->read_idx) {
241 slowest_reader_before_writer = &reader;
242 }
243 } else {
244 if (!slowest_reader_after_writer ||
245 reader.read_idx < slowest_reader_after_writer->read_idx) {
246 slowest_reader_after_writer = &reader;
247 }
248 }
249 }
250 return *(slowest_reader_after_writer ? slowest_reader_after_writer
251 : slowest_reader_before_writer);
252}
253
254Status PrefixedEntryRingBufferMulti::Dering() {
255 if (buffer_ == nullptr || readers_.size() == 0) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700256 return Status::FailedPrecondition();
Keir Mierle866cff42020-04-28 22:24:44 -0700257 }
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -0800258
Keir Mierle866cff42020-04-28 22:24:44 -0700259 // Check if by luck we're already deringed.
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -0800260 Reader* slowest_reader = &GetSlowestReader();
261 if (slowest_reader->read_idx == 0) {
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800262 return OkStatus();
Keir Mierle866cff42020-04-28 22:24:44 -0700263 }
264
Wyatt Heplere2cbadf2020-06-22 11:21:45 -0700265 auto buffer_span = std::span(buffer_, buffer_bytes_);
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -0800266 std::rotate(buffer_span.begin(),
267 buffer_span.begin() + slowest_reader->read_idx,
268 buffer_span.end());
Keir Mierle866cff42020-04-28 22:24:44 -0700269
270 // If the new index is past the end of the buffer,
271 // alias it back (wrap) to the start of the buffer.
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -0800272 if (write_idx_ < slowest_reader->read_idx) {
Keir Mierle866cff42020-04-28 22:24:44 -0700273 write_idx_ += buffer_bytes_;
274 }
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -0800275 write_idx_ -= slowest_reader->read_idx;
276
277 for (Reader& reader : readers_) {
278 if (&reader == slowest_reader) {
279 continue;
280 }
281 if (reader.read_idx < slowest_reader->read_idx) {
282 reader.read_idx += buffer_bytes_;
283 }
284 reader.read_idx -= slowest_reader->read_idx;
285 }
286
287 slowest_reader->read_idx = 0;
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800288 return OkStatus();
Keir Mierle866cff42020-04-28 22:24:44 -0700289}
290
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -0800291Status PrefixedEntryRingBufferMulti::InternalPopFront(Reader& reader) {
292 if (buffer_ == nullptr) {
293 return Status::FailedPrecondition();
Keir Mierle866cff42020-04-28 22:24:44 -0700294 }
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -0800295 if (reader.entry_count == 0) {
296 return Status::OutOfRange();
297 }
298
299 // Advance the read pointer past the front entry to the next one.
300 EntryInfo info = FrontEntryInfo(reader);
301 size_t entry_bytes = info.preamble_bytes + info.data_bytes;
302 size_t prev_read_idx = reader.read_idx;
303 reader.read_idx = IncrementIndex(prev_read_idx, entry_bytes);
304 reader.entry_count--;
305 return OkStatus();
Keir Mierle866cff42020-04-28 22:24:44 -0700306}
307
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -0800308size_t PrefixedEntryRingBufferMulti::InternalFrontEntryDataSizeBytes(
309 Reader& reader) {
310 if (reader.entry_count == 0) {
Keir Mierle866cff42020-04-28 22:24:44 -0700311 return 0;
312 }
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -0800313 return FrontEntryInfo(reader).data_bytes;
314}
315
316size_t PrefixedEntryRingBufferMulti::InternalFrontEntryTotalSizeBytes(
317 Reader& reader) {
318 if (reader.entry_count == 0) {
319 return 0;
320 }
321 EntryInfo info = FrontEntryInfo(reader);
Keir Mierle866cff42020-04-28 22:24:44 -0700322 return info.preamble_bytes + info.data_bytes;
323}
324
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -0800325PrefixedEntryRingBufferMulti::EntryInfo
326PrefixedEntryRingBufferMulti::FrontEntryInfo(Reader& reader) {
Keir Mierle866cff42020-04-28 22:24:44 -0700327 // Entry headers consists of: (optional prefix byte, varint size, data...)
328
Prashanth Swaminathan44202c92021-03-03 13:23:54 -0800329 // If a preamble exists, extract the varint and it's bytes in bytes.
330 size_t user_preamble_bytes = 0;
Prashanth Swaminathand9be1132021-03-10 14:55:23 -0800331 uint64_t user_preamble_data = 0;
Prashanth Swaminathan44202c92021-03-03 13:23:54 -0800332 byte varint_buf[varint::kMaxVarint32SizeBytes];
333 if (user_preamble_) {
334 RawRead(varint_buf, reader.read_idx, varint::kMaxVarint32SizeBytes);
Prashanth Swaminathan44202c92021-03-03 13:23:54 -0800335 user_preamble_bytes = varint::Decode(varint_buf, &user_preamble_data);
336 PW_DASSERT(user_preamble_bytes != 0u);
337 }
338
339 // Read the entry header; extract the varint and it's bytes in bytes.
Keir Mierle866cff42020-04-28 22:24:44 -0700340 RawRead(varint_buf,
Prashanth Swaminathan44202c92021-03-03 13:23:54 -0800341 IncrementIndex(reader.read_idx, user_preamble_bytes),
342 varint::kMaxVarint32SizeBytes);
343 uint64_t entry_bytes;
344 size_t length_bytes = varint::Decode(varint_buf, &entry_bytes);
345 PW_DASSERT(length_bytes != 0u);
Keir Mierle866cff42020-04-28 22:24:44 -0700346
347 EntryInfo info = {};
Prashanth Swaminathan44202c92021-03-03 13:23:54 -0800348 info.preamble_bytes = user_preamble_bytes + length_bytes;
Prashanth Swaminathand9be1132021-03-10 14:55:23 -0800349 info.user_preamble = static_cast<uint32_t>(user_preamble_data);
Prashanth Swaminathan44202c92021-03-03 13:23:54 -0800350 info.data_bytes = entry_bytes;
Keir Mierle866cff42020-04-28 22:24:44 -0700351 return info;
352}
353
354// Comparisons ordered for more probable early exits, assuming the reader is
355// not far behind the writer compared to the size of the ring.
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -0800356size_t PrefixedEntryRingBufferMulti::RawAvailableBytes() {
357 // Compute slowest reader.
358 // TODO: Alternatively, the slowest reader could be actively mantained on
359 // every read operation, but reads are more likely than writes.
360 if (readers_.size() == 0) {
361 return buffer_bytes_;
362 }
363
364 size_t read_idx = GetSlowestReader().read_idx;
Keir Mierle866cff42020-04-28 22:24:44 -0700365 // Case: Not wrapped.
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -0800366 if (read_idx < write_idx_) {
367 return buffer_bytes_ - (write_idx_ - read_idx);
Keir Mierle866cff42020-04-28 22:24:44 -0700368 }
369 // Case: Wrapped
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -0800370 if (read_idx > write_idx_) {
371 return read_idx - write_idx_;
Keir Mierle866cff42020-04-28 22:24:44 -0700372 }
373 // Case: Matched read and write heads; empty or full.
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -0800374 for (Reader& reader : readers_) {
375 if (reader.read_idx == read_idx && reader.entry_count != 0) {
376 return 0;
377 }
378 }
379 return buffer_bytes_;
Keir Mierle866cff42020-04-28 22:24:44 -0700380}
381
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -0800382void PrefixedEntryRingBufferMulti::RawWrite(std::span<const std::byte> source) {
Keir Mierle866cff42020-04-28 22:24:44 -0700383 // Write until the end of the source or the backing buffer.
384 size_t bytes_until_wrap = buffer_bytes_ - write_idx_;
385 size_t bytes_to_copy = std::min(source.size(), bytes_until_wrap);
386 memcpy(buffer_ + write_idx_, source.data(), bytes_to_copy);
387
388 // If there wasn't space in the backing buffer, wrap to the front.
389 if (bytes_to_copy < source.size()) {
390 memcpy(
391 buffer_, source.data() + bytes_to_copy, source.size() - bytes_to_copy);
392 }
393 write_idx_ = IncrementIndex(write_idx_, source.size());
394}
395
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -0800396void PrefixedEntryRingBufferMulti::RawRead(byte* destination,
397 size_t source_idx,
398 size_t length_bytes) {
Keir Mierle866cff42020-04-28 22:24:44 -0700399 // Read the pre-wrap bytes.
400 size_t bytes_until_wrap = buffer_bytes_ - source_idx;
401 size_t bytes_to_copy = std::min(length_bytes, bytes_until_wrap);
402 memcpy(destination, buffer_ + source_idx, bytes_to_copy);
403
404 // Read the post-wrap bytes, if needed.
405 if (bytes_to_copy < length_bytes) {
406 memcpy(destination + bytes_to_copy, buffer_, length_bytes - bytes_to_copy);
407 }
408}
409
Prashanth Swaminathanbf6e2e92021-02-09 20:12:22 -0800410size_t PrefixedEntryRingBufferMulti::IncrementIndex(size_t index,
411 size_t count) {
Keir Mierle866cff42020-04-28 22:24:44 -0700412 // Note: This doesn't use modulus (%) since the branch is cheaper, and we
413 // guarantee that count will never be greater than buffer_bytes_.
414 index += count;
415 if (index > buffer_bytes_) {
416 index -= buffer_bytes_;
417 }
418 return index;
419}
420
Prashanth Swaminathand9be1132021-03-10 14:55:23 -0800421Status PrefixedEntryRingBufferMulti::Reader::PeekFrontWithPreamble(
422 std::span<byte> data,
423 uint32_t& user_preamble_out,
424 size_t& entry_bytes_read_out) {
425 entry_bytes_read_out = 0;
426 return buffer->InternalRead(
427 *this, GetOutput(data, &entry_bytes_read_out), false, &user_preamble_out);
428}
429
Keir Mierle866cff42020-04-28 22:24:44 -0700430} // namespace ring_buffer
431} // namespace pw