sparrow 0.3.0
Loading...
Searching...
No Matches
iterator.hpp
Go to the documentation of this file.
1// Copyright 2024 Man Group Operations Limited
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://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,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#pragma once
16
17#include <compare>
18#include <iterator>
19#include <memory>
20#include <type_traits>
21#include <utility>
22
23namespace sparrow
24{
25 namespace detail
26 {
27 // Since C++20, iterators do not require dereference to return an
28 // lvalue, and therefore they do not require to provide operator->.
29 // However, because it is such a common operation, and because we
30 // don't want to propagate special cases for lvalue / rvalue handling
31 // everywhere in generic code, the iterator_base class provides an
32 // implementation of operator->, that returns either the address of
33 // an lvalue, or the address of a proxy on an rvalue.
34
35 // operator-> dispatcher for proxy references
36 template <class Reference, class Pointer>
38 {
39 struct proxy
40 {
41 explicit proxy(const Reference& x)
42 : m_reference(x)
43 {
44 }
45
46 explicit proxy(Reference&& x)
47 : m_reference(std::move(x))
48 {
49 }
50
51 Reference* operator->()
52 {
53 return std::addressof(m_reference);
54 }
55
56 private:
57
58 Reference m_reference;
59 };
60
62
63 [[nodiscard]] static result_type apply(const Reference& x)
64 {
65 return result_type(x);
66 }
67
68 [[nodiscard]] static result_type apply(Reference&& x)
69 {
70 return result_type(std::move(x));
71 }
72 };
73
74 // operator-> dispatcher for true references
75 template <class T, class Pointer>
76 struct operator_arrow_dispatcher<T&, Pointer>
77 {
78 using result_type = Pointer;
79
80 static result_type apply(T& x)
81 {
82 return std::addressof(x);
83 }
84 };
85 }
86
87 // Base class implementing the interface of a standard iterator
88 // that models the given IteratorConcept. Only the specializations
89 // for specific IteratorConcept values are defined. Currently,
90 // output_iterator_tag and input_iterator_tag are not supported.
91 // This allows a lot of simplifications regarding the definitions of
92 // postfix increment operators and related methods.
93 template <class Derived, class IteratorConcept, class Element, class Reference, class Difference>
95
96 // Utility class for accessing private methods
97 // of iterators.
99 {
100 template <class It>
101 static typename It::reference dereference(const It& it)
102 {
103 return it.dereference();
104 }
105
106 template <class It>
107 static void increment(It& it)
108 {
109 it.increment();
110 }
111
112 template <class It>
113 static void decrement(It& it)
114 {
115 it.decrement();
116 }
117
118 template <class It>
119 static void advance(It& it, typename It::difference_type n)
120 {
121 it.advance(n);
122 }
123
124// On MSVC and GCC < 13, those methods need to be public to be accessible by friend functions.
125#if _WIN32 || __GNUC__ < 13
126
127 public:
128
129#endif
130 template <class It>
131 [[nodiscard]] static typename It::difference_type distance_to(const It& lhs, const It& rhs)
132 {
133 return lhs.distance_to(rhs);
134 }
135
136 template <class It>
137 [[nodiscard]] static bool equal(const It& lhs, const It& rhs)
138 {
139 return lhs.equal(rhs);
140 }
141
142 template <class It>
143 [[nodiscard]] static bool less_than(const It& lhs, const It& rhs)
144 {
145 return lhs.less_than(rhs);
146 }
147
148// On MSVC and GCC < 13, those methods need to be public to be accessible by friend functions.
149#if _WIN32 || __GNUC__ < 13
150
151 private:
152
153#endif
154
155 template <class Derived, class E, class T, class R, class D>
156 friend class iterator_root_base;
157
158 template <class It>
159 friend typename It::difference_type operator-(const It&, const It&);
160
161 template <class It>
162 friend bool operator==(const It&, const It&);
163
164 template <class It>
165 friend std::strong_ordering operator<=>(const It&, const It&);
166 };
167
168 // Specialization of iterator_root_base for forward iterator.
169 template <class Derived, class Element, class Reference, class Difference>
170 class iterator_root_base<Derived, Element, std::forward_iterator_tag, Reference, Difference>
171 {
172 private:
173
174 using operator_arrow_dispatcher = detail::operator_arrow_dispatcher<Reference, Element*>;
175
176 public:
177
178 using derived_type = Derived;
179 using value_type = std::remove_cv_t<Element>;
180 using reference = Reference;
181 using pointer = typename operator_arrow_dispatcher::result_type;
182 using difference_type = Difference;
183 using iterator_category = std::forward_iterator_tag;
184 using iterator_concept = std::forward_iterator_tag;
185
186 reference operator*() const
187 {
188 return iterator_access::dereference(this->derived());
189 }
190
191 pointer operator->() const
192 {
193 return operator_arrow_dispatcher::apply(*this->derived());
194 }
195
196 derived_type& operator++()
197 {
198 iterator_access::increment(this->derived());
199 return this->derived();
200 }
201
202 derived_type operator++(int)
203 {
204 derived_type tmp(this->derived());
205 ++*this;
206 return tmp;
207 }
208
209 friend inline bool operator==(const derived_type& lhs, const derived_type& rhs)
210 {
211 return iterator_access::equal(lhs, rhs);
212 }
213
214 protected:
215
216 [[nodiscard]] derived_type& derived()
217 {
218 return *static_cast<derived_type*>(this);
219 }
220
221 [[nodiscard]] const derived_type& derived() const
222 {
223 return *static_cast<const derived_type*>(this);
224 }
225 };
226
227 // Specialization of iterator_root_base for bidirectional iterator.
228 template <class Derived, class Element, class Reference, class Difference>
229 class iterator_root_base<Derived, Element, std::bidirectional_iterator_tag, Reference, Difference>
230 : public iterator_root_base<Derived, Element, std::forward_iterator_tag, Reference, Difference>
231 {
232 public:
233
234 using base_type = iterator_root_base<Derived, Element, std::forward_iterator_tag, Reference, Difference>;
235 using derived_type = typename base_type::derived_type;
236 using iterator_category = std::bidirectional_iterator_tag;
237 using iterator_concept = std::bidirectional_iterator_tag;
238
239 derived_type& operator--()
240 {
241 iterator_access::decrement(this->derived());
242 return this->derived();
243 }
244
245 derived_type operator--(int)
246 {
247 derived_type tmp(this->derived());
248 --*this;
249 return tmp;
250 }
251 };
252
253 // Specialization of iterator_root_base for random access iterator.
254 template <class Derived, class Element, class Reference, class Difference>
255 class iterator_root_base<Derived, Element, std::random_access_iterator_tag, Reference, Difference>
256 : public iterator_root_base<Derived, Element, std::bidirectional_iterator_tag, Reference, Difference>
257 {
258 public:
259
261 using derived_type = typename base_type::derived_type;
262 using reference = typename base_type::reference;
263 using difference_type = typename base_type::difference_type;
264 using iterator_category = std::random_access_iterator_tag;
265 using iterator_concept = std::random_access_iterator_tag;
266
268 {
269 iterator_access::advance(this->derived(), n);
270 return this->derived();
271 }
272
274 {
275 derived_type tmp(it);
276 return tmp += n;
277 }
278
280 {
281 derived_type tmp(it);
282 return tmp += n;
283 }
284
286 {
287 iterator_access::advance(this->derived(), -n);
288 return this->derived();
289 }
290
292 {
293 derived_type tmp(it);
294 return tmp -= n;
295 }
296
298 {
299 return iterator_access::dereference(this->derived() + n);
300 }
301
302 friend inline difference_type operator-(const derived_type& lhs, const derived_type& rhs)
303 {
304 return iterator_access::distance_to(rhs, lhs);
305 }
306
307 friend inline std::strong_ordering operator<=>(const derived_type& lhs, const derived_type& rhs)
308 {
309 if (iterator_access::less_than(lhs, rhs))
310 {
311 return std::strong_ordering::less;
312 }
313 else if (iterator_access::equal(lhs, rhs))
314 {
315 return std::strong_ordering::equal;
316 }
317 else
318 {
319 return std::strong_ordering::greater;
320 }
321 }
322 };
323
324 // Specialization of iterator_root_base for contiguous iterator.
325 template <class Derived, class Element, class Reference, class Difference>
326 class iterator_root_base<Derived, Element, std::contiguous_iterator_tag, Reference, Difference>
327 : public iterator_root_base<Derived, Element, std::random_access_iterator_tag, Reference, Difference>
328 {
329 public:
330
331#ifdef __APPLE__
332 // Apple Clang wrong implementation of contiguous_iterator concept
334 using element_type = typename base_type::value_type;
335#endif
336 using iterator_concept = std::contiguous_iterator_tag;
337 };
338
339 /*
340 * @class iterator_base
341 * @brief Base class for iterator
342 *
343 * iterator_base is a CRTP base class that implements the interface of standard iterators,
344 * based on functions that must be supplied by a derived iterator class.
345 *
346 * The derived iterator class must define methods implementing the iterator's core behavior.
347 * The following table describes the expressions that must be valid, depending on the concept
348 * modeled by the derived iterator.
349 *
350 *
351 * | Concept | Expression | Implementation |
352 * | ------------- | ------------------- | ---------------------------- |
353 * | forward | it.dereference() | Access the value referred to |
354 * | forward | it.equal(jit) | Compare for equality |
355 * | forward | it.increment() | Advance by one position |
356 * | bidirectional | it.decrement() | Retreat by one position |
357 * | random access | it.advance(n) | Advance by n positions |
358 * | random access | it.distance_to(jit) | Compute the distance |
359 * | random access | it.less_than(jit) | Compare for inequality |
360 *
361 * These methods should be private and the derived iterator should declare sparrow::iterator_access
362 * as a friend class so that `iterator_base` implementation can access those methods.
363 *
364 * @tparam Derived The type inheriting from this CRTP base class
365 * @tparam Element The element type of the iterator, used to compute the `value_type` inner type.
366 * Element should be `value_type` iterators, and `const value_type` for const iterators.
367 * @tparam IteratorConcept The tag corresponding to the concept satisfied by the iterator.
368 * `input_iterator_tag` and `output_iterator_tag` are not supported.
369 * @tparam Reference The return type of the dereferencing operation. By default, `Element&`.
370 * @tparam Difference The unsigned integer used as the `difference_type`. By default, `std::ptrdiff_t`.
371 *
372 * @remark By default, the `iterator_category` inner type is the same as the `iterator_concept` inner type
373 * (except for contiguous_iterator, where it is `random_access_iterator_tag`). This can be overloaded
374 * in the inheriting iterator class.
375 */
376 template <class Derived, class Element, class IteratorConcept, class Reference = Element&, class Difference = std::ptrdiff_t>
377 class iterator_base : public iterator_root_base<Derived, Element, IteratorConcept, Reference, Difference>
378 {
379 };
380
381 /*
382 * @class iterator_adaptor
383 * @brief generic iterator adaptor
384 *
385 * This class forwards the calls to its "base" iterator, i.e.
386 * the iterator it adapts. Iterator adaptor classes should
387 * inherit from this class and redefine the private methods
388 * they need only.
389 */
390 template <
391 class Derived,
392 class Iter,
393 class Element,
394 class IteratorConcept = typename std::iterator_traits<Iter>::iterator_category,
395 class Reference = std::iter_reference_t<Iter>,
396 class Difference = std::iter_difference_t<Iter>>
397 class iterator_adaptor : public iterator_base<Derived, Element, IteratorConcept, Reference, Difference>
398 {
399 public:
400
403 using reference = typename base_type::reference;
404 using difference_type = typename base_type::difference_type;
405 using iterator_type = Iter;
406
407 iterator_adaptor() = default;
408
409 explicit iterator_adaptor(const iterator_type& iter)
410 : p_iter(iter)
411 {
412 }
413
414 [[nodiscard]] const iterator_type& base() const
415 {
416 return p_iter;
417 }
418
419 private:
420
421 reference dereference() const
422 {
423 return *p_iter;
424 }
425
426 void increment()
427 {
428 ++p_iter;
429 }
430
431 void decrement()
432 {
433 --p_iter;
434 }
435
436 void advance(difference_type n)
437 {
438 p_iter += n;
439 }
440
441 [[nodiscard]] difference_type distance_to(const self_type& rhs) const
442 {
443 return rhs.p_iter - p_iter;
444 }
445
446 [[nodiscard]] bool equal(const self_type& rhs) const
447 {
448 return p_iter == rhs.p_iter;
449 }
450
451 [[nodiscard]] bool less_than(const self_type& rhs) const
452 {
453 return p_iter < rhs.p_iter;
454 }
455
456 iterator_type p_iter = {};
457
458 friend class iterator_access;
459 };
460
461 /*
462 * @class pointer_iterator
463 * @brief iterator adaptor for pointers
464 *
465 * pointer_iterator gives an iterator API to a pointer.
466 * @tparam T the pointer to adapt
467 */
468 template <class T>
470
471 template <class T>
472 class pointer_iterator<T*>
473 : public iterator_adaptor<pointer_iterator<T*>, T*, T, std::contiguous_iterator_tag>
474 {
475 public:
476
477 using self_type = pointer_iterator<T*>;
479 using iterator_type = typename base_type::iterator_type;
480
481 pointer_iterator() = default;
482
483 explicit pointer_iterator(iterator_type p)
484 : base_type(p)
485 {
486 }
487
488 template <class U>
489 requires std::convertible_to<U*, iterator_type>
490 explicit pointer_iterator(U* u)
491 : base_type(iterator_type(u))
492 {
493 }
494 };
495
496 template <class T>
498 {
499 return pointer_iterator<T*>(t);
500 }
501
502 template <class InputIt, std::integral Distance>
503 [[nodiscard]] constexpr InputIt next(InputIt it, Distance n)
504 {
505 std::advance(it, n);
506 return it;
507 }
508}
friend bool operator==(const It &, const It &)
friend It::difference_type operator-(const It &, const It &)
friend std::strong_ordering operator<=>(const It &, const It &)
static bool less_than(const It &lhs, const It &rhs)
Definition iterator.hpp:143
friend class iterator_root_base
Definition iterator.hpp:156
static It::difference_type distance_to(const It &lhs, const It &rhs)
Definition iterator.hpp:131
static bool equal(const It &lhs, const It &rhs)
Definition iterator.hpp:137
iterator_adaptor< Derived, Iter, Element, IteratorConcept, Reference, Difference > self_type
Definition iterator.hpp:402
iterator_adaptor(const iterator_type &iter)
Definition iterator.hpp:409
iterator_base< Derived, Element, IteratorConcept, Reference, Difference > base_type
Definition iterator.hpp:401
const iterator_type & base() const
Definition iterator.hpp:414
friend difference_type operator-(const derived_type &lhs, const derived_type &rhs)
Definition iterator.hpp:302
friend std::strong_ordering operator<=>(const derived_type &lhs, const derived_type &rhs)
Definition iterator.hpp:307
iterator_root_base< Derived, Element, std::bidirectional_iterator_tag, Reference, Difference > base_type
Definition iterator.hpp:260
pointer_iterator< T * > make_pointer_iterator(T *t)
Definition iterator.hpp:497
SPARROW_API bool operator==(const array &lhs, const array &rhs)
Compares the content of two arrays.
constexpr InputIt next(InputIt it, Distance n)
Definition iterator.hpp:503
static result_type apply(Reference &&x)
Definition iterator.hpp:68
static result_type apply(const Reference &x)
Definition iterator.hpp:63