C/C++ API Reference
Loading...
Searching...
No Matches
chunk_iterator.h
1// Copyright 2025 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#pragma once
15
16#include <cstddef>
17#include <iterator>
18#include <type_traits>
19#include <utility>
20
21#include "pw_assert/assert.h"
22#include "pw_bytes/span.h"
23#include "pw_containers/dynamic_deque.h"
24#include "pw_multibuf/v2/internal/entry.h"
25
26namespace pw::multibuf::v2::internal {
27
28// Forward declaration.
29template <Mutability kMutability>
30class ChunksImpl;
31
44template <Mutability kMutability>
46 private:
47 using SpanType = std::
48 conditional_t<kMutability == Mutability::kConst, ConstByteSpan, ByteSpan>;
49 using ByteType = typename SpanType::element_type;
50
51 public:
52 using size_type = Entry::size_type;
53 using difference_type = Entry::difference_type;
54 using value_type = SpanType;
55 using pointer = value_type*;
56 using const_pointer = const value_type*;
57 using reference = value_type&;
58 using const_reference = const value_type&;
59 using iterator_category = std::bidirectional_iterator_tag;
60
61 constexpr ChunkIterator() = default;
62 ~ChunkIterator() = default;
63 constexpr ChunkIterator(const ChunkIterator& other) { *this = other; }
64 constexpr ChunkIterator& operator=(const ChunkIterator& other);
65 constexpr ChunkIterator(ChunkIterator&& other) = default;
66 constexpr ChunkIterator& operator=(ChunkIterator&& other) = default;
67
68 // Support converting non-const iterators to const_iterators.
69 constexpr operator ChunkIterator<Mutability::kConst>() const {
70 return {deque_, chunk_, entries_per_chunk_};
71 }
72
73 constexpr reference operator*() {
74 PW_ASSERT(is_valid());
75 return current_;
76 }
77
78 constexpr const_reference operator*() const {
79 PW_ASSERT(is_valid());
80 return current_;
81 }
82
83 constexpr pointer operator->() {
84 PW_ASSERT(is_valid());
85 return &current_;
86 }
87
88 constexpr const_pointer operator->() const {
89 PW_ASSERT(is_valid());
90 return &current_;
91 }
92
93 constexpr ChunkIterator& operator++();
94
95 constexpr ChunkIterator operator++(int) {
96 ChunkIterator previous(*this);
97 operator++();
98 return previous;
99 }
100
101 constexpr ChunkIterator& operator--();
102
103 constexpr ChunkIterator operator--(int) {
104 ChunkIterator previous(*this);
105 operator--();
106 return previous;
107 }
108
109 constexpr friend bool operator==(const ChunkIterator& lhs,
110 const ChunkIterator& rhs) {
111 return lhs.deque_ == rhs.deque_ &&
112 lhs.entries_per_chunk_ == rhs.entries_per_chunk_ &&
113 lhs.chunk_ == rhs.chunk_;
114 }
115
116 constexpr friend bool operator!=(const ChunkIterator& lhs,
117 const ChunkIterator& rhs) {
118 return !(lhs == rhs);
119 }
120
121 private:
122 using Deque = Entry::Deque;
123
124 // Iterators that point to something are created `Chunks` or `ConstChunks`.
125 template <Mutability>
126 friend class ChunksImpl;
127
128 // Allow internal conversions between iterator subtypes
129 template <Mutability>
130 friend class ChunkIterator;
131
132 // Allow MultiBufs to create iterators.
133 friend class GenericMultiBuf;
134
135 constexpr ChunkIterator(const Deque* deque,
136 size_type chunk,
137 size_type entries_per_chunk)
138 : deque_(deque), chunk_(chunk), entries_per_chunk_(entries_per_chunk) {
139 ResetCurrent();
140 }
141
142 [[nodiscard]] constexpr bool is_valid() const {
143 return deque_ != nullptr && chunk_ < num_chunks();
144 }
145
146 constexpr size_type num_chunks() const {
147 return Entry::num_chunks(*deque_, entries_per_chunk_);
148 }
149
150 constexpr void ResetCurrent();
151
152 const Deque* deque_ = nullptr;
153 size_type chunk_ = 0;
154 size_type entries_per_chunk_ = Entry::kMinEntriesPerChunk;
155 SpanType current_;
156};
157
158// Template method implementations.
159
160template <Mutability kMutability>
162 const ChunkIterator& other) {
163 deque_ = other.deque_;
164 chunk_ = other.chunk_;
165 entries_per_chunk_ = other.entries_per_chunk_;
166 ResetCurrent();
167 return *this;
168}
169
170template <Mutability kMutability>
171constexpr ChunkIterator<kMutability>& ChunkIterator<kMutability>::operator++() {
172 PW_ASSERT(is_valid());
173 size_t left = current_.size();
174 while (left != 0) {
175 left -= Entry::GetLength(*deque_, chunk_, entries_per_chunk_);
176 ++chunk_;
177 }
178 while (chunk_ < num_chunks() &&
179 Entry::GetLength(*deque_, chunk_, entries_per_chunk_) == 0) {
180 ++chunk_;
181 }
182 ResetCurrent();
183 return *this;
184}
185
186template <Mutability kMutability>
187constexpr ChunkIterator<kMutability>& ChunkIterator<kMutability>::operator--() {
188 PW_ASSERT(deque_ != nullptr);
189 PW_ASSERT(chunk_ != 0);
190 current_ = SpanType();
191 while (chunk_ != 0) {
192 SpanType prev = Entry::GetView(*deque_, chunk_ - 1, entries_per_chunk_);
193 if (!current_.empty() && prev.data() + prev.size() != current_.data()) {
194 break;
195 }
196 current_ = SpanType(prev.data(), prev.size() + current_.size());
197 --chunk_;
198 }
199 return *this;
200}
201
202template <Mutability kMutability>
203constexpr void ChunkIterator<kMutability>::ResetCurrent() {
204 if (!is_valid()) {
205 current_ = SpanType();
206 chunk_ = num_chunks();
207 return;
208 }
209
210 current_ = Entry::GetView(*deque_, chunk_, entries_per_chunk_);
211 for (size_type i = chunk_ + 1; i < num_chunks(); ++i) {
212 SpanType next = Entry::GetView(*deque_, i, entries_per_chunk_);
213 if (next.empty()) {
214 continue;
215 }
216 if (current_.empty()) {
217 current_ = next;
218 chunk_ = i;
219 continue;
220 }
221 if (current_.data() + current_.size() != next.data()) {
222 break;
223 }
224 current_ = SpanType(current_.data(), current_.size() + next.size());
225 }
226 if (current_.empty()) {
227 chunk_ = num_chunks();
228 }
229}
230
231} // namespace pw::multibuf::v2::internal
Definition: dynamic_deque.h:60
Definition: chunk_iterator.h:45
static constexpr size_type num_chunks(const Deque &deque, size_type entries_per_chunk)
Returns the number of chunks in a deque.
Definition: entry.h:68
static constexpr ByteSpan GetView(const Deque &deque, size_type chunk, size_type entries_per_chunk, size_type layer)
Returns a view of the visible data length of the chunk at the given layer.
Definition: entry.h:235
static constexpr size_type GetLength(const Deque &deque, size_type chunk, size_type entries_per_chunk, size_type layer)
Returns the length of the given layer of the chunk.
Definition: entry.h:216
static constexpr size_type kMinEntriesPerChunk
Minimum number of entries per chunk.
Definition: entry.h:65