[WebAssembly] Fix asan issue from https://reviews.llvm.org/D121349
[llvm-project.git] / libcxx / test / support / test_iterators.h
blob6b546e6b2f6c68f9169b4a27e7674bc45968075d
1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #ifndef SUPPORT_TEST_ITERATORS_H
10 #define SUPPORT_TEST_ITERATORS_H
12 #include <cassert>
13 #include <concepts>
14 #include <iterator>
15 #include <stdexcept>
16 #include <utility>
18 #include "test_macros.h"
20 // This iterator meets C++20's Cpp17OutputIterator requirements, as described
21 // in Table 90 ([output.iterators]).
22 template <class It>
23 class cpp17_output_iterator
25 It it_;
27 template <class U> friend class cpp17_output_iterator;
28 public:
29 typedef std::output_iterator_tag iterator_category;
30 typedef void value_type;
31 typedef typename std::iterator_traits<It>::difference_type difference_type;
32 typedef It pointer;
33 typedef typename std::iterator_traits<It>::reference reference;
35 TEST_CONSTEXPR explicit cpp17_output_iterator(It it) : it_(std::move(it)) {}
36 template <class U>
37 TEST_CONSTEXPR cpp17_output_iterator(const cpp17_output_iterator<U>& u) :it_(u.it_) {}
39 TEST_CONSTEXPR reference operator*() const {return *it_;}
41 TEST_CONSTEXPR_CXX14 cpp17_output_iterator& operator++() {++it_; return *this;}
42 TEST_CONSTEXPR_CXX14 cpp17_output_iterator operator++(int) {return cpp17_output_iterator(it_++);}
44 friend TEST_CONSTEXPR It base(const cpp17_output_iterator& i) { return i.it_; }
46 template <class T>
47 void operator,(T const &) = delete;
49 #if _LIBCPP_STD_VER > 17
50 static_assert(std::output_iterator<cpp17_output_iterator<int*>, int>);
51 #endif
53 // This iterator meets C++20's Cpp17InputIterator requirements, as described
54 // in Table 89 ([input.iterators]).
55 template <class It, class ItTraits = It>
56 class cpp17_input_iterator
58 typedef std::iterator_traits<ItTraits> Traits;
59 It it_;
61 template <class U, class T> friend class cpp17_input_iterator;
62 public:
63 typedef std::input_iterator_tag iterator_category;
64 typedef typename Traits::value_type value_type;
65 typedef typename Traits::difference_type difference_type;
66 typedef It pointer;
67 typedef typename Traits::reference reference;
69 TEST_CONSTEXPR explicit cpp17_input_iterator(It it) : it_(it) {}
70 template <class U, class T>
71 TEST_CONSTEXPR cpp17_input_iterator(const cpp17_input_iterator<U, T>& u) : it_(u.it_) {}
73 TEST_CONSTEXPR reference operator*() const {return *it_;}
75 TEST_CONSTEXPR_CXX14 cpp17_input_iterator& operator++() {++it_; return *this;}
76 TEST_CONSTEXPR_CXX14 cpp17_input_iterator operator++(int) {return cpp17_input_iterator(it_++);}
78 friend TEST_CONSTEXPR bool operator==(const cpp17_input_iterator& x, const cpp17_input_iterator& y) {return x.it_ == y.it_;}
79 friend TEST_CONSTEXPR bool operator!=(const cpp17_input_iterator& x, const cpp17_input_iterator& y) {return x.it_ != y.it_;}
81 friend TEST_CONSTEXPR It base(const cpp17_input_iterator& i) { return i.it_; }
83 template <class T>
84 void operator,(T const &) = delete;
86 #if _LIBCPP_STD_VER > 17
87 static_assert(std::input_iterator<cpp17_input_iterator<int*>>);
88 #endif
90 template <class It>
91 class forward_iterator
93 It it_;
95 template <class U> friend class forward_iterator;
96 public:
97 typedef std::forward_iterator_tag iterator_category;
98 typedef typename std::iterator_traits<It>::value_type value_type;
99 typedef typename std::iterator_traits<It>::difference_type difference_type;
100 typedef It pointer;
101 typedef typename std::iterator_traits<It>::reference reference;
103 TEST_CONSTEXPR forward_iterator() : it_() {}
104 TEST_CONSTEXPR explicit forward_iterator(It it) : it_(it) {}
105 template <class U>
106 TEST_CONSTEXPR forward_iterator(const forward_iterator<U>& u) : it_(u.it_) {}
108 TEST_CONSTEXPR reference operator*() const {return *it_;}
110 TEST_CONSTEXPR_CXX14 forward_iterator& operator++() {++it_; return *this;}
111 TEST_CONSTEXPR_CXX14 forward_iterator operator++(int) {return forward_iterator(it_++);}
113 friend TEST_CONSTEXPR bool operator==(const forward_iterator& x, const forward_iterator& y) {return x.it_ == y.it_;}
114 friend TEST_CONSTEXPR bool operator!=(const forward_iterator& x, const forward_iterator& y) {return x.it_ != y.it_;}
116 friend TEST_CONSTEXPR It base(const forward_iterator& i) { return i.it_; }
118 template <class T>
119 void operator,(T const &) = delete;
122 template <class It>
123 class bidirectional_iterator
125 It it_;
127 template <class U> friend class bidirectional_iterator;
128 public:
129 typedef std::bidirectional_iterator_tag iterator_category;
130 typedef typename std::iterator_traits<It>::value_type value_type;
131 typedef typename std::iterator_traits<It>::difference_type difference_type;
132 typedef It pointer;
133 typedef typename std::iterator_traits<It>::reference reference;
135 TEST_CONSTEXPR bidirectional_iterator() : it_() {}
136 TEST_CONSTEXPR explicit bidirectional_iterator(It it) : it_(it) {}
137 template <class U>
138 TEST_CONSTEXPR bidirectional_iterator(const bidirectional_iterator<U>& u) : it_(u.it_) {}
140 TEST_CONSTEXPR reference operator*() const {return *it_;}
142 TEST_CONSTEXPR_CXX14 bidirectional_iterator& operator++() {++it_; return *this;}
143 TEST_CONSTEXPR_CXX14 bidirectional_iterator& operator--() {--it_; return *this;}
144 TEST_CONSTEXPR_CXX14 bidirectional_iterator operator++(int) {return bidirectional_iterator(it_++);}
145 TEST_CONSTEXPR_CXX14 bidirectional_iterator operator--(int) {return bidirectional_iterator(it_--);}
147 friend TEST_CONSTEXPR bool operator==(const bidirectional_iterator& x, const bidirectional_iterator& y) {return x.it_ == y.it_;}
148 friend TEST_CONSTEXPR bool operator!=(const bidirectional_iterator& x, const bidirectional_iterator& y) {return x.it_ != y.it_;}
150 friend TEST_CONSTEXPR It base(const bidirectional_iterator& i) { return i.it_; }
152 template <class T>
153 void operator,(T const &) = delete;
156 template <class It>
157 class random_access_iterator
159 It it_;
161 template <class U> friend class random_access_iterator;
162 public:
163 typedef std::random_access_iterator_tag iterator_category;
164 typedef typename std::iterator_traits<It>::value_type value_type;
165 typedef typename std::iterator_traits<It>::difference_type difference_type;
166 typedef It pointer;
167 typedef typename std::iterator_traits<It>::reference reference;
169 TEST_CONSTEXPR random_access_iterator() : it_() {}
170 TEST_CONSTEXPR explicit random_access_iterator(It it) : it_(it) {}
171 template <class U>
172 TEST_CONSTEXPR random_access_iterator(const random_access_iterator<U>& u) : it_(u.it_) {}
174 TEST_CONSTEXPR_CXX14 reference operator*() const {return *it_;}
175 TEST_CONSTEXPR_CXX14 reference operator[](difference_type n) const {return it_[n];}
177 TEST_CONSTEXPR_CXX14 random_access_iterator& operator++() {++it_; return *this;}
178 TEST_CONSTEXPR_CXX14 random_access_iterator& operator--() {--it_; return *this;}
179 TEST_CONSTEXPR_CXX14 random_access_iterator operator++(int) {return random_access_iterator(it_++);}
180 TEST_CONSTEXPR_CXX14 random_access_iterator operator--(int) {return random_access_iterator(it_--);}
182 TEST_CONSTEXPR_CXX14 random_access_iterator& operator+=(difference_type n) {it_ += n; return *this;}
183 TEST_CONSTEXPR_CXX14 random_access_iterator& operator-=(difference_type n) {it_ -= n; return *this;}
184 friend TEST_CONSTEXPR_CXX14 random_access_iterator operator+(random_access_iterator x, difference_type n) {x += n; return x;}
185 friend TEST_CONSTEXPR_CXX14 random_access_iterator operator+(difference_type n, random_access_iterator x) {x += n; return x;}
186 friend TEST_CONSTEXPR_CXX14 random_access_iterator operator-(random_access_iterator x, difference_type n) {x -= n; return x;}
187 friend TEST_CONSTEXPR difference_type operator-(random_access_iterator x, random_access_iterator y) {return x.it_ - y.it_;}
189 friend TEST_CONSTEXPR bool operator==(const random_access_iterator& x, const random_access_iterator& y) {return x.it_ == y.it_;}
190 friend TEST_CONSTEXPR bool operator!=(const random_access_iterator& x, const random_access_iterator& y) {return x.it_ != y.it_;}
191 friend TEST_CONSTEXPR bool operator< (const random_access_iterator& x, const random_access_iterator& y) {return x.it_ < y.it_;}
192 friend TEST_CONSTEXPR bool operator<=(const random_access_iterator& x, const random_access_iterator& y) {return x.it_ <= y.it_;}
193 friend TEST_CONSTEXPR bool operator> (const random_access_iterator& x, const random_access_iterator& y) {return x.it_ > y.it_;}
194 friend TEST_CONSTEXPR bool operator>=(const random_access_iterator& x, const random_access_iterator& y) {return x.it_ >= y.it_;}
196 friend TEST_CONSTEXPR It base(const random_access_iterator& i) { return i.it_; }
198 template <class T>
199 void operator,(T const &) = delete;
202 #if TEST_STD_VER > 17
203 template <class It>
204 class contiguous_iterator
206 static_assert(std::is_pointer_v<It>, "Things probably break in this case");
208 It it_;
210 template <class U> friend class contiguous_iterator;
211 public:
212 typedef std::contiguous_iterator_tag iterator_category;
213 typedef typename std::iterator_traits<It>::value_type value_type;
214 typedef typename std::iterator_traits<It>::difference_type difference_type;
215 typedef It pointer;
216 typedef typename std::iterator_traits<It>::reference reference;
217 typedef typename std::remove_pointer<It>::type element_type;
219 TEST_CONSTEXPR_CXX14 It base() const {return it_;}
221 TEST_CONSTEXPR_CXX14 contiguous_iterator() : it_() {}
222 TEST_CONSTEXPR_CXX14 explicit contiguous_iterator(It it) : it_(it) {}
223 template <class U>
224 TEST_CONSTEXPR_CXX14 contiguous_iterator(const contiguous_iterator<U>& u) : it_(u.it_) {}
226 TEST_CONSTEXPR reference operator*() const {return *it_;}
227 TEST_CONSTEXPR pointer operator->() const {return it_;}
228 TEST_CONSTEXPR reference operator[](difference_type n) const {return it_[n];}
230 TEST_CONSTEXPR_CXX14 contiguous_iterator& operator++() {++it_; return *this;}
231 TEST_CONSTEXPR_CXX14 contiguous_iterator& operator--() {--it_; return *this;}
232 TEST_CONSTEXPR_CXX14 contiguous_iterator operator++(int) {return contiguous_iterator(it_++);}
233 TEST_CONSTEXPR_CXX14 contiguous_iterator operator--(int) {return contiguous_iterator(it_--);}
235 TEST_CONSTEXPR_CXX14 contiguous_iterator& operator+=(difference_type n) {it_ += n; return *this;}
236 TEST_CONSTEXPR_CXX14 contiguous_iterator& operator-=(difference_type n) {it_ -= n; return *this;}
237 friend TEST_CONSTEXPR_CXX14 contiguous_iterator operator+(contiguous_iterator x, difference_type n) {x += n; return x;}
238 friend TEST_CONSTEXPR_CXX14 contiguous_iterator operator+(difference_type n, contiguous_iterator x) {x += n; return x;}
239 friend TEST_CONSTEXPR_CXX14 contiguous_iterator operator-(contiguous_iterator x, difference_type n) {x -= n; return x;}
240 friend TEST_CONSTEXPR difference_type operator-(contiguous_iterator x, contiguous_iterator y) {return x.it_ - y.it_;}
242 friend TEST_CONSTEXPR bool operator==(const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ == y.it_;}
243 friend TEST_CONSTEXPR bool operator!=(const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ != y.it_;}
244 friend TEST_CONSTEXPR bool operator< (const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ < y.it_;}
245 friend TEST_CONSTEXPR bool operator<=(const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ <= y.it_;}
246 friend TEST_CONSTEXPR bool operator> (const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ > y.it_;}
247 friend TEST_CONSTEXPR bool operator>=(const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ >= y.it_;}
249 friend TEST_CONSTEXPR It base(const contiguous_iterator& i) { return i.it_; }
251 template <class T>
252 void operator,(T const &) = delete;
255 template <class It>
256 class three_way_contiguous_iterator
258 static_assert(std::is_pointer_v<It>, "Things probably break in this case");
260 It it_;
262 template <class U> friend class three_way_contiguous_iterator;
263 public:
264 typedef std::contiguous_iterator_tag iterator_category;
265 typedef typename std::iterator_traits<It>::value_type value_type;
266 typedef typename std::iterator_traits<It>::difference_type difference_type;
267 typedef It pointer;
268 typedef typename std::iterator_traits<It>::reference reference;
269 typedef typename std::remove_pointer<It>::type element_type;
271 constexpr It base() const {return it_;}
273 constexpr three_way_contiguous_iterator() : it_() {}
274 constexpr explicit three_way_contiguous_iterator(It it) : it_(it) {}
275 template <class U>
276 constexpr three_way_contiguous_iterator(const three_way_contiguous_iterator<U>& u) : it_(u.it_) {}
278 constexpr reference operator*() const {return *it_;}
279 constexpr pointer operator->() const {return it_;}
280 constexpr reference operator[](difference_type n) const {return it_[n];}
282 constexpr three_way_contiguous_iterator& operator++() {++it_; return *this;}
283 constexpr three_way_contiguous_iterator& operator--() {--it_; return *this;}
284 constexpr three_way_contiguous_iterator operator++(int) {return three_way_contiguous_iterator(it_++);}
285 constexpr three_way_contiguous_iterator operator--(int) {return three_way_contiguous_iterator(it_--);}
287 constexpr three_way_contiguous_iterator& operator+=(difference_type n) {it_ += n; return *this;}
288 constexpr three_way_contiguous_iterator& operator-=(difference_type n) {it_ -= n; return *this;}
289 friend constexpr three_way_contiguous_iterator operator+(three_way_contiguous_iterator x, difference_type n) {x += n; return x;}
290 friend constexpr three_way_contiguous_iterator operator+(difference_type n, three_way_contiguous_iterator x) {x += n; return x;}
291 friend constexpr three_way_contiguous_iterator operator-(three_way_contiguous_iterator x, difference_type n) {x -= n; return x;}
292 friend constexpr difference_type operator-(three_way_contiguous_iterator x, three_way_contiguous_iterator y) {return x.it_ - y.it_;}
294 friend constexpr auto operator<=>(const three_way_contiguous_iterator& x, const three_way_contiguous_iterator& y) {return x.it_ <=> y.it_;}
295 friend constexpr bool operator==(const three_way_contiguous_iterator& x, const three_way_contiguous_iterator& y) {return x.it_ == y.it_;}
297 template <class T>
298 void operator,(T const &) = delete;
300 #endif // TEST_STD_VER > 17
302 template <class Iter> // ADL base() for everything else (including pointers)
303 TEST_CONSTEXPR Iter base(Iter i) { return i; }
305 template <typename T>
306 struct ThrowingIterator {
307 typedef std::bidirectional_iterator_tag iterator_category;
308 typedef ptrdiff_t difference_type;
309 typedef const T value_type;
310 typedef const T * pointer;
311 typedef const T & reference;
313 enum ThrowingAction { TAIncrement, TADecrement, TADereference, TAAssignment, TAComparison };
315 TEST_CONSTEXPR ThrowingIterator()
316 : begin_(nullptr), end_(nullptr), current_(nullptr), action_(TADereference), index_(0) {}
317 TEST_CONSTEXPR explicit ThrowingIterator(const T* first, const T* last, int index = 0,
318 ThrowingAction action = TADereference)
319 : begin_(first), end_(last), current_(first), action_(action), index_(index) {}
320 TEST_CONSTEXPR ThrowingIterator(const ThrowingIterator &rhs)
321 : begin_(rhs.begin_), end_(rhs.end_), current_(rhs.current_), action_(rhs.action_), index_(rhs.index_) {}
323 TEST_CONSTEXPR_CXX14 ThrowingIterator& operator=(const ThrowingIterator& rhs) {
324 if (action_ == TAAssignment && --index_ < 0) {
325 #ifndef TEST_HAS_NO_EXCEPTIONS
326 throw std::runtime_error("throw from iterator assignment");
327 #else
328 assert(false);
329 #endif
331 begin_ = rhs.begin_;
332 end_ = rhs.end_;
333 current_ = rhs.current_;
334 action_ = rhs.action_;
335 index_ = rhs.index_;
336 return *this;
339 TEST_CONSTEXPR_CXX14 reference operator*() const {
340 if (action_ == TADereference && --index_ < 0) {
341 #ifndef TEST_HAS_NO_EXCEPTIONS
342 throw std::runtime_error("throw from iterator dereference");
343 #else
344 assert(false);
345 #endif
347 return *current_;
350 TEST_CONSTEXPR_CXX14 ThrowingIterator& operator++() {
351 if (action_ == TAIncrement && --index_ < 0) {
352 #ifndef TEST_HAS_NO_EXCEPTIONS
353 throw std::runtime_error("throw from iterator increment");
354 #else
355 assert(false);
356 #endif
358 ++current_;
359 return *this;
362 TEST_CONSTEXPR_CXX14 ThrowingIterator operator++(int) {
363 ThrowingIterator temp = *this;
364 ++(*this);
365 return temp;
368 TEST_CONSTEXPR_CXX14 ThrowingIterator& operator--() {
369 if (action_ == TADecrement && --index_ < 0) {
370 #ifndef TEST_HAS_NO_EXCEPTIONS
371 throw std::runtime_error("throw from iterator decrement");
372 #else
373 assert(false);
374 #endif
376 --current_;
377 return *this;
380 TEST_CONSTEXPR_CXX14 ThrowingIterator operator--(int) {
381 ThrowingIterator temp = *this;
382 --(*this);
383 return temp;
386 TEST_CONSTEXPR_CXX14 friend bool operator==(const ThrowingIterator& a, const ThrowingIterator& b) {
387 if (a.action_ == TAComparison && --a.index_ < 0) {
388 #ifndef TEST_HAS_NO_EXCEPTIONS
389 throw std::runtime_error("throw from iterator comparison");
390 #else
391 assert(false);
392 #endif
394 bool atEndL = a.current_ == a.end_;
395 bool atEndR = b.current_ == b.end_;
396 if (atEndL != atEndR) return false; // one is at the end (or empty), the other is not.
397 if (atEndL) return true; // both are at the end (or empty)
398 return a.current_ == b.current_;
401 TEST_CONSTEXPR friend bool operator!=(const ThrowingIterator& a, const ThrowingIterator& b) {
402 return !(a == b);
405 template <class T2>
406 void operator,(T2 const &) = delete;
408 private:
409 const T* begin_;
410 const T* end_;
411 const T* current_;
412 ThrowingAction action_;
413 mutable int index_;
416 template <typename T>
417 struct NonThrowingIterator {
418 typedef std::bidirectional_iterator_tag iterator_category;
419 typedef ptrdiff_t difference_type;
420 typedef const T value_type;
421 typedef const T * pointer;
422 typedef const T & reference;
424 NonThrowingIterator()
425 : begin_(nullptr), end_(nullptr), current_(nullptr) {}
426 explicit NonThrowingIterator(const T *first, const T *last)
427 : begin_(first), end_(last), current_(first) {}
428 NonThrowingIterator(const NonThrowingIterator& rhs)
429 : begin_(rhs.begin_), end_(rhs.end_), current_(rhs.current_) {}
431 NonThrowingIterator& operator=(const NonThrowingIterator& rhs) TEST_NOEXCEPT {
432 begin_ = rhs.begin_;
433 end_ = rhs.end_;
434 current_ = rhs.current_;
435 return *this;
438 reference operator*() const TEST_NOEXCEPT {
439 return *current_;
442 NonThrowingIterator& operator++() TEST_NOEXCEPT {
443 ++current_;
444 return *this;
447 NonThrowingIterator operator++(int) TEST_NOEXCEPT {
448 NonThrowingIterator temp = *this;
449 ++(*this);
450 return temp;
453 NonThrowingIterator & operator--() TEST_NOEXCEPT {
454 --current_;
455 return *this;
458 NonThrowingIterator operator--(int) TEST_NOEXCEPT {
459 NonThrowingIterator temp = *this;
460 --(*this);
461 return temp;
464 friend bool operator==(const NonThrowingIterator& a, const NonThrowingIterator& b) TEST_NOEXCEPT {
465 bool atEndL = a.current_ == a.end_;
466 bool atEndR = b.current_ == b.end_;
467 if (atEndL != atEndR) return false; // one is at the end (or empty), the other is not.
468 if (atEndL) return true; // both are at the end (or empty)
469 return a.current_ == b.current_;
472 friend bool operator!=(const NonThrowingIterator& a, const NonThrowingIterator& b) TEST_NOEXCEPT {
473 return !(a == b);
476 template <class T2>
477 void operator,(T2 const &) = delete;
479 private:
480 const T *begin_;
481 const T *end_;
482 const T *current_;
485 #if TEST_STD_VER > 17
487 template <class It>
488 class cpp20_input_iterator
490 It it_;
492 public:
493 using value_type = std::iter_value_t<It>;
494 using difference_type = std::iter_difference_t<It>;
495 using iterator_concept = std::input_iterator_tag;
497 constexpr explicit cpp20_input_iterator(It it) : it_(it) {}
498 cpp20_input_iterator(cpp20_input_iterator&&) = default;
499 cpp20_input_iterator& operator=(cpp20_input_iterator&&) = default;
500 constexpr decltype(auto) operator*() const { return *it_; }
501 constexpr cpp20_input_iterator& operator++() { ++it_; return *this; }
502 constexpr void operator++(int) { ++it_; }
504 friend constexpr It base(const cpp20_input_iterator& i) { return i.it_; }
506 template <class T>
507 void operator,(T const &) = delete;
510 template<std::input_or_output_iterator>
511 struct iter_value_or_void { using type = void; };
513 template<std::input_iterator I>
514 struct iter_value_or_void<I> {
515 using type = std::iter_value_t<I>;
518 // Iterator adaptor that counts the number of times the iterator has had a successor/predecessor
519 // operation called. Has two recorders:
520 // * `stride_count`, which records the total number of calls to an op++, op--, op+=, or op-=.
521 // * `stride_displacement`, which records the displacement of the calls. This means that both
522 // op++/op+= will increase the displacement counter by 1, and op--/op-= will decrease the
523 // displacement counter by 1.
524 template <class It>
525 class stride_counting_iterator {
526 public:
527 using value_type = typename iter_value_or_void<It>::type;
528 using difference_type = std::iter_difference_t<It>;
529 using iterator_concept =
530 std::conditional_t<std::contiguous_iterator<It>, std::contiguous_iterator_tag,
531 std::conditional_t<std::random_access_iterator<It>, std::random_access_iterator_tag,
532 std::conditional_t<std::bidirectional_iterator<It>, std::bidirectional_iterator_tag,
533 std::conditional_t<std::forward_iterator<It>, std::forward_iterator_tag,
534 std::conditional_t<std::input_iterator<It>, std::input_iterator_tag,
535 /* else */ std::output_iterator_tag
536 >>>>>;
538 stride_counting_iterator() requires std::default_initializable<It> = default;
540 constexpr explicit stride_counting_iterator(It const& it) : base_(base(it)) { }
542 friend constexpr It base(stride_counting_iterator const& it) { return It(it.base_); }
544 constexpr difference_type stride_count() const { return stride_count_; }
546 constexpr difference_type stride_displacement() const { return stride_displacement_; }
548 constexpr decltype(auto) operator*() const { return *It(base_); }
550 constexpr decltype(auto) operator[](difference_type n) const { return It(base_)[n]; }
552 constexpr stride_counting_iterator& operator++() {
553 It tmp(base_);
554 base_ = base(++tmp);
555 ++stride_count_;
556 ++stride_displacement_;
557 return *this;
560 constexpr void operator++(int) { ++*this; }
562 constexpr stride_counting_iterator operator++(int)
563 requires std::forward_iterator<It>
565 auto temp = *this;
566 ++*this;
567 return temp;
570 constexpr stride_counting_iterator& operator--()
571 requires std::bidirectional_iterator<It>
573 It tmp(base_);
574 base_ = base(--tmp);
575 ++stride_count_;
576 --stride_displacement_;
577 return *this;
580 constexpr stride_counting_iterator operator--(int)
581 requires std::bidirectional_iterator<It>
583 auto temp = *this;
584 --*this;
585 return temp;
588 constexpr stride_counting_iterator& operator+=(difference_type const n)
589 requires std::random_access_iterator<It>
591 It tmp(base_);
592 base_ = base(tmp += n);
593 ++stride_count_;
594 ++stride_displacement_;
595 return *this;
598 constexpr stride_counting_iterator& operator-=(difference_type const n)
599 requires std::random_access_iterator<It>
601 It tmp(base_);
602 base_ = base(tmp -= n);
603 ++stride_count_;
604 --stride_displacement_;
605 return *this;
608 friend constexpr stride_counting_iterator operator+(stride_counting_iterator it, difference_type n)
609 requires std::random_access_iterator<It>
611 return it += n;
614 friend constexpr stride_counting_iterator operator+(difference_type n, stride_counting_iterator it)
615 requires std::random_access_iterator<It>
617 return it += n;
620 friend constexpr stride_counting_iterator operator-(stride_counting_iterator it, difference_type n)
621 requires std::random_access_iterator<It>
623 return it -= n;
626 friend constexpr difference_type operator-(stride_counting_iterator const& x, stride_counting_iterator const& y)
627 requires std::sized_sentinel_for<It, It>
629 return base(x) - base(y);
632 constexpr bool operator==(stride_counting_iterator const& other) const
633 requires std::sentinel_for<It, It>
635 return It(base_) == It(other.base_);
638 friend constexpr bool operator<(stride_counting_iterator const& x, stride_counting_iterator const& y)
639 requires std::random_access_iterator<It>
641 return It(x.base_) < It(y.base_);
644 friend constexpr bool operator>(stride_counting_iterator const& x, stride_counting_iterator const& y)
645 requires std::random_access_iterator<It>
647 return It(x.base_) > It(y.base_);
650 friend constexpr bool operator<=(stride_counting_iterator const& x, stride_counting_iterator const& y)
651 requires std::random_access_iterator<It>
653 return It(x.base_) <= It(y.base_);
656 friend constexpr bool operator>=(stride_counting_iterator const& x, stride_counting_iterator const& y)
657 requires std::random_access_iterator<It>
659 return It(x.base_) >= It(y.base_);
662 template <class T>
663 void operator,(T const &) = delete;
665 private:
666 decltype(base(std::declval<It>())) base_;
667 difference_type stride_count_ = 0;
668 difference_type stride_displacement_ = 0;
671 #endif // TEST_STD_VER > 17
673 #if TEST_STD_VER > 17
674 template <class It>
675 class sentinel_wrapper {
676 public:
677 explicit sentinel_wrapper() = default;
678 constexpr explicit sentinel_wrapper(const It& it) : base_(base(it)) {}
679 constexpr bool operator==(const It& other) const { return base_ == base(other); }
680 friend constexpr It base(const sentinel_wrapper& s) { return It(s.base_); }
681 private:
682 decltype(base(std::declval<It>())) base_;
685 template <class It>
686 class sized_sentinel {
687 public:
688 explicit sized_sentinel() = default;
689 constexpr explicit sized_sentinel(const It& it) : base_(base(it)) {}
690 constexpr bool operator==(const It& other) const { return base_ == base(other); }
691 friend constexpr auto operator-(const sized_sentinel& s, const It& i) { return s.base_ - base(i); }
692 friend constexpr auto operator-(const It& i, const sized_sentinel& s) { return base(i) - s.base_; }
693 friend constexpr It base(const sized_sentinel& s) { return It(s.base_); }
694 private:
695 decltype(base(std::declval<It>())) base_;
697 #endif // TEST_STD_VER > 17
699 #endif // SUPPORT_TEST_ITERATORS_H