C/C++ API Reference
Loading...
Searching...
No Matches
byte_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 <functional>
18#include <iterator>
19
20#include "pw_assert/assert.h"
21#include "pw_bytes/span.h"
22#include "pw_containers/dynamic_deque.h"
23#include "pw_multibuf/v2/internal/entry.h"
24
25namespace pw::multibuf::v2 {
26
27namespace test {
28class IteratorTest;
29} // namespace test
30
31namespace internal {
32
42 public:
43 using Deque = Entry::Deque;
44 using size_type = Entry::size_type;
45 using difference_type = Entry::difference_type;
46 using iterator_category = std::random_access_iterator_tag;
47
48 ~BasicByteIterator() = default;
49
50 constexpr friend difference_type operator-(const BasicByteIterator& lhs,
51 const BasicByteIterator& rhs);
52
53 protected:
54 constexpr BasicByteIterator() = default;
55 constexpr BasicByteIterator(const Deque& deque,
56 size_type chunk,
57 size_type entries_per_chunk,
58 size_type offset)
59 : deque_(&deque),
60 chunk_(chunk),
61 entries_per_chunk_(entries_per_chunk),
62 offset_(offset) {}
63
64 [[nodiscard]] constexpr bool has_deque() const { return deque_ != nullptr; }
65
66 [[nodiscard]] constexpr const Deque& deque() const {
67 PW_ASSERT(deque_ != nullptr);
68 return *deque_;
69 }
70
71 constexpr void Increment(difference_type n);
72
73 constexpr void Decrement(difference_type n);
74
75 [[nodiscard]] constexpr int Compare(const BasicByteIterator& other) const;
76
77 const Deque* deque_ = nullptr;
78 size_type chunk_ = 0;
79 size_type entries_per_chunk_ = 0;
80 size_type offset_ = 0;
81};
82
84template <Mutability kMutability>
86 public:
88 using BasicByteIterator::difference_type;
89 using BasicByteIterator::iterator_category;
90 using BasicByteIterator::size_type;
91
92 using value_type = std::conditional_t<kMutability == Mutability::kConst,
93 const std::byte,
94 std::byte>;
95 using pointer = value_type*;
96 using reference = value_type&;
97
98 constexpr ByteIterator() = default;
99 constexpr ByteIterator(const ByteIterator& other) = default;
100 ByteIterator& operator=(const ByteIterator& other) = default;
101
102 // Support converting non-const iterators to const_iterators.
103 constexpr operator ByteIterator<Mutability::kConst>() const {
104 return has_deque() ? ByteIterator<Mutability::kConst>(
105 deque(), chunk_, entries_per_chunk_, offset_)
107 }
108
109 constexpr reference operator*() const {
110 return Entry::GetView(deque(), chunk_, entries_per_chunk_)[offset_];
111 }
112
113 constexpr reference operator[](difference_type n) const {
114 return *(*this + n);
115 }
116
117 constexpr ByteIterator& operator++() { return operator+=(1); }
118
119 constexpr ByteIterator operator++(int) {
120 ByteIterator previous(*this);
121 operator++();
122 return previous;
123 }
124
125 template <typename T, typename = std::enable_if_t<std::is_integral_v<T>, int>>
126 constexpr ByteIterator& operator+=(T n) {
127 if constexpr (std::is_unsigned_v<T>) {
128 PW_ASSERT(size_t(n) < std::numeric_limits<difference_type>::max());
129 }
130 Increment(static_cast<difference_type>(n));
131 return *this;
132 }
133
134 template <typename T, typename = std::enable_if_t<std::is_integral_v<T>, int>>
135 constexpr friend ByteIterator operator+(ByteIterator it, T n) {
136 return it += n;
137 }
138
139 template <typename T, typename = std::enable_if_t<std::is_integral_v<T>, int>>
140 constexpr friend ByteIterator operator+(T n, ByteIterator it) {
141 return it += n;
142 }
143
144 constexpr ByteIterator& operator--() { return operator-=(1); }
145
146 constexpr ByteIterator operator--(int) {
147 ByteIterator previous(*this);
148 operator--();
149 return previous;
150 }
151
152 template <typename T, typename = std::enable_if_t<std::is_integral_v<T>, int>>
153 constexpr ByteIterator& operator-=(T n) {
154 if constexpr (std::is_unsigned_v<T>) {
155 PW_ASSERT(size_t(n) < std::numeric_limits<difference_type>::max());
156 }
157 Decrement(static_cast<difference_type>(n));
158 return *this;
159 }
160
161 template <typename T, typename = std::enable_if_t<std::is_integral_v<T>, int>>
162 constexpr friend ByteIterator operator-(ByteIterator it, T n) {
163 return it -= n;
164 }
165
166 constexpr friend bool operator==(const ByteIterator& lhs,
167 const ByteIterator& rhs) {
168 return lhs.Compare(rhs) == 0;
169 }
170
171 constexpr friend bool operator!=(const ByteIterator& lhs,
172 const ByteIterator& rhs) {
173 return lhs.Compare(rhs) != 0;
174 }
175
176 constexpr friend bool operator<(const ByteIterator& lhs,
177 const ByteIterator& rhs) {
178 return lhs.Compare(rhs) < 0;
179 }
180
181 constexpr friend bool operator>(const ByteIterator& lhs,
182 const ByteIterator& rhs) {
183 return lhs.Compare(rhs) > 0;
184 }
185
186 constexpr friend bool operator<=(const ByteIterator& lhs,
187 const ByteIterator& rhs) {
188 return lhs.Compare(rhs) <= 0;
189 }
190
191 constexpr friend bool operator>=(const ByteIterator& lhs,
192 const ByteIterator& rhs) {
193 return lhs.Compare(rhs) >= 0;
194 }
195
196 private:
197 // Allow non-const iterators to construct const_iterators in conversions.
198 template <Mutability>
199 friend class ByteIterator;
200
201 // Allow MultiBufs to create iterators.
202 friend class GenericMultiBuf;
203
204 // For unit testing.
205 friend class ::pw::multibuf::v2::test::IteratorTest;
206
207 constexpr ByteIterator(const Deque& deque,
208 size_type chunk,
209 size_type entries_per_chunk,
210 size_type offset)
211 : BasicByteIterator(deque, chunk, entries_per_chunk, offset) {}
212};
213
214// Constexpr and template method implementations.
215
216constexpr void BasicByteIterator::Increment(difference_type n) {
217 if (n < 0) {
218 Decrement(-n);
219 return;
220 }
221 PW_ASSERT(deque_ != nullptr);
222 PW_ASSERT(n < std::numeric_limits<size_type>::max());
223 size_type delta = static_cast<size_type>(n) + offset_;
224 size_type length = 0;
225 size_type num_chunks = Entry::num_chunks(*deque_, entries_per_chunk_);
226 while (chunk_ < num_chunks) {
227 length = Entry::GetLength(*deque_, chunk_, entries_per_chunk_);
228 if (delta < length) {
229 break;
230 }
231 delta -= length;
232 ++chunk_;
233 }
234 PW_ASSERT(delta < length || delta == 0);
235 offset_ = delta;
236}
237
238constexpr void BasicByteIterator::Decrement(difference_type n) {
239 if (n < 0) {
240 return Increment(-n);
241 }
242 PW_ASSERT(deque_ != nullptr);
243 PW_ASSERT(n < std::numeric_limits<size_type>::max());
244 size_type delta = static_cast<size_type>(n);
245 while (delta > offset_) {
246 PW_ASSERT(chunk_ != 0);
247 --chunk_;
248 delta -= offset_;
249 offset_ = Entry::GetLength(*deque_, chunk_, entries_per_chunk_);
250 }
251 offset_ -= delta;
252}
253
254constexpr int BasicByteIterator::Compare(const BasicByteIterator& other) const {
255 if (deque_ == nullptr && other.deque_ == nullptr) {
256 return 0;
257 }
258 if (deque_ == nullptr && other.deque_ != nullptr) {
259 return -1;
260 }
261 if (deque_ != nullptr && other.deque_ == nullptr) {
262 return 1;
263 }
264 if (deque_ != other.deque_) {
265 return std::less<>()(deque_, other.deque_) ? -1 : 1;
266 }
267 if (chunk_ != other.chunk_) {
268 return chunk_ < other.chunk_ ? -1 : 1;
269 }
270 if (offset_ != other.offset_) {
271 return offset_ < other.offset_ ? -1 : 1;
272 }
273 return 0;
274}
275
276constexpr BasicByteIterator::difference_type operator-(
277 const BasicByteIterator& lhs, const BasicByteIterator& rhs) {
278 using size_type = BasicByteIterator::size_type;
279 PW_ASSERT(lhs.deque_ != nullptr);
280 PW_ASSERT(lhs.deque_ == rhs.deque_);
281 PW_ASSERT(lhs.entries_per_chunk_ == rhs.entries_per_chunk_);
282 int cmp = lhs.Compare(rhs);
283 if (cmp < 0) {
284 return -(rhs - lhs);
285 }
286 if (cmp == 0) {
287 return 0;
288 }
289 size_type delta = 0;
290 size_type chunk = rhs.chunk_;
291 while (chunk < lhs.chunk_) {
292 delta += Entry::GetLength(*rhs.deque_, chunk, rhs.entries_per_chunk_);
293 ++chunk;
294 }
295 delta -= rhs.offset_;
296 delta += lhs.offset_;
297 return static_cast<BasicByteIterator::difference_type>(delta);
298}
299
300} // namespace internal
301} // namespace pw::multibuf::v2
Definition: dynamic_deque.h:60
Definition: byte_iterator.h:41
Byte iterator templated on the const-ness of the bytes it references.
Definition: byte_iterator.h:85
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