GF2++
Loading...
Searching...
No Matches
Iterators.h
Go to the documentation of this file.
1#pragma once
2// SPDX-FileCopyrightText: 2025 Nessan Fitzmaurice <nzznfitz+gh@icloud.com>
3// SPDX-License-Identifier: MIT
4
8
9#include <gf2/BitStore.h>
10#include <gf2/BitRef.h>
11
12namespace gf2 {
13
14// --------------------------------------------------------------------------------------------------------------------
15// `BitsIter` ...
16// --------------------------------------------------------------------------------------------------------------------
17
37template<BitStore Store, bool is_const>
38class BitsIter {
39public:
40 // We keep a pointer to the parent bit-store which is either const or non-const.
41 using store_pointer = std::conditional_t<is_const, const Store*, Store*>;
42
43 // The value type is either a `bool` or a `BitRef` depending on the constness of the iterator.
44 using value_type = std::conditional_t<is_const, bool, BitRef<Store>>;
45
46 // The difference type is always a `std::ptrdiff_t` (required by the iterator concept).
47 using difference_type = std::ptrdiff_t;
48
49private:
50 store_pointer m_store = nullptr;
51 usize m_index = 0;
52
53public:
54 // Our constructor captures a (const or non-const) pointer to the store and the index for the bit of interest.
55 BitsIter(store_pointer store, usize idx) : m_store(store), m_index{idx} {}
56
57 // Iterator are required to act like value types so must be default constructible, moveable, and copyable.
58 BitsIter() = default;
59 BitsIter(BitsIter&&) = default;
60 BitsIter(BitsIter const&) = default;
61 BitsIter& operator=(BitsIter&&) = default;
62 BitsIter& operator=(BitsIter const&) = default;
63
64 // Iterators must be comparable (this is needed so that any range-for loop will work).
65 constexpr bool operator==(BitsIter const& other) const {
66 return m_store == other.m_store && m_index == other.m_index;
67 }
68
69 // Returns the item that the iterator is currently pointing to.
70 // The `decltype(auto)` will either be a `bool` or a `BitRef` depending on the constness of the pointer.
71 constexpr decltype(auto) operator*() const { return m_store->operator[](m_index); }
72
73 // Any call to `begin()` returns a new iterator pointing to the first bit in the store.
74 constexpr auto begin() const { return BitsIter(m_store, 0); }
75
76 // Any call to `end()` returns a new iterator pointing to the bit after the last bit in the store.
77 constexpr auto end() const { return BitsIter(m_store, m_store->size()); }
78
79 // Increment the iterator, returning the new value (the `i++` operator).
80 constexpr BitsIter& operator++() {
81 ++m_index;
82 return *this;
83 }
84
85 // Increment the iterator, returning the previous value (the `++i` operator).
86 constexpr BitsIter operator++(int) {
87 auto prev = *this;
88 ++*this;
89 return prev;
90 }
91
92 // Decrement the iterator, returning the new value (the `--i` operator).
93 constexpr BitsIter& operator--() {
94 --m_index;
95 return *this;
96 }
97
98 // Decrement the iterator, returning the previous value (the `--i` operator).
99 constexpr BitsIter operator--(int) {
100 auto prev = *this;
101 --*this;
102 return prev;
103 }
104};
105
106// --------------------------------------------------------------------------------------------------------------------
107// `SetBitsIter` ...
108// --------------------------------------------------------------------------------------------------------------------
109
122template<BitStore Store>
123class SetBitsIter {
124private:
125 const Store* m_store = nullptr; // The store we're iterating over
126 std::optional<usize> m_index = std::nullopt; // Search after this index.
127
128public:
129 // The value type is a `usize` (the index of the set bit).
130 using value_type = usize;
131
132 // The difference type is always a `std::ptrdiff_t` (required by the iterator concept).
133 using difference_type = std::ptrdiff_t;
134
135 // Our constructor captures a pointer to the store and sets the index to uninitialized.
136 SetBitsIter(Store const* store, std::optional<usize> idx = std::nullopt) : m_store(store), m_index{idx} {
137 // Empty body ...
138 }
139
140 // Iterator are required to act like value types so must be default constructible, moveable, and copyable.
141 SetBitsIter() = default;
142 SetBitsIter(SetBitsIter&&) = default;
143 SetBitsIter(SetBitsIter const&) = default;
144 SetBitsIter& operator=(SetBitsIter&&) = default;
145 SetBitsIter& operator=(SetBitsIter const&) = default;
146
147 // Iterators must be comparable (this is how the range-for loops work).
148 constexpr bool operator==(SetBitsIter const& other) const {
149 return m_store == other.m_store && m_index == other.m_index;
150 }
151
152 // What is the iterator currently pointing to? (this is what the range-for loop will use).
153 constexpr value_type operator*() const { return *m_index; }
154
155 // Any call to `begin` returns a new iterator pointing to the first set bit in the store.
156 constexpr auto begin() const { return SetBitsIter(m_store, m_store->first_set()); }
157
158 // Any call to `end` returns a new iterator that is not initialized.
159 constexpr auto end() const { return SetBitsIter(m_store, std::nullopt); }
160
161 // Increment the iterator, returning the new value (the `i++` operator).
162 constexpr SetBitsIter& operator++() {
163 if (m_index.has_value()) m_index = m_store->next_set(*m_index);
164 return *this;
165 }
166
167 // Increment the iterator, returning the previous value (the `++i` operator).
168 constexpr SetBitsIter operator++(int) {
169 auto prev = *this;
170 ++*this;
171 return prev;
172 }
173
174 // Decrement the iterator, returning the new value (the `--i` operator).
175 constexpr SetBitsIter& operator--() {
176 if (m_index.has_value()) m_index = previous_set(*m_store, *m_index);
177 return *this;
178 }
179
180 // Decrement the iterator, returning the previous value (the `--i` operator).
181 constexpr SetBitsIter operator--(int) {
182 auto prev = *this;
183 --*this;
184 return prev;
185 }
186};
187
188// --------------------------------------------------------------------------------------------------------------------
189// `UnsetBitsIter` ...
190// --------------------------------------------------------------------------------------------------------------------
191
204template<BitStore Store>
205class UnsetBitsIter {
206private:
207 const Store* m_store = nullptr; // The store we're iterating over
208 std::optional<usize> m_index = std::nullopt; // Search after this index.
209
210public:
211 // The value type is a `usize` (the index of the unset bit).
212 using value_type = usize;
213
214 // The difference type is always a `std::ptrdiff_t` (required by the iterator concept).
215 using difference_type = std::ptrdiff_t;
216
217 // Our constructor captures a pointer to the store and sets the index to uninitialized.
218 UnsetBitsIter(Store const* store, std::optional<usize> idx = std::nullopt) : m_store(store), m_index{idx} {
219 // Empty body ...
220 }
221
222 // Iterator are required to act like value types so must be default constructible, moveable, and copyable.
223 UnsetBitsIter() = default;
224 UnsetBitsIter(UnsetBitsIter&&) = default;
225 UnsetBitsIter(UnsetBitsIter const&) = default;
226 UnsetBitsIter& operator=(UnsetBitsIter&&) = default;
227 UnsetBitsIter& operator=(UnsetBitsIter const&) = default;
228
229 // Iterators must be comparable (this is how the range-for loops work).
230 constexpr bool operator==(UnsetBitsIter const& other) const {
231 return m_store == other.m_store && m_index == other.m_index;
232 }
233
234 // What is the iterator currently pointing to? (this is what the range-for loop will use).
235 constexpr value_type operator*() const { return *m_index; }
236
237 // Any call to `begin` returns a new iterator pointing to the first unset bit in the store.
238 constexpr auto begin() const { return UnsetBitsIter(m_store, m_store->first_unset()); }
239
240 // Any call to `end` returns a new iterator that is not initialized.
241 constexpr auto end() const { return UnsetBitsIter(m_store, std::nullopt); }
242
243 // Increment the iterator, returning the new value (the `i++` operator).
244 constexpr UnsetBitsIter& operator++() {
245 if (m_index.has_value()) m_index = m_store->next_unset(*m_index);
246 return *this;
247 }
248
249 // Increment the iterator, returning the previous value (the `++i` operator).
250 constexpr UnsetBitsIter operator++(int) {
251 auto prev = *this;
252 ++*this;
253 return prev;
254 }
255
256 // Decrement the iterator, returning the new value (the `--i` operator).
257 constexpr UnsetBitsIter& operator--() {
258 if (m_index.has_value()) m_index = previous_unset(*m_store, *m_index);
259 return *this;
260 }
261
262 // Decrement the iterator, returning the previous value (the `--i` operator).
263 constexpr UnsetBitsIter operator--(int) {
264 auto prev = *this;
265 --*this;
266 return prev;
267 }
268};
269
270// --------------------------------------------------------------------------------------------------------------------
271// `WordsIter` ...
272// --------------------------------------------------------------------------------------------------------------------
273
286template<BitStore Store>
287class WordsIter {
288private:
289 const Store* m_store = nullptr;
290 usize m_index = 0;
291
292public:
293 // The value type is the word type of the store with any const qualification dropped.
294 using value_type = typename Store::word_type;
295
296 // The difference type is always a `std::ptrdiff_t` (required by the iterator concept).
297 using difference_type = std::ptrdiff_t;
298
299 // Our constructor captures a pointer to the store and sets the index to 0
300 WordsIter(Store const* store, usize idx = 0) : m_store(store), m_index{idx} {
301 // Empty body ...
302 }
303
304 // Iterator are required to act like value types so must be default constructible, moveable, and copyable.
305 WordsIter() = default;
306 WordsIter(WordsIter&&) = default;
307 WordsIter(WordsIter const&) = default;
308 WordsIter& operator=(WordsIter&&) = default;
309 WordsIter& operator=(WordsIter const&) = default;
310
311 // Iterators must be comparable (this is how the range-for loops work).
312 constexpr bool operator==(WordsIter const& other) const {
313 return m_store == other.m_store && m_index == other.m_index;
314 }
315
316 // What is the iterator currently pointing to? (this is what the range-for loop will use).
317 constexpr value_type operator*() const { return m_store->word(m_index); }
318
319 // Any call to `begin` returns a new iterator pointing to the first unset bit in the store.
320 constexpr auto begin() const { return WordsIter(m_store, 0); }
321
322 // Any call to `end` returns a new iterator that is not initialized.
323 constexpr auto end() const { return WordsIter(m_store, m_store->words()); }
324
325 // Increment the iterator, returning the new value (the `i++` operator).
326 constexpr WordsIter& operator++() {
327 ++m_index;
328 return *this;
329 }
330
331 // Increment the iterator, returning the previous value (the `++i` operator).
332 constexpr WordsIter operator++(int) {
333 auto prev = *this;
334 ++*this;
335 return prev;
336 }
337
338 // Decrement the iterator, returning the new value (the `--i` operator).
339 constexpr WordsIter& operator--() {
340 --m_index;
341 return *this;
342 }
343
344 // Decrement the iterator, returning the previous value (the `--i` operator).
345 constexpr WordsIter operator--(int) {
346 auto prev = *this;
347 --*this;
348 return prev;
349 }
350};
351
352} // namespace gf2
A BitRef is a proxy type that references a single bit in a bit-store. See the BitRef page for more ...
A concept for types that can access individual bits packed into contiguous primitive unsigned words,...
The namespace for the gf2 library.
Definition assert.h:119
constexpr std::optional< usize > previous_set(Store const &store, usize index)
Returns the index of the previous set bit before index in the store or {} if there are none.
Definition BitStore.h:857
constexpr std::optional< usize > previous_unset(Store const &store, usize index)
Returns the index of the previous unset bit before index in the store or {} if no more unset bits exi...
Definition BitStore.h:1013
std::size_t usize
Word type alias for the platform's "native"-sized unsigned integer.
Definition Unsigned.h:42