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/unsigned_word.h>
10#include <gf2/store_word.h>
11#include <optional>
12
13namespace gf2 {
14
15// clang-format off
16// Forward declare some classes of interest:
17template<typename Store> class BitStore;
18template<typename Store> class BitRef;
19// clang-format on
20
21// --------------------------------------------------------------------------------------------------------------------
22// `BitsIter` ...
23// --------------------------------------------------------------------------------------------------------------------
24
44template<typename Store, bool is_const>
45class BitsIter {
46public:
47 // We keep a pointer to the parent bit-store which is either const or non-const.
48 using store_pointer = std::conditional_t<is_const, const BitStore<Store>*, BitStore<Store>*>;
49
50 // The value type is either a `bool` or a `BitRef` depending on the constness of the iterator.
51 using value_type = std::conditional_t<is_const, bool, BitRef<Store>>;
52
53 // The difference type is always a `std::ptrdiff_t` (required by the iterator concept).
54 using difference_type = std::ptrdiff_t;
55
56private:
57 store_pointer m_store = nullptr;
58 usize m_index = 0;
59
60public:
61 // Our constructor captures a (const or non-const) pointer to the store and the index for the bit of interest.
62 BitsIter(store_pointer store, usize idx) : m_store(store), m_index{idx} {}
63
64 // Iterator are required to act like value types so must be default constructible, moveable, and copyable.
65 BitsIter() = default;
66 BitsIter(BitsIter&&) = default;
67 BitsIter(const BitsIter&) = default;
68 BitsIter& operator=(BitsIter&&) = default;
69 BitsIter& operator=(const BitsIter&) = default;
70
71 // Iterators must be comparable (this is needed so that any range-for loop will work).
72 constexpr bool operator==(const BitsIter& other) const {
73 return m_store == other.m_store && m_index == other.m_index;
74 }
75
76 // Returns the item that the iterator is currently pointing to.
77 // The `decltype(auto)` will either be a `bool` or a `BitRef<Word>` depending on the constness of the pointer.
78 constexpr decltype(auto) operator*() const { return m_store->operator[](m_index); }
79
80 // Any call to `begin()` returns a new iterator pointing to the first bit in the store.
81 constexpr auto begin() const { return BitsIter(m_store, 0); }
82
83 // Any call to `end()` returns a new iterator pointing to the bit after the last bit in the store.
84 constexpr auto end() const { return BitsIter(m_store, m_store->size()); }
85
86 // Increment the iterator, returning the new value (the `i++` operator).
87 constexpr BitsIter& operator++() {
88 ++m_index;
89 return *this;
90 }
91
92 // Increment the iterator, returning the previous value (the `++i` operator).
93 constexpr BitsIter operator++(int) {
94 auto prev = *this;
95 ++*this;
96 return prev;
97 }
98
99 // Decrement the iterator, returning the new value (the `--i` operator).
100 constexpr BitsIter& operator--() {
101 --m_index;
102 return *this;
103 }
104
105 // Decrement the iterator, returning the previous value (the `--i` operator).
106 constexpr BitsIter operator--(int) {
107 auto prev = *this;
108 --*this;
109 return prev;
110 }
111};
112
113// --------------------------------------------------------------------------------------------------------------------
114// `SetBitsIter` ...
115// --------------------------------------------------------------------------------------------------------------------
116
129template<typename Store>
130class SetBitsIter {
131private:
132 const BitStore<Store>* m_store = nullptr; // The store we're iterating over
133 std::optional<usize> m_index = std::nullopt; // Search after this index.
134
135public:
136 // The value type is a `usize` (the index of the set bit).
137 using value_type = usize;
138
139 // The difference type is always a `std::ptrdiff_t` (required by the iterator concept).
140 using difference_type = std::ptrdiff_t;
141
142 // Our constructor captures a pointer to the store and sets the index to uninitialized.
143 SetBitsIter(const BitStore<Store>* store, std::optional<usize> idx = std::nullopt) : m_store(store), m_index{idx} {
144 // Empty body ...
145 }
146
147 // Iterator are required to act like value types so must be default constructible, moveable, and copyable.
148 SetBitsIter() = default;
149 SetBitsIter(SetBitsIter&&) = default;
150 SetBitsIter(const SetBitsIter&) = default;
151 SetBitsIter& operator=(SetBitsIter&&) = default;
152 SetBitsIter& operator=(const SetBitsIter&) = default;
153
154 // Iterators must be comparable (this is how the range-for loops work).
155 constexpr bool operator==(const SetBitsIter& other) const {
156 return m_store == other.m_store && m_index == other.m_index;
157 }
158
159 // What is the iterator currently pointing to? (this is what the range-for loop will use).
160 constexpr value_type operator*() const { return *m_index; }
161
162 // Any call to `begin` returns a new iterator pointing to the first set bit in the store.
163 constexpr auto begin() const { return SetBitsIter(m_store, m_store->first_set()); }
164
165 // Any call to `end` returns a new iterator that is not initialized.
166 constexpr auto end() const { return SetBitsIter(m_store, std::nullopt); }
167
168 // Increment the iterator, returning the new value (the `i++` operator).
169 constexpr SetBitsIter& operator++() {
170 if (m_index.has_value()) m_index = m_store->next_set(*m_index);
171 return *this;
172 }
173
174 // Increment the iterator, returning the previous value (the `++i` operator).
175 constexpr SetBitsIter operator++(int) {
176 auto prev = m_index;
177 ++*this;
178 return prev;
179 }
180
181 // Decrement the iterator, returning the new value (the `--i` operator).
182 constexpr SetBitsIter& operator--() {
183 if (m_index.has_value()) m_index = m_store->previous_set(*m_index);
184 return *this;
185 }
186
187 // Decrement the iterator, returning the previous value (the `--i` operator).
188 constexpr SetBitsIter operator--(int) {
189 auto prev = m_index;
190 --*this;
191 return prev;
192 }
193};
194
195// --------------------------------------------------------------------------------------------------------------------
196// `UnsetBitsIter` ...
197// --------------------------------------------------------------------------------------------------------------------
198
211template<typename Store>
212class UnsetBitsIter {
213private:
214 const BitStore<Store>* m_store = nullptr; // The store we're iterating over
215 std::optional<usize> m_index = std::nullopt; // Search after this index.
216
217public:
218 // The value type is a `usize` (the index of the unset bit).
219 using value_type = usize;
220
221 // The difference type is always a `std::ptrdiff_t` (required by the iterator concept).
222 using difference_type = std::ptrdiff_t;
223
224 // Our constructor captures a pointer to the store and sets the index to uninitialized.
225 UnsetBitsIter(const BitStore<Store>* store, std::optional<usize> idx = std::nullopt) :
226 m_store(store), m_index{idx} {
227 // Empty body ...
228 }
229
230 // Iterator are required to act like value types so must be default constructible, moveable, and copyable.
231 UnsetBitsIter() = default;
232 UnsetBitsIter(UnsetBitsIter&&) = default;
233 UnsetBitsIter(const UnsetBitsIter&) = default;
234 UnsetBitsIter& operator=(UnsetBitsIter&&) = default;
235 UnsetBitsIter& operator=(const UnsetBitsIter&) = default;
236
237 // Iterators must be comparable (this is how the range-for loops work).
238 constexpr bool operator==(const UnsetBitsIter& other) const {
239 return m_store == other.m_store && m_index == other.m_index;
240 }
241
242 // What is the iterator currently pointing to? (this is what the range-for loop will use).
243 constexpr value_type operator*() const { return *m_index; }
244
245 // Any call to `begin` returns a new iterator pointing to the first unset bit in the store.
246 constexpr auto begin() const { return UnsetBitsIter(m_store, m_store->first_unset()); }
247
248 // Any call to `end` returns a new iterator that is not initialized.
249 constexpr auto end() const { return UnsetBitsIter(m_store, std::nullopt); }
250
251 // Increment the iterator, returning the new value (the `i++` operator).
252 constexpr UnsetBitsIter& operator++() {
253 if (m_index.has_value()) m_index = m_store->next_unset(*m_index);
254 return *this;
255 }
256
257 // Increment the iterator, returning the previous value (the `++i` operator).
258 constexpr UnsetBitsIter operator++(int) {
259 auto prev = m_index;
260 ++*this;
261 return prev;
262 }
263
264 // Decrement the iterator, returning the new value (the `--i` operator).
265 constexpr UnsetBitsIter& operator--() {
266 if (m_index.has_value()) m_index = m_store->previous_unset(*m_index);
267 return *this;
268 }
269
270 // Decrement the iterator, returning the previous value (the `--i` operator).
271 constexpr UnsetBitsIter operator--(int) {
272 auto prev = m_index;
273 --*this;
274 return prev;
275 }
276};
277
278// --------------------------------------------------------------------------------------------------------------------
279// `WordsIter` ...
280// --------------------------------------------------------------------------------------------------------------------
281
294template<typename Store>
295class WordsIter {
296private:
297 const BitStore<Store>* m_store = nullptr;
298 usize m_index = 0;
299
300public:
301 // The value type is the word type of the store with any const qualification dropped.
302 using value_type = typename store_word<Store>::word_type;
303
304 // The difference type is always a `std::ptrdiff_t` (required by the iterator concept).
305 using difference_type = std::ptrdiff_t;
306
307 // Our constructor captures a pointer to the store and sets the index to 0
308 WordsIter(const BitStore<Store>* store, usize idx = 0) : m_store(store), m_index{idx} {
309 // Empty body ...
310 }
311
312 // Iterator are required to act like value types so must be default constructible, moveable, and copyable.
313 WordsIter() = default;
314 WordsIter(WordsIter&&) = default;
315 WordsIter(const WordsIter&) = default;
316 WordsIter& operator=(WordsIter&&) = default;
317 WordsIter& operator=(const WordsIter&) = default;
318
319 // Iterators must be comparable (this is how the range-for loops work).
320 constexpr bool operator==(const WordsIter& other) const {
321 return m_store == other.m_store && m_index == other.m_index;
322 }
323
324 // What is the iterator currently pointing to? (this is what the range-for loop will use).
325 constexpr value_type operator*() const { return m_store->word(m_index); }
326
327 // Any call to `begin` returns a new iterator pointing to the first unset bit in the store.
328 constexpr auto begin() const { return WordsIter(m_store, 0); }
329
330 // Any call to `end` returns a new iterator that is not initialized.
331 constexpr auto end() const { return WordsIter(m_store, m_store->words()); }
332
333 // Increment the iterator, returning the new value (the `i++` operator).
334 constexpr WordsIter& operator++() {
335 ++m_index;
336 return *this;
337 }
338
339 // Increment the iterator, returning the previous value (the `++i` operator).
340 constexpr WordsIter operator++(int) {
341 auto prev = *this;
342 ++*this;
343 return prev;
344 }
345
346 // Decrement the iterator, returning the new value (the `--i` operator).
347 constexpr WordsIter& operator--() {
348 --m_index;
349 return *this;
350 }
351
352 // Decrement the iterator, returning the previous value (the `--i` operator).
353 constexpr WordsIter operator--(int) {
354 auto prev = *this;
355 --*this;
356 return prev;
357 }
358};
359
360} // namespace gf2
A BitRef is a proxy class to reference a single bit in a bit-store.
Definition BitRef.h:38
The base class for the vector-like types in the gf2 library: BitSet, BitVec, and BitSpan The templat...
Definition BitStore.h:35
The namespace for the gf2 library.
Definition assert.h:119
std::size_t usize
Word type alias for the platform's "native"-sized unsigned integer.
Definition unsigned_word.h:41
Utility functions that work on primitive unsigned word types. See the unsigned word page for more d...