21#include "pw_assert/assert.h"
22#include "pw_bytes/span.h"
23#include "pw_containers/dynamic_deque.h"
24#include "pw_multibuf/internal/entry.h"
26namespace pw::multibuf {
29template <
typename,
typename>
32class MultiBufV1Adapter;
36enum class ChunkContiguity {
41enum class ChunkMutability {
58template <
typename SizeType,
59 ChunkContiguity kContiguity,
60 ChunkMutability kMutability>
63 using SpanType = std::conditional_t<kMutability == ChunkMutability::kConst,
66 using ByteType =
typename SpanType::element_type;
67 using Deque = std::conditional_t<kMutability == ChunkMutability::kConst,
72 using size_type = SizeType;
73 using difference_type = std::ptrdiff_t;
74 using value_type = SpanType;
75 using pointer = value_type*;
76 using const_pointer =
const value_type*;
77 using reference = value_type&;
78 using const_reference =
const value_type&;
79 using iterator_category = std::bidirectional_iterator_tag;
92 return {deque_, chunk_, entries_per_chunk_};
95 constexpr reference operator*() {
96 PW_ASSERT(is_valid());
100 constexpr const_reference operator*()
const {
101 PW_ASSERT(is_valid());
105 constexpr pointer operator->() {
106 PW_ASSERT(is_valid());
110 constexpr const_pointer operator->()
const {
111 PW_ASSERT(is_valid());
133 return lhs.deque_ == rhs.deque_ &&
134 lhs.entries_per_chunk_ == rhs.entries_per_chunk_ &&
135 lhs.chunk_ == rhs.chunk_;
140 return !(lhs == rhs);
145 template <
typename, ChunkContiguity, ChunkMutability>
149 template <
typename, ChunkContiguity, ChunkMutability>
153 template <
typename, ChunkMutability>
156 friend MultiBufV1Adapter;
160 size_type entries_per_chunk)
161 : deque_(deque), chunk_(chunk), entries_per_chunk_(entries_per_chunk) {
165 [[nodiscard]]
constexpr bool is_valid()
const {
166 return deque_ !=
nullptr && chunk_ < num_chunks();
169 constexpr size_type num_chunks()
const {
170 return deque_ ==
nullptr ? 0 : deque_->size() / entries_per_chunk_;
173 constexpr ByteType* data(size_type chunk)
const {
177 ? (*deque_)[view_index].base_view.offset
178 : (*deque_)[view_index].view.offset;
179 return (*deque_)[data_index].data + offset;
182 constexpr size_t size(size_type chunk)
const {
185 ? (*deque_)[view_index].base_view.length
186 : (*deque_)[view_index].view.length;
189 constexpr void ResetCurrent();
191 Deque* deque_ =
nullptr;
192 size_type chunk_ = 0;
199template <
typename SizeType,
200 ChunkContiguity kContiguity,
201 ChunkMutability kMutability>
205 deque_ = other.deque_;
206 chunk_ = other.chunk_;
207 entries_per_chunk_ = other.entries_per_chunk_;
212template <
typename SizeType,
213 ChunkContiguity kContiguity,
214 ChunkMutability kMutability>
215constexpr ChunkIterator<SizeType, kContiguity, kMutability>&
216ChunkIterator<SizeType, kContiguity, kMutability>::operator++() {
217 PW_ASSERT(is_valid());
219 if constexpr (kContiguity == ChunkContiguity::kKeepAll) {
225 size_t left = current_.size();
227 left -= size(chunk_);
230 while (chunk_ < num_chunks() && size(chunk_) == 0) {
237template <
typename SizeType,
238 ChunkContiguity kContiguity,
239 ChunkMutability kMutability>
240constexpr ChunkIterator<SizeType, kContiguity, kMutability>&
241ChunkIterator<SizeType, kContiguity, kMutability>::operator--() {
242 PW_ASSERT(deque_ !=
nullptr);
243 PW_ASSERT(chunk_ != 0);
245 if constexpr (kContiguity == ChunkContiguity::kKeepAll) {
247 current_ = SpanType(data(chunk_), size(chunk_));
251 current_ = SpanType();
252 while (chunk_ != 0) {
253 SpanType prev(data(chunk_ - 1), size(chunk_ - 1));
254 if (!current_.empty() && prev.data() + prev.size() != current_.data()) {
257 current_ = SpanType(prev.data(), prev.size() + current_.size());
263template <
typename SizeType,
264 ChunkContiguity kContiguity,
265 ChunkMutability kMutability>
267ChunkIterator<SizeType, kContiguity, kMutability>::ResetCurrent() {
269 current_ = SpanType();
270 chunk_ = num_chunks();
274 current_ = SpanType(data(chunk_), size(chunk_));
275 if constexpr (kContiguity == ChunkContiguity::kKeepAll) {
279 for (size_type i = chunk_ + 1; i < num_chunks(); ++i) {
280 size_t next_size = size(i);
281 if (next_size == 0) {
284 auto* next_data = data(i);
285 if (current_.empty()) {
286 current_ = SpanType(next_data, next_size);
290 if (current_.data() + current_.size() != next_data) {
293 current_ = SpanType(current_.data(), current_.size() + next_size);
295 if (current_.empty()) {
296 chunk_ = num_chunks();
Definition: dynamic_deque.h:60
Definition: chunk_iterator.h:30
Definition: byte_iterator.h:43
Definition: chunk_iterator.h:61
Base class for ranges of chunks.
Definition: chunks.h:33
static constexpr size_type kMinEntriesPerChunk
Minimum number of entries per chunk.
Definition: entry.h:55
static constexpr size_type data_index(size_type chunk, size_type entries_per_chunk)
Returns the index to the data entry of a given chunk.
Definition: entry.h:64
static constexpr size_type top_view_index(size_type chunk, size_type entries_per_chunk)
Returns the index to the top view entry of a given chunk.
Definition: entry.h:83