1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef SUPPORT_TEST_ITERATORS_H
10 #define SUPPORT_TEST_ITERATORS_H
17 #include <type_traits>
20 #include "test_macros.h"
21 #include "type_algorithms.h"
24 // This iterator meets C++20's Cpp17OutputIterator requirements, as described
25 // in Table 90 ([output.iterators]).
27 class cpp17_output_iterator
31 template <class U
> friend class cpp17_output_iterator
;
33 typedef std::output_iterator_tag iterator_category
;
34 typedef void value_type
;
35 typedef typename
std::iterator_traits
<It
>::difference_type difference_type
;
37 typedef typename
std::iterator_traits
<It
>::reference reference
;
39 TEST_CONSTEXPR
explicit cpp17_output_iterator(It it
) : it_(std::move(it
)) {}
42 TEST_CONSTEXPR
cpp17_output_iterator(const cpp17_output_iterator
<U
>& u
) : it_(u
.it_
) {}
44 template <class U
, class = typename
std::enable_if
<std::is_default_constructible
<U
>::value
>::type
>
45 TEST_CONSTEXPR_CXX14
cpp17_output_iterator(cpp17_output_iterator
<U
>&& u
) : it_(u
.it_
) { u
.it_
= U(); }
47 TEST_CONSTEXPR reference
operator*() const {return *it_
;}
49 TEST_CONSTEXPR_CXX14 cpp17_output_iterator
& operator++() {++it_
; return *this;}
50 TEST_CONSTEXPR_CXX14 cpp17_output_iterator
operator++(int) {return cpp17_output_iterator(it_
++);}
52 friend TEST_CONSTEXPR It
base(const cpp17_output_iterator
& i
) { return i
.it_
; }
55 void operator,(T
const &) = delete;
59 cpp17_output_iterator(It
) -> cpp17_output_iterator
<It
>;
63 static_assert(std::output_iterator
<cpp17_output_iterator
<int*>, int>);
66 // This iterator meets C++20's Cpp17InputIterator requirements, as described
67 // in Table 89 ([input.iterators]).
68 template <class It
, class ItTraits
= It
>
69 class cpp17_input_iterator
71 typedef std::iterator_traits
<ItTraits
> Traits
;
74 template <class U
, class T
> friend class cpp17_input_iterator
;
76 typedef std::input_iterator_tag iterator_category
;
77 typedef typename
Traits::value_type value_type
;
78 typedef typename
Traits::difference_type difference_type
;
80 typedef typename
Traits::reference reference
;
82 TEST_CONSTEXPR
explicit cpp17_input_iterator(It it
) : it_(it
) {}
84 template <class U
, class T
>
85 TEST_CONSTEXPR
cpp17_input_iterator(const cpp17_input_iterator
<U
, T
>& u
) : it_(u
.it_
) {}
87 template <class U
, class T
, class = typename
std::enable_if
<std::is_default_constructible
<U
>::value
>::type
>
88 TEST_CONSTEXPR_CXX14
cpp17_input_iterator(cpp17_input_iterator
<U
, T
>&& u
) : it_(u
.it_
) { u
.it_
= U(); }
90 TEST_CONSTEXPR reference
operator*() const {return *it_
;}
92 TEST_CONSTEXPR_CXX14 cpp17_input_iterator
& operator++() {++it_
; return *this;}
93 TEST_CONSTEXPR_CXX14 cpp17_input_iterator
operator++(int) {return cpp17_input_iterator(it_
++);}
95 friend TEST_CONSTEXPR
bool operator==(const cpp17_input_iterator
& x
, const cpp17_input_iterator
& y
) {return x
.it_
== y
.it_
;}
96 friend TEST_CONSTEXPR
bool operator!=(const cpp17_input_iterator
& x
, const cpp17_input_iterator
& y
) {return x
.it_
!= y
.it_
;}
98 friend TEST_CONSTEXPR It
base(const cpp17_input_iterator
& i
) { return i
.it_
; }
101 void operator,(T
const &) = delete;
103 #if TEST_STD_VER > 14
105 cpp17_input_iterator(It
) -> cpp17_input_iterator
<It
>;
108 #if TEST_STD_VER > 17
109 static_assert(std::input_iterator
<cpp17_input_iterator
<int*>>);
113 class forward_iterator
117 template <class U
> friend class forward_iterator
;
119 typedef std::forward_iterator_tag iterator_category
;
120 typedef typename
std::iterator_traits
<It
>::value_type value_type
;
121 typedef typename
std::iterator_traits
<It
>::difference_type difference_type
;
123 typedef typename
std::iterator_traits
<It
>::reference reference
;
125 TEST_CONSTEXPR
forward_iterator() : it_() {}
126 TEST_CONSTEXPR
explicit forward_iterator(It it
) : it_(it
) {}
129 TEST_CONSTEXPR
forward_iterator(const forward_iterator
<U
>& u
) : it_(u
.it_
) {}
131 template <class U
, class = typename
std::enable_if
<std::is_default_constructible
<U
>::value
>::type
>
132 TEST_CONSTEXPR_CXX14
forward_iterator(forward_iterator
<U
>&& other
) : it_(other
.it_
) { other
.it_
= U(); }
134 TEST_CONSTEXPR reference
operator*() const {return *it_
;}
136 TEST_CONSTEXPR_CXX14 forward_iterator
& operator++() {++it_
; return *this;}
137 TEST_CONSTEXPR_CXX14 forward_iterator
operator++(int) {return forward_iterator(it_
++);}
139 friend TEST_CONSTEXPR
bool operator==(const forward_iterator
& x
, const forward_iterator
& y
) {return x
.it_
== y
.it_
;}
140 friend TEST_CONSTEXPR
bool operator!=(const forward_iterator
& x
, const forward_iterator
& y
) {return x
.it_
!= y
.it_
;}
142 friend TEST_CONSTEXPR It
base(const forward_iterator
& i
) { return i
.it_
; }
145 void operator,(T
const &) = delete;
147 #if TEST_STD_VER > 14
149 forward_iterator(It
) -> forward_iterator
<It
>;
153 class bidirectional_iterator
157 template <class U
> friend class bidirectional_iterator
;
159 typedef std::bidirectional_iterator_tag iterator_category
;
160 typedef typename
std::iterator_traits
<It
>::value_type value_type
;
161 typedef typename
std::iterator_traits
<It
>::difference_type difference_type
;
163 typedef typename
std::iterator_traits
<It
>::reference reference
;
165 TEST_CONSTEXPR
bidirectional_iterator() : it_() {}
166 TEST_CONSTEXPR
explicit bidirectional_iterator(It it
) : it_(it
) {}
169 TEST_CONSTEXPR
bidirectional_iterator(const bidirectional_iterator
<U
>& u
) : it_(u
.it_
) {}
171 template <class U
, class = typename
std::enable_if
<std::is_default_constructible
<U
>::value
>::type
>
172 TEST_CONSTEXPR_CXX14
bidirectional_iterator(bidirectional_iterator
<U
>&& u
) : it_(u
.it_
) { u
.it_
= U(); }
174 TEST_CONSTEXPR reference
operator*() const {return *it_
;}
176 TEST_CONSTEXPR_CXX14 bidirectional_iterator
& operator++() {++it_
; return *this;}
177 TEST_CONSTEXPR_CXX14 bidirectional_iterator
& operator--() {--it_
; return *this;}
178 TEST_CONSTEXPR_CXX14 bidirectional_iterator
operator++(int) {return bidirectional_iterator(it_
++);}
179 TEST_CONSTEXPR_CXX14 bidirectional_iterator
operator--(int) {return bidirectional_iterator(it_
--);}
181 friend TEST_CONSTEXPR
bool operator==(const bidirectional_iterator
& x
, const bidirectional_iterator
& y
) {return x
.it_
== y
.it_
;}
182 friend TEST_CONSTEXPR
bool operator!=(const bidirectional_iterator
& x
, const bidirectional_iterator
& y
) {return x
.it_
!= y
.it_
;}
184 friend TEST_CONSTEXPR It
base(const bidirectional_iterator
& i
) { return i
.it_
; }
187 void operator,(T
const &) = delete;
189 #if TEST_STD_VER > 14
191 bidirectional_iterator(It
) -> bidirectional_iterator
<It
>;
195 class random_access_iterator
199 template <class U
> friend class random_access_iterator
;
201 typedef std::random_access_iterator_tag iterator_category
;
202 typedef typename
std::iterator_traits
<It
>::value_type value_type
;
203 typedef typename
std::iterator_traits
<It
>::difference_type difference_type
;
205 typedef typename
std::iterator_traits
<It
>::reference reference
;
207 TEST_CONSTEXPR
random_access_iterator() : it_() {}
208 TEST_CONSTEXPR
explicit random_access_iterator(It it
) : it_(it
) {}
211 TEST_CONSTEXPR
random_access_iterator(const random_access_iterator
<U
>& u
) : it_(u
.it_
) {}
213 template <class U
, class = typename
std::enable_if
<std::is_default_constructible
<U
>::value
>::type
>
214 TEST_CONSTEXPR_CXX14
random_access_iterator(random_access_iterator
<U
>&& u
) : it_(u
.it_
) { u
.it_
= U(); }
216 TEST_CONSTEXPR_CXX14 reference
operator*() const {return *it_
;}
217 TEST_CONSTEXPR_CXX14 reference
operator[](difference_type n
) const {return it_
[n
];}
219 TEST_CONSTEXPR_CXX14 random_access_iterator
& operator++() {++it_
; return *this;}
220 TEST_CONSTEXPR_CXX14 random_access_iterator
& operator--() {--it_
; return *this;}
221 TEST_CONSTEXPR_CXX14 random_access_iterator
operator++(int) {return random_access_iterator(it_
++);}
222 TEST_CONSTEXPR_CXX14 random_access_iterator
operator--(int) {return random_access_iterator(it_
--);}
224 TEST_CONSTEXPR_CXX14 random_access_iterator
& operator+=(difference_type n
) {it_
+= n
; return *this;}
225 TEST_CONSTEXPR_CXX14 random_access_iterator
& operator-=(difference_type n
) {it_
-= n
; return *this;}
226 friend TEST_CONSTEXPR_CXX14 random_access_iterator
operator+(random_access_iterator x
, difference_type n
) {x
+= n
; return x
;}
227 friend TEST_CONSTEXPR_CXX14 random_access_iterator
operator+(difference_type n
, random_access_iterator x
) {x
+= n
; return x
;}
228 friend TEST_CONSTEXPR_CXX14 random_access_iterator
operator-(random_access_iterator x
, difference_type n
) {x
-= n
; return x
;}
229 friend TEST_CONSTEXPR difference_type
operator-(random_access_iterator x
, random_access_iterator y
) {return x
.it_
- y
.it_
;}
231 friend TEST_CONSTEXPR
bool operator==(const random_access_iterator
& x
, const random_access_iterator
& y
) {return x
.it_
== y
.it_
;}
232 friend TEST_CONSTEXPR
bool operator!=(const random_access_iterator
& x
, const random_access_iterator
& y
) {return x
.it_
!= y
.it_
;}
233 friend TEST_CONSTEXPR
bool operator< (const random_access_iterator
& x
, const random_access_iterator
& y
) {return x
.it_
< y
.it_
;}
234 friend TEST_CONSTEXPR
bool operator<=(const random_access_iterator
& x
, const random_access_iterator
& y
) {return x
.it_
<= y
.it_
;}
235 friend TEST_CONSTEXPR
bool operator> (const random_access_iterator
& x
, const random_access_iterator
& y
) {return x
.it_
> y
.it_
;}
236 friend TEST_CONSTEXPR
bool operator>=(const random_access_iterator
& x
, const random_access_iterator
& y
) {return x
.it_
>= y
.it_
;}
238 friend TEST_CONSTEXPR It
base(const random_access_iterator
& i
) { return i
.it_
; }
241 void operator,(T
const &) = delete;
243 #if TEST_STD_VER > 14
245 random_access_iterator(It
) -> random_access_iterator
<It
>;
248 #if TEST_STD_VER > 17
250 template <std::random_access_iterator It
>
251 class cpp20_random_access_iterator
{
254 template <std::random_access_iterator
>
255 friend class cpp20_random_access_iterator
;
258 using iterator_category
= std::input_iterator_tag
;
259 using iterator_concept
= std::random_access_iterator_tag
;
260 using value_type
= typename
std::iterator_traits
<It
>::value_type
;
261 using difference_type
= typename
std::iterator_traits
<It
>::difference_type
;
263 constexpr cpp20_random_access_iterator() : it_() {}
264 constexpr explicit cpp20_random_access_iterator(It it
) : it_(it
) {}
267 constexpr cpp20_random_access_iterator(const cpp20_random_access_iterator
<U
>& u
) : it_(u
.it_
) {}
270 constexpr cpp20_random_access_iterator(cpp20_random_access_iterator
<U
>&& u
) : it_(u
.it_
) {
274 constexpr decltype(auto) operator*() const { return *it_
; }
275 constexpr decltype(auto) operator[](difference_type n
) const { return it_
[n
]; }
277 constexpr cpp20_random_access_iterator
& operator++() {
281 constexpr cpp20_random_access_iterator
& operator--() {
285 constexpr cpp20_random_access_iterator
operator++(int) { return cpp20_random_access_iterator(it_
++); }
286 constexpr cpp20_random_access_iterator
operator--(int) { return cpp20_random_access_iterator(it_
--); }
288 constexpr cpp20_random_access_iterator
& operator+=(difference_type n
) {
292 constexpr cpp20_random_access_iterator
& operator-=(difference_type n
) {
296 friend constexpr cpp20_random_access_iterator
operator+(cpp20_random_access_iterator x
, difference_type n
) {
300 friend constexpr cpp20_random_access_iterator
operator+(difference_type n
, cpp20_random_access_iterator x
) {
304 friend constexpr cpp20_random_access_iterator
operator-(cpp20_random_access_iterator x
, difference_type n
) {
308 friend constexpr difference_type
operator-(cpp20_random_access_iterator x
, cpp20_random_access_iterator y
) {
309 return x
.it_
- y
.it_
;
312 friend constexpr bool operator==(const cpp20_random_access_iterator
& x
, const cpp20_random_access_iterator
& y
) {
313 return x
.it_
== y
.it_
;
315 friend constexpr bool operator!=(const cpp20_random_access_iterator
& x
, const cpp20_random_access_iterator
& y
) {
316 return x
.it_
!= y
.it_
;
318 friend constexpr bool operator<(const cpp20_random_access_iterator
& x
, const cpp20_random_access_iterator
& y
) {
319 return x
.it_
< y
.it_
;
321 friend constexpr bool operator<=(const cpp20_random_access_iterator
& x
, const cpp20_random_access_iterator
& y
) {
322 return x
.it_
<= y
.it_
;
324 friend constexpr bool operator>(const cpp20_random_access_iterator
& x
, const cpp20_random_access_iterator
& y
) {
325 return x
.it_
> y
.it_
;
327 friend constexpr bool operator>=(const cpp20_random_access_iterator
& x
, const cpp20_random_access_iterator
& y
) {
328 return x
.it_
>= y
.it_
;
331 friend constexpr It
base(const cpp20_random_access_iterator
& i
) { return i
.it_
; }
334 void operator,(T
const&) = delete;
337 cpp20_random_access_iterator(It
) -> cpp20_random_access_iterator
<It
>;
339 static_assert(std::random_access_iterator
<cpp20_random_access_iterator
<int*>>);
342 class contiguous_iterator
344 static_assert(std::is_pointer_v
<It
>, "Things probably break in this case");
348 template <class U
> friend class contiguous_iterator
;
350 typedef std::contiguous_iterator_tag iterator_category
;
351 typedef typename
std::iterator_traits
<It
>::value_type value_type
;
352 typedef typename
std::iterator_traits
<It
>::difference_type difference_type
;
354 typedef typename
std::iterator_traits
<It
>::reference reference
;
355 typedef typename
std::remove_pointer
<It
>::type element_type
;
357 TEST_CONSTEXPR_CXX14 It
base() const {return it_
;}
359 TEST_CONSTEXPR_CXX14
contiguous_iterator() : it_() {}
360 TEST_CONSTEXPR_CXX14
explicit contiguous_iterator(It it
) : it_(it
) {}
363 TEST_CONSTEXPR_CXX14
contiguous_iterator(const contiguous_iterator
<U
>& u
) : it_(u
.it_
) {}
365 template <class U
, class = typename
std::enable_if
<std::is_default_constructible
<U
>::value
>::type
>
366 constexpr contiguous_iterator(contiguous_iterator
<U
>&& u
) : it_(u
.it_
) { u
.it_
= U(); }
368 TEST_CONSTEXPR reference
operator*() const {return *it_
;}
369 TEST_CONSTEXPR pointer
operator->() const {return it_
;}
370 TEST_CONSTEXPR reference
operator[](difference_type n
) const {return it_
[n
];}
372 TEST_CONSTEXPR_CXX14 contiguous_iterator
& operator++() {++it_
; return *this;}
373 TEST_CONSTEXPR_CXX14 contiguous_iterator
& operator--() {--it_
; return *this;}
374 TEST_CONSTEXPR_CXX14 contiguous_iterator
operator++(int) {return contiguous_iterator(it_
++);}
375 TEST_CONSTEXPR_CXX14 contiguous_iterator
operator--(int) {return contiguous_iterator(it_
--);}
377 TEST_CONSTEXPR_CXX14 contiguous_iterator
& operator+=(difference_type n
) {it_
+= n
; return *this;}
378 TEST_CONSTEXPR_CXX14 contiguous_iterator
& operator-=(difference_type n
) {it_
-= n
; return *this;}
379 friend TEST_CONSTEXPR_CXX14 contiguous_iterator
operator+(contiguous_iterator x
, difference_type n
) {x
+= n
; return x
;}
380 friend TEST_CONSTEXPR_CXX14 contiguous_iterator
operator+(difference_type n
, contiguous_iterator x
) {x
+= n
; return x
;}
381 friend TEST_CONSTEXPR_CXX14 contiguous_iterator
operator-(contiguous_iterator x
, difference_type n
) {x
-= n
; return x
;}
382 friend TEST_CONSTEXPR difference_type
operator-(contiguous_iterator x
, contiguous_iterator y
) {return x
.it_
- y
.it_
;}
384 friend TEST_CONSTEXPR
bool operator==(const contiguous_iterator
& x
, const contiguous_iterator
& y
) {return x
.it_
== y
.it_
;}
385 friend TEST_CONSTEXPR
bool operator!=(const contiguous_iterator
& x
, const contiguous_iterator
& y
) {return x
.it_
!= y
.it_
;}
386 friend TEST_CONSTEXPR
bool operator< (const contiguous_iterator
& x
, const contiguous_iterator
& y
) {return x
.it_
< y
.it_
;}
387 friend TEST_CONSTEXPR
bool operator<=(const contiguous_iterator
& x
, const contiguous_iterator
& y
) {return x
.it_
<= y
.it_
;}
388 friend TEST_CONSTEXPR
bool operator> (const contiguous_iterator
& x
, const contiguous_iterator
& y
) {return x
.it_
> y
.it_
;}
389 friend TEST_CONSTEXPR
bool operator>=(const contiguous_iterator
& x
, const contiguous_iterator
& y
) {return x
.it_
>= y
.it_
;}
391 friend TEST_CONSTEXPR It
base(const contiguous_iterator
& i
) { return i
.it_
; }
394 void operator,(T
const &) = delete;
397 contiguous_iterator(It
) -> contiguous_iterator
<It
>;
400 class three_way_contiguous_iterator
402 static_assert(std::is_pointer_v
<It
>, "Things probably break in this case");
406 template <class U
> friend class three_way_contiguous_iterator
;
408 typedef std::contiguous_iterator_tag iterator_category
;
409 typedef typename
std::iterator_traits
<It
>::value_type value_type
;
410 typedef typename
std::iterator_traits
<It
>::difference_type difference_type
;
412 typedef typename
std::iterator_traits
<It
>::reference reference
;
413 typedef typename
std::remove_pointer
<It
>::type element_type
;
415 constexpr It
base() const {return it_
;}
417 constexpr three_way_contiguous_iterator() : it_() {}
418 constexpr explicit three_way_contiguous_iterator(It it
) : it_(it
) {}
421 constexpr three_way_contiguous_iterator(const three_way_contiguous_iterator
<U
>& u
) : it_(u
.it_
) {}
423 template <class U
, class = typename
std::enable_if
<std::is_default_constructible
<U
>::value
>::type
>
424 constexpr three_way_contiguous_iterator(three_way_contiguous_iterator
<U
>&& u
) : it_(u
.it_
) { u
.it_
= U(); }
426 constexpr reference
operator*() const {return *it_
;}
427 constexpr pointer
operator->() const {return it_
;}
428 constexpr reference
operator[](difference_type n
) const {return it_
[n
];}
430 constexpr three_way_contiguous_iterator
& operator++() {++it_
; return *this;}
431 constexpr three_way_contiguous_iterator
& operator--() {--it_
; return *this;}
432 constexpr three_way_contiguous_iterator
operator++(int) {return three_way_contiguous_iterator(it_
++);}
433 constexpr three_way_contiguous_iterator
operator--(int) {return three_way_contiguous_iterator(it_
--);}
435 constexpr three_way_contiguous_iterator
& operator+=(difference_type n
) {it_
+= n
; return *this;}
436 constexpr three_way_contiguous_iterator
& operator-=(difference_type n
) {it_
-= n
; return *this;}
437 friend constexpr three_way_contiguous_iterator
operator+(three_way_contiguous_iterator x
, difference_type n
) {x
+= n
; return x
;}
438 friend constexpr three_way_contiguous_iterator
operator+(difference_type n
, three_way_contiguous_iterator x
) {x
+= n
; return x
;}
439 friend constexpr three_way_contiguous_iterator
operator-(three_way_contiguous_iterator x
, difference_type n
) {x
-= n
; return x
;}
440 friend constexpr difference_type
operator-(three_way_contiguous_iterator x
, three_way_contiguous_iterator y
) {return x
.it_
- y
.it_
;}
442 friend constexpr auto operator<=>(const three_way_contiguous_iterator
& x
, const three_way_contiguous_iterator
& y
) {return x
.it_
<=> y
.it_
;}
443 friend constexpr bool operator==(const three_way_contiguous_iterator
& x
, const three_way_contiguous_iterator
& y
) {return x
.it_
== y
.it_
;}
446 void operator,(T
const &) = delete;
449 three_way_contiguous_iterator(It
) -> three_way_contiguous_iterator
<It
>;
450 #endif // TEST_STD_VER > 17
452 template <class Iter
> // ADL base() for everything else (including pointers)
453 TEST_CONSTEXPR Iter
base(Iter i
) { return i
; }
455 template <typename T
>
456 struct ThrowingIterator
{
457 typedef std::bidirectional_iterator_tag iterator_category
;
458 typedef std::ptrdiff_t difference_type
;
459 typedef const T value_type
;
460 typedef const T
* pointer
;
461 typedef const T
& reference
;
463 enum ThrowingAction
{ TAIncrement
, TADecrement
, TADereference
, TAAssignment
, TAComparison
};
465 TEST_CONSTEXPR
ThrowingIterator()
466 : begin_(nullptr), end_(nullptr), current_(nullptr), action_(TADereference
), index_(0) {}
467 TEST_CONSTEXPR
explicit ThrowingIterator(const T
* first
, const T
* last
, int index
= 0,
468 ThrowingAction action
= TADereference
)
469 : begin_(first
), end_(last
), current_(first
), action_(action
), index_(index
) {}
470 TEST_CONSTEXPR
ThrowingIterator(const ThrowingIterator
&rhs
)
471 : begin_(rhs
.begin_
), end_(rhs
.end_
), current_(rhs
.current_
), action_(rhs
.action_
), index_(rhs
.index_
) {}
473 TEST_CONSTEXPR_CXX14 ThrowingIterator
& operator=(const ThrowingIterator
& rhs
) {
474 if (action_
== TAAssignment
&& --index_
< 0) {
475 #ifndef TEST_HAS_NO_EXCEPTIONS
476 throw std::runtime_error("throw from iterator assignment");
483 current_
= rhs
.current_
;
484 action_
= rhs
.action_
;
489 TEST_CONSTEXPR_CXX14 reference
operator*() const {
490 if (action_
== TADereference
&& --index_
< 0) {
491 #ifndef TEST_HAS_NO_EXCEPTIONS
492 throw std::runtime_error("throw from iterator dereference");
500 TEST_CONSTEXPR_CXX14 ThrowingIterator
& operator++() {
501 if (action_
== TAIncrement
&& --index_
< 0) {
502 #ifndef TEST_HAS_NO_EXCEPTIONS
503 throw std::runtime_error("throw from iterator increment");
512 TEST_CONSTEXPR_CXX14 ThrowingIterator
operator++(int) {
513 ThrowingIterator temp
= *this;
518 TEST_CONSTEXPR_CXX14 ThrowingIterator
& operator--() {
519 if (action_
== TADecrement
&& --index_
< 0) {
520 #ifndef TEST_HAS_NO_EXCEPTIONS
521 throw std::runtime_error("throw from iterator decrement");
530 TEST_CONSTEXPR_CXX14 ThrowingIterator
operator--(int) {
531 ThrowingIterator temp
= *this;
536 TEST_CONSTEXPR_CXX14
friend bool operator==(const ThrowingIterator
& a
, const ThrowingIterator
& b
) {
537 if (a
.action_
== TAComparison
&& --a
.index_
< 0) {
538 #ifndef TEST_HAS_NO_EXCEPTIONS
539 throw std::runtime_error("throw from iterator comparison");
544 bool atEndL
= a
.current_
== a
.end_
;
545 bool atEndR
= b
.current_
== b
.end_
;
546 if (atEndL
!= atEndR
) return false; // one is at the end (or empty), the other is not.
547 if (atEndL
) return true; // both are at the end (or empty)
548 return a
.current_
== b
.current_
;
551 TEST_CONSTEXPR
friend bool operator!=(const ThrowingIterator
& a
, const ThrowingIterator
& b
) {
556 void operator,(T2
const &) = delete;
562 ThrowingAction action_
;
566 template <typename T
>
567 struct NonThrowingIterator
{
568 typedef std::bidirectional_iterator_tag iterator_category
;
569 typedef std::ptrdiff_t difference_type
;
570 typedef const T value_type
;
571 typedef const T
* pointer
;
572 typedef const T
& reference
;
574 NonThrowingIterator()
575 : begin_(nullptr), end_(nullptr), current_(nullptr) {}
576 explicit NonThrowingIterator(const T
*first
, const T
*last
)
577 : begin_(first
), end_(last
), current_(first
) {}
578 NonThrowingIterator(const NonThrowingIterator
& rhs
)
579 : begin_(rhs
.begin_
), end_(rhs
.end_
), current_(rhs
.current_
) {}
581 NonThrowingIterator
& operator=(const NonThrowingIterator
& rhs
) TEST_NOEXCEPT
{
584 current_
= rhs
.current_
;
588 reference
operator*() const TEST_NOEXCEPT
{
592 NonThrowingIterator
& operator++() TEST_NOEXCEPT
{
597 NonThrowingIterator
operator++(int) TEST_NOEXCEPT
{
598 NonThrowingIterator temp
= *this;
603 NonThrowingIterator
& operator--() TEST_NOEXCEPT
{
608 NonThrowingIterator
operator--(int) TEST_NOEXCEPT
{
609 NonThrowingIterator temp
= *this;
614 friend bool operator==(const NonThrowingIterator
& a
, const NonThrowingIterator
& b
) TEST_NOEXCEPT
{
615 bool atEndL
= a
.current_
== a
.end_
;
616 bool atEndR
= b
.current_
== b
.end_
;
617 if (atEndL
!= atEndR
) return false; // one is at the end (or empty), the other is not.
618 if (atEndL
) return true; // both are at the end (or empty)
619 return a
.current_
== b
.current_
;
622 friend bool operator!=(const NonThrowingIterator
& a
, const NonThrowingIterator
& b
) TEST_NOEXCEPT
{
627 void operator,(T2
const &) = delete;
635 #if TEST_STD_VER > 17
638 class cpp20_input_iterator
643 using value_type
= std::iter_value_t
<It
>;
644 using difference_type
= std::iter_difference_t
<It
>;
645 using iterator_concept
= std::input_iterator_tag
;
647 constexpr explicit cpp20_input_iterator(It it
) : it_(it
) {}
648 cpp20_input_iterator(cpp20_input_iterator
&&) = default;
649 cpp20_input_iterator
& operator=(cpp20_input_iterator
&&) = default;
650 constexpr decltype(auto) operator*() const { return *it_
; }
651 constexpr cpp20_input_iterator
& operator++() { ++it_
; return *this; }
652 constexpr void operator++(int) { ++it_
; }
654 friend constexpr It
base(const cpp20_input_iterator
& i
) { return i
.it_
; }
657 void operator,(T
const &) = delete;
660 cpp20_input_iterator(It
) -> cpp20_input_iterator
<It
>;
662 static_assert(std::input_iterator
<cpp20_input_iterator
<int*>>);
664 template<std::input_or_output_iterator
>
665 struct iter_value_or_void
{ using type
= void; };
667 template<std::input_iterator I
>
668 struct iter_value_or_void
<I
> {
669 using type
= std::iter_value_t
<I
>;
673 class cpp20_output_iterator
{
677 using difference_type
= std::iter_difference_t
<It
>;
679 constexpr explicit cpp20_output_iterator(It it
) : it_(it
) {}
680 cpp20_output_iterator(cpp20_output_iterator
&&) = default;
681 cpp20_output_iterator
& operator=(cpp20_output_iterator
&&) = default;
683 constexpr decltype(auto) operator*() const { return *it_
; }
684 constexpr cpp20_output_iterator
& operator++() {
688 constexpr cpp20_output_iterator
operator++(int) { return cpp20_output_iterator(it_
++); }
690 friend constexpr It
base(const cpp20_output_iterator
& i
) { return i
.it_
; }
693 void operator,(T
const&) = delete;
696 cpp20_output_iterator(It
) -> cpp20_output_iterator
<It
>;
698 static_assert(std::output_iterator
<cpp20_output_iterator
<int*>, int>);
700 # if TEST_STD_VER >= 20
702 // An `input_iterator` that can be used in a `std::ranges::common_range`
703 template <class Base
>
704 struct common_input_iterator
{
707 using value_type
= std::iter_value_t
<Base
>;
708 using difference_type
= std::intptr_t;
709 using iterator_concept
= std::input_iterator_tag
;
711 constexpr common_input_iterator() = default;
712 constexpr explicit common_input_iterator(Base it
) : it_(it
) {}
714 constexpr common_input_iterator
& operator++() {
718 constexpr void operator++(int) { ++it_
; }
720 constexpr decltype(auto) operator*() const { return *it_
; }
722 friend constexpr bool operator==(common_input_iterator
const&, common_input_iterator
const&) = default;
725 # endif // TEST_STD_VER >= 20
727 // Iterator adaptor that counts the number of times the iterator has had a successor/predecessor
728 // operation called. Has two recorders:
729 // * `stride_count`, which records the total number of calls to an op++, op--, op+=, or op-=.
730 // * `stride_displacement`, which records the displacement of the calls. This means that both
731 // op++/op+= will increase the displacement counter by 1, and op--/op-= will decrease the
732 // displacement counter by 1.
734 class stride_counting_iterator
{
736 using value_type
= typename iter_value_or_void
<It
>::type
;
737 using difference_type
= std::iter_difference_t
<It
>;
738 using iterator_concept
=
739 std::conditional_t
<std::contiguous_iterator
<It
>, std::contiguous_iterator_tag
,
740 std::conditional_t
<std::random_access_iterator
<It
>, std::random_access_iterator_tag
,
741 std::conditional_t
<std::bidirectional_iterator
<It
>, std::bidirectional_iterator_tag
,
742 std::conditional_t
<std::forward_iterator
<It
>, std::forward_iterator_tag
,
743 std::conditional_t
<std::input_iterator
<It
>, std::input_iterator_tag
,
744 /* else */ std::output_iterator_tag
747 stride_counting_iterator() requires
std::default_initializable
<It
> = default;
749 constexpr explicit stride_counting_iterator(It
const& it
) : base_(base(it
)) { }
751 friend constexpr It
base(stride_counting_iterator
const& it
) { return It(it
.base_
); }
753 constexpr difference_type
stride_count() const { return stride_count_
; }
755 constexpr difference_type
stride_displacement() const { return stride_displacement_
; }
757 constexpr decltype(auto) operator*() const { return *It(base_
); }
759 constexpr decltype(auto) operator[](difference_type n
) const { return It(base_
)[n
]; }
761 constexpr stride_counting_iterator
& operator++() {
765 ++stride_displacement_
;
769 constexpr void operator++(int) { ++*this; }
771 constexpr stride_counting_iterator
operator++(int)
772 requires
std::forward_iterator
<It
>
779 constexpr stride_counting_iterator
& operator--()
780 requires
std::bidirectional_iterator
<It
>
785 --stride_displacement_
;
789 constexpr stride_counting_iterator
operator--(int)
790 requires
std::bidirectional_iterator
<It
>
797 constexpr stride_counting_iterator
& operator+=(difference_type
const n
)
798 requires
std::random_access_iterator
<It
>
801 base_
= base(tmp
+= n
);
803 ++stride_displacement_
;
807 constexpr stride_counting_iterator
& operator-=(difference_type
const n
)
808 requires
std::random_access_iterator
<It
>
811 base_
= base(tmp
-= n
);
813 --stride_displacement_
;
817 friend constexpr stride_counting_iterator
operator+(stride_counting_iterator it
, difference_type n
)
818 requires
std::random_access_iterator
<It
>
823 friend constexpr stride_counting_iterator
operator+(difference_type n
, stride_counting_iterator it
)
824 requires
std::random_access_iterator
<It
>
829 friend constexpr stride_counting_iterator
operator-(stride_counting_iterator it
, difference_type n
)
830 requires
std::random_access_iterator
<It
>
835 friend constexpr difference_type
operator-(stride_counting_iterator
const& x
, stride_counting_iterator
const& y
)
836 requires
std::sized_sentinel_for
<It
, It
>
838 return base(x
) - base(y
);
841 constexpr bool operator==(stride_counting_iterator
const& other
) const
842 requires
std::sentinel_for
<It
, It
>
844 return It(base_
) == It(other
.base_
);
847 friend constexpr bool operator<(stride_counting_iterator
const& x
, stride_counting_iterator
const& y
)
848 requires
std::random_access_iterator
<It
>
850 return It(x
.base_
) < It(y
.base_
);
853 friend constexpr bool operator>(stride_counting_iterator
const& x
, stride_counting_iterator
const& y
)
854 requires
std::random_access_iterator
<It
>
856 return It(x
.base_
) > It(y
.base_
);
859 friend constexpr bool operator<=(stride_counting_iterator
const& x
, stride_counting_iterator
const& y
)
860 requires
std::random_access_iterator
<It
>
862 return It(x
.base_
) <= It(y
.base_
);
865 friend constexpr bool operator>=(stride_counting_iterator
const& x
, stride_counting_iterator
const& y
)
866 requires
std::random_access_iterator
<It
>
868 return It(x
.base_
) >= It(y
.base_
);
872 void operator,(T
const &) = delete;
875 decltype(base(std::declval
<It
>())) base_
;
876 difference_type stride_count_
= 0;
877 difference_type stride_displacement_
= 0;
880 stride_counting_iterator(It
) -> stride_counting_iterator
<It
>;
882 #endif // TEST_STD_VER > 17
884 #if TEST_STD_VER > 17
886 class sentinel_wrapper
{
888 explicit sentinel_wrapper() = default;
889 constexpr explicit sentinel_wrapper(const It
& it
) : base_(base(it
)) {}
890 constexpr bool operator==(const It
& other
) const { return base_
== base(other
); }
891 friend constexpr It
base(const sentinel_wrapper
& s
) { return It(s
.base_
); }
893 decltype(base(std::declval
<It
>())) base_
;
896 sentinel_wrapper(It
) -> sentinel_wrapper
<It
>;
899 class sized_sentinel
{
901 explicit sized_sentinel() = default;
902 constexpr explicit sized_sentinel(const It
& it
) : base_(base(it
)) {}
903 constexpr bool operator==(const It
& other
) const { return base_
== base(other
); }
904 friend constexpr auto operator-(const sized_sentinel
& s
, const It
& i
) { return s
.base_
- base(i
); }
905 friend constexpr auto operator-(const It
& i
, const sized_sentinel
& s
) { return base(i
) - s
.base_
; }
906 friend constexpr It
base(const sized_sentinel
& s
) { return It(s
.base_
); }
908 decltype(base(std::declval
<It
>())) base_
;
911 sized_sentinel(It
) -> sized_sentinel
<It
>;
917 using value_type
= int;
918 using reference
= int&;
919 using difference_type
= std::ptrdiff_t;
922 value_type
* ptr_
= nullptr;
923 int* iter_moves_
= nullptr;
924 int* iter_swaps_
= nullptr;
926 constexpr Iterator(int* p
, int* iter_moves
, int* iter_swaps
)
928 , iter_moves_(iter_moves
)
929 , iter_swaps_(iter_swaps
) {}
932 constexpr Iterator() = default;
933 static constexpr Iterator
TrackMoves(int* p
, int& iter_moves
) {
934 return Iterator(p
, &iter_moves
, /*iter_swaps=*/nullptr);
936 static constexpr Iterator
TrackSwaps(int& iter_swaps
) {
937 return Iterator(/*p=*/nullptr, /*iter_moves=*/nullptr, &iter_swaps
);
939 static constexpr Iterator
TrackSwaps(int* p
, int& iter_swaps
) {
940 return Iterator(p
, /*iter_moves=*/nullptr, &iter_swaps
);
943 constexpr int iter_moves() const { assert(iter_moves_
); return *iter_moves_
; }
944 constexpr int iter_swaps() const { assert(iter_swaps_
); return *iter_swaps_
; }
946 constexpr value_type
& operator*() const { return *ptr_
; }
947 constexpr reference
operator[](difference_type n
) const { return ptr_
[n
]; }
949 friend constexpr Iterator
operator+(Iterator i
, difference_type n
) {
950 return Iterator(i
.ptr_
+ n
, i
.iter_moves_
, i
.iter_swaps_
);
952 friend constexpr Iterator
operator+(difference_type n
, Iterator i
) {
955 constexpr Iterator
operator-(difference_type n
) const {
956 return Iterator(ptr_
- n
, iter_moves_
, iter_swaps_
);
958 constexpr difference_type
operator-(Iterator rhs
) const {
959 return ptr_
- rhs
.ptr_
;
961 constexpr Iterator
& operator+=(difference_type n
) {
965 constexpr Iterator
& operator-=(difference_type n
) {
970 constexpr Iterator
& operator++() { ++ptr_
; return *this; }
971 constexpr Iterator
operator++(int) {
972 Iterator prev
= *this;
977 constexpr Iterator
& operator--() { --ptr_
; return *this; }
978 constexpr Iterator
operator--(int) {
979 Iterator prev
= *this;
984 constexpr friend void iter_swap(Iterator a
, Iterator b
) {
985 std::swap(a
.ptr_
, b
.ptr_
);
991 constexpr friend value_type
&& iter_move(Iterator iter
) {
992 if (iter
.iter_moves_
) {
993 ++(*iter
.iter_moves_
);
995 return std::move(*iter
);
998 constexpr friend bool operator==(const Iterator
& lhs
, const Iterator
& rhs
) {
999 return lhs
.ptr_
== rhs
.ptr_
;
1001 constexpr friend auto operator<=>(const Iterator
& lhs
, const Iterator
& rhs
) {
1002 return lhs
.ptr_
<=> rhs
.ptr_
;
1009 class rvalue_iterator
{
1011 using iterator_category
= std::input_iterator_tag
;
1012 using iterator_concept
= std::random_access_iterator_tag
;
1013 using difference_type
= std::ptrdiff_t;
1014 using reference
= T
&&;
1015 using value_type
= T
;
1017 rvalue_iterator() = default;
1018 constexpr rvalue_iterator(T
* it
) : it_(it
) {}
1020 constexpr reference
operator*() const { return std::move(*it_
); }
1022 constexpr rvalue_iterator
& operator++() {
1027 constexpr rvalue_iterator
operator++(int) {
1033 constexpr rvalue_iterator
& operator--() {
1038 constexpr rvalue_iterator
operator--(int) {
1044 constexpr rvalue_iterator
operator+(difference_type n
) const {
1050 constexpr friend rvalue_iterator
operator+(difference_type n
, rvalue_iterator iter
) {
1055 constexpr rvalue_iterator
operator-(difference_type n
) const {
1061 constexpr difference_type
operator-(const rvalue_iterator
& other
) const { return it_
- other
.it_
; }
1063 constexpr rvalue_iterator
& operator+=(difference_type n
) {
1068 constexpr rvalue_iterator
& operator-=(difference_type n
) {
1073 constexpr reference
operator[](difference_type n
) const { return std::move(it_
[n
]); }
1075 auto operator<=>(const rvalue_iterator
&) const noexcept
= default;
1082 rvalue_iterator(T
*) -> rvalue_iterator
<T
>;
1084 static_assert(std::random_access_iterator
<rvalue_iterator
<int*>>);
1087 // ======================================================================
1088 // Proxy that can wrap a value or a reference. It simulates C++23's tuple
1089 // but simplified to just hold one argument.
1090 // Note that unlike tuple, this class deliberately doesn't have special handling
1091 // of swap to cause a compilation error if it's used in an algorithm that relies
1092 // on plain swap instead of ranges::iter_swap.
1093 // This class is useful for testing that if algorithms support proxy iterator
1094 // properly, i.e. calling ranges::iter_swap and ranges::iter_move instead of
1095 // plain swap and std::move.
1100 inline constexpr bool IsProxy
= false;
1103 inline constexpr bool IsProxy
<Proxy
<T
>> = true;
1109 constexpr T
& getData() & { return data
; }
1111 constexpr const T
& getData() const& { return data
; }
1113 constexpr T
&& getData() && { return static_cast<T
&&>(data
); }
1115 constexpr const T
&& getData() const&& { return static_cast<const T
&&>(data
); }
1118 requires
std::constructible_from
<T
, U
&&>
1119 constexpr Proxy(U
&& u
) : data
{std::forward
<U
>(u
)} {}
1121 // This constructor covers conversion from cvref of Proxy<U>, including non-const/const versions of copy/move constructor
1122 template <class Other
>
1123 requires(IsProxy
<std::decay_t
<Other
>> && std::constructible_from
<T
, decltype(std::declval
<Other
>().getData())>)
1124 constexpr Proxy(Other
&& other
) : data
{std::forward
<Other
>(other
).getData()} {}
1126 template <class Other
>
1127 requires(IsProxy
<std::decay_t
<Other
>> && std::assignable_from
<T
&, decltype(std::declval
<Other
>().getData())>)
1128 constexpr Proxy
& operator=(Other
&& other
) {
1129 data
= std::forward
<Other
>(other
).getData();
1133 // const assignment required to make ProxyIterator model std::indirectly_writable
1134 template <class Other
>
1135 requires(IsProxy
<std::decay_t
<Other
>> && std::assignable_from
<const T
&, decltype(std::declval
<Other
>().getData())>)
1136 constexpr const Proxy
& operator=(Other
&& other
) const {
1137 data
= std::forward
<Other
>(other
).getData();
1141 // If `T` is a reference type, the implicitly-generated assignment operator will be deleted (and would take precedence
1142 // over the templated `operator=` above because it's a better match).
1143 constexpr Proxy
& operator=(const Proxy
& rhs
) {
1148 // no specialised swap function that takes const Proxy& and no specialised const member swap
1149 // Calling swap(Proxy<T>{}, Proxy<T>{}) would fail (pass prvalues)
1151 // Compare operators are defined for the convenience of the tests
1152 friend constexpr bool operator==(const Proxy
&, const Proxy
&)
1153 requires (std::equality_comparable
<T
> && !std::is_reference_v
<T
>)
1156 // Helps compare e.g. `Proxy<int>` and `Proxy<int&>`. Note that the default equality comparison operator is deleted
1157 // when `T` is a reference type.
1159 friend constexpr bool operator==(const Proxy
& lhs
, const Proxy
<U
>& rhs
)
1160 requires
std::equality_comparable_with
<std::decay_t
<T
>, std::decay_t
<U
>> {
1161 return lhs
.data
== rhs
.data
;
1164 friend constexpr auto operator<=>(const Proxy
&, const Proxy
&)
1165 requires (std::three_way_comparable
<T
> && !std::is_reference_v
<T
>)
1168 // Helps compare e.g. `Proxy<int>` and `Proxy<int&>`. Note that the default 3-way comparison operator is deleted when
1169 // `T` is a reference type.
1171 friend constexpr auto operator<=>(const Proxy
& lhs
, const Proxy
<U
>& rhs
)
1172 requires
std::three_way_comparable_with
<std::decay_t
<T
>, std::decay_t
<U
>> {
1173 return lhs
.data
<=> rhs
.data
;
1177 // This is to make ProxyIterator model `std::indirectly_readable`
1178 template <class T
, class U
, template <class> class TQual
, template <class> class UQual
>
1179 requires requires
{ typename
std::common_reference_t
<TQual
<T
>, UQual
<U
>>; }
1180 struct std::basic_common_reference
<Proxy
<T
>, Proxy
<U
>, TQual
, UQual
> {
1181 using type
= Proxy
<std::common_reference_t
<TQual
<T
>, UQual
<U
>>>;
1184 template <class T
, class U
>
1185 requires requires
{ typename
std::common_type_t
<T
, U
>; }
1186 struct std::common_type
<Proxy
<T
>, Proxy
<U
>> {
1187 using type
= Proxy
<std::common_type_t
<T
, U
>>;
1191 // ======================================================================
1192 // It wraps `Base` iterator and when dereferenced it returns a Proxy<ref>
1193 // It simulates C++23's zip_view::iterator but simplified to just wrap
1194 // one base iterator.
1195 // Note it forwards value_type, iter_move, iter_swap. e.g if the base
1196 // iterator is int*,
1197 // operator* -> Proxy<int&>
1198 // iter_value_t -> Proxy<int>
1199 // iter_move -> Proxy<int&&>
1200 template <class Base
>
1201 struct ProxyIteratorBase
{};
1203 template <class Base
>
1204 requires
std::derived_from
<
1205 typename
std::iterator_traits
<Base
>::iterator_category
,
1206 std::input_iterator_tag
>
1207 struct ProxyIteratorBase
<Base
> {
1208 using iterator_category
= std::input_iterator_tag
;
1211 template <std::input_iterator Base
>
1212 consteval
auto get_iterator_concept() {
1213 if constexpr (std::random_access_iterator
<Base
>) {
1214 return std::random_access_iterator_tag
{};
1215 } else if constexpr (std::bidirectional_iterator
<Base
>) {
1216 return std::bidirectional_iterator_tag
{};
1217 } else if constexpr (std::forward_iterator
<Base
>) {
1218 return std::forward_iterator_tag
{};
1220 return std::input_iterator_tag
{};
1224 template <std::input_iterator Base
>
1225 struct ProxyIterator
: ProxyIteratorBase
<Base
> {
1228 using iterator_concept
= decltype(get_iterator_concept
<Base
>());
1229 using value_type
= Proxy
<std::iter_value_t
<Base
>>;
1230 using difference_type
= std::iter_difference_t
<Base
>;
1233 requires
std::default_initializable
<Base
>
1236 constexpr ProxyIterator(Base base
) : base_
{std::move(base
)} {}
1239 requires
std::constructible_from
<Base
, T
&&>
1240 constexpr ProxyIterator(T
&& t
) : base_
{std::forward
<T
>(t
)} {}
1242 friend constexpr decltype(auto) base(const ProxyIterator
& p
) { return base(p
.base_
); }
1244 // Specialization of iter_move
1245 // If operator* returns Proxy<Foo&>, iter_move will return Proxy<Foo&&>
1246 // Note std::move(*it) returns Proxy<Foo&>&&, which is not what we want as
1247 // it will likely result in a copy rather than a move
1248 friend constexpr Proxy
<std::iter_rvalue_reference_t
<Base
>> iter_move(const ProxyIterator
& p
) noexcept
{
1249 return {std::ranges::iter_move(p
.base_
)};
1252 // Specialization of iter_swap
1253 // Note std::swap(*x, *y) would fail to compile as operator* returns prvalues
1254 // and std::swap takes non-const lvalue references
1255 friend constexpr void iter_swap(const ProxyIterator
& x
, const ProxyIterator
& y
) noexcept
{
1256 std::ranges::iter_swap(x
.base_
, y
.base_
);
1259 // to satisfy input_iterator
1260 constexpr Proxy
<std::iter_reference_t
<Base
>> operator*() const { return {*base_
}; }
1262 constexpr ProxyIterator
& operator++() {
1267 constexpr void operator++(int) { ++*this; }
1269 friend constexpr bool operator==(const ProxyIterator
& x
, const ProxyIterator
& y
)
1270 requires
std::equality_comparable
<Base
> {
1271 return x
.base_
== y
.base_
;
1274 // to satisfy forward_iterator
1275 constexpr ProxyIterator
operator++(int)
1276 requires
std::forward_iterator
<Base
> {
1282 // to satisfy bidirectional_iterator
1283 constexpr ProxyIterator
& operator--()
1284 requires
std::bidirectional_iterator
<Base
> {
1289 constexpr ProxyIterator
operator--(int)
1290 requires
std::bidirectional_iterator
<Base
> {
1296 // to satisfy random_access_iterator
1297 constexpr ProxyIterator
& operator+=(difference_type n
)
1298 requires
std::random_access_iterator
<Base
> {
1303 constexpr ProxyIterator
& operator-=(difference_type n
)
1304 requires
std::random_access_iterator
<Base
> {
1309 constexpr Proxy
<std::iter_reference_t
<Base
>> operator[](difference_type n
) const
1310 requires
std::random_access_iterator
<Base
> {
1314 friend constexpr bool operator<(const ProxyIterator
& x
, const ProxyIterator
& y
)
1315 requires
std::random_access_iterator
<Base
> {
1316 return x
.base_
< y
.base_
;
1319 friend constexpr bool operator>(const ProxyIterator
& x
, const ProxyIterator
& y
)
1320 requires
std::random_access_iterator
<Base
> {
1321 return x
.base_
> y
.base_
;
1324 friend constexpr bool operator<=(const ProxyIterator
& x
, const ProxyIterator
& y
)
1325 requires
std::random_access_iterator
<Base
> {
1326 return x
.base_
<= y
.base_
;
1329 friend constexpr bool operator>=(const ProxyIterator
& x
, const ProxyIterator
& y
)
1330 requires
std::random_access_iterator
<Base
> {
1331 return x
.base_
>= y
.base_
;
1334 friend constexpr auto operator<=>(const ProxyIterator
& x
, const ProxyIterator
& y
)
1335 requires(std::random_access_iterator
<Base
> && std::three_way_comparable
<Base
>) {
1336 return x
.base_
<=> y
.base_
;
1339 friend constexpr ProxyIterator
operator+(const ProxyIterator
& x
, difference_type n
)
1340 requires
std::random_access_iterator
<Base
> {
1341 return ProxyIterator
{x
.base_
+ n
};
1344 friend constexpr ProxyIterator
operator+(difference_type n
, const ProxyIterator
& x
)
1345 requires
std::random_access_iterator
<Base
> {
1346 return ProxyIterator
{n
+ x
.base_
};
1349 friend constexpr ProxyIterator
operator-(const ProxyIterator
& x
, difference_type n
)
1350 requires
std::random_access_iterator
<Base
> {
1351 return ProxyIterator
{x
.base_
- n
};
1354 friend constexpr difference_type
operator-(const ProxyIterator
& x
, const ProxyIterator
& y
)
1355 requires
std::random_access_iterator
<Base
> {
1356 return x
.base_
- y
.base_
;
1359 template <class Base
>
1360 ProxyIterator(Base
) -> ProxyIterator
<Base
>;
1362 static_assert(std::indirectly_readable
<ProxyIterator
<int*>>);
1363 static_assert(std::indirectly_writable
<ProxyIterator
<int*>, Proxy
<int>>);
1364 static_assert(std::indirectly_writable
<ProxyIterator
<int*>, Proxy
<int&>>);
1366 template <class Iter
>
1367 using Cpp20InputProxyIterator
= ProxyIterator
<cpp20_input_iterator
<Iter
>>;
1369 template <class Iter
>
1370 using ForwardProxyIterator
= ProxyIterator
<forward_iterator
<Iter
>>;
1372 template <class Iter
>
1373 using BidirectionalProxyIterator
= ProxyIterator
<bidirectional_iterator
<Iter
>>;
1375 template <class Iter
>
1376 using RandomAccessProxyIterator
= ProxyIterator
<random_access_iterator
<Iter
>>;
1378 template <class Iter
>
1379 using ContiguousProxyIterator
= ProxyIterator
<contiguous_iterator
<Iter
>>;
1381 template <class BaseSent
>
1382 struct ProxySentinel
{
1385 ProxySentinel() = default;
1386 constexpr ProxySentinel(BaseSent base
) : base_
{std::move(base
)} {}
1388 template <class Base
>
1389 requires
std::equality_comparable_with
<Base
, BaseSent
>
1390 friend constexpr bool operator==(const ProxyIterator
<Base
>& p
, const ProxySentinel
& sent
) {
1391 return p
.base_
== sent
.base_
;
1394 template <class BaseSent
>
1395 ProxySentinel(BaseSent
) -> ProxySentinel
<BaseSent
>;
1397 template <std::ranges::input_range Base
>
1398 requires
std::ranges::view
<Base
>
1402 constexpr auto begin() { return ProxyIterator
{std::ranges::begin(base_
)}; }
1404 constexpr auto end() { return ProxySentinel
{std::ranges::end(base_
)}; }
1406 constexpr auto begin() const
1407 requires
std::ranges::input_range
<const Base
> {
1408 return ProxyIterator
{std::ranges::begin(base_
)};
1411 constexpr auto end() const
1412 requires
std::ranges::input_range
<const Base
> {
1413 return ProxySentinel
{std::ranges::end(base_
)};
1417 template <std::ranges::input_range R
>
1418 requires
std::ranges::viewable_range
<R
&&>
1419 ProxyRange(R
&&) -> ProxyRange
<std::views::all_t
<R
&&>>;
1421 #endif // TEST_STD_VER > 17
1423 #if TEST_STD_VER >= 17
1426 template <class Derived
, class Iter
>
1427 class iterator_wrapper
{
1430 using iter_traits
= std::iterator_traits
<Iter
>;
1433 using iterator_category
= typename
iter_traits::iterator_category
;
1434 using value_type
= typename
iter_traits::value_type
;
1435 using difference_type
= typename
iter_traits::difference_type
;
1436 using pointer
= typename
iter_traits::pointer
;
1437 using reference
= typename
iter_traits::reference
;
1439 constexpr iterator_wrapper() : iter_() {}
1440 constexpr explicit iterator_wrapper(Iter iter
) : iter_(iter
) {}
1442 decltype(*iter_
) operator*() { return *iter_
; }
1443 decltype(*iter_
) operator*() const { return *iter_
; }
1445 decltype(iter_
[0]) operator[](difference_type v
) const {
1449 Derived
& operator++() {
1451 return static_cast<Derived
&>(*this);
1454 Derived
operator++(int) {
1455 auto tmp
= static_cast<Derived
&>(*this);
1460 Derived
& operator--() {
1462 return static_cast<Derived
&>(*this);
1465 Derived
operator--(int) {
1466 auto tmp
= static_cast<Derived
&>(*this);
1471 iterator_wrapper
& operator+=(difference_type i
) {
1476 friend decltype(iter_
- iter_
) operator-(const iterator_wrapper
& lhs
, const iterator_wrapper
& rhs
) {
1477 return lhs
.iter_
- rhs
.iter_
;
1480 friend Derived
operator-(Derived iter
, difference_type i
) {
1485 friend Derived
operator+(Derived iter
, difference_type i
) {
1490 friend bool operator==(const iterator_wrapper
& lhs
, const iterator_wrapper
& rhs
) { return lhs
.iter_
== rhs
.iter_
; }
1491 friend bool operator!=(const iterator_wrapper
& lhs
, const iterator_wrapper
& rhs
) { return lhs
.iter_
!= rhs
.iter_
; }
1494 class iterator_error
: std::runtime_error
{
1496 iterator_error(const char* what
) : std::runtime_error(what
) {}
1499 #ifndef TEST_HAS_NO_EXCEPTIONS
1500 template <class Iter
>
1501 class throw_on_move_iterator
: public iterator_wrapper
<throw_on_move_iterator
<Iter
>, Iter
> {
1502 using base
= iterator_wrapper
<throw_on_move_iterator
<Iter
>, Iter
>;
1504 int moves_until_throw_
= 0;
1507 using difference_type
= typename
base::difference_type
;
1508 using value_type
= typename
base::value_type
;
1509 using iterator_category
= typename
base::iterator_category
;
1511 throw_on_move_iterator() = default;
1512 throw_on_move_iterator(Iter iter
, int moves_until_throw
)
1513 : base(std::move(iter
)), moves_until_throw_(moves_until_throw
) {}
1515 throw_on_move_iterator(const throw_on_move_iterator
& other
) : base(other
) {}
1516 throw_on_move_iterator
& operator=(const throw_on_move_iterator
& other
) {
1517 static_cast<base
&>(*this) = other
;
1521 throw_on_move_iterator(throw_on_move_iterator
&& other
)
1522 : base(std::move(other
)), moves_until_throw_(other
.moves_until_throw_
- 1) {
1523 if (moves_until_throw_
== -1)
1524 throw iterator_error("throw_on_move_iterator");
1527 throw_on_move_iterator
& operator=(throw_on_move_iterator
&& other
) {
1528 moves_until_throw_
= other
.moves_until_throw_
- 1;
1529 if (moves_until_throw_
== -1)
1530 throw iterator_error("throw_on_move_iterator");
1535 template <class Iter
>
1536 throw_on_move_iterator(Iter
) -> throw_on_move_iterator
<Iter
>;
1537 #endif // TEST_HAS_NO_EXCEPTIONS
1540 #endif // TEST_STD_VER >= 17
1543 template <class Ptr
>
1544 using random_access_iterator_list
=
1546 #if TEST_STD_VER >= 20
1547 contiguous_iterator
<Ptr
>,
1549 random_access_iterator
<Ptr
> >;
1551 template <class Ptr
>
1552 using bidirectional_iterator_list
=
1553 concatenate_t
<random_access_iterator_list
<Ptr
>, type_list
<bidirectional_iterator
<Ptr
> > >;
1555 template <class Ptr
>
1556 using forward_iterator_list
= concatenate_t
<bidirectional_iterator_list
<Ptr
>, type_list
<forward_iterator
<Ptr
> > >;
1558 template <class Ptr
>
1559 using cpp17_input_iterator_list
= concatenate_t
<forward_iterator_list
<Ptr
>, type_list
<cpp17_input_iterator
<Ptr
> > >;
1561 #if TEST_STD_VER >= 20
1562 template <class Ptr
>
1563 using cpp20_input_iterator_list
=
1564 concatenate_t
<forward_iterator_list
<Ptr
>, type_list
<cpp20_input_iterator
<Ptr
>, cpp17_input_iterator
<Ptr
>>>;
1566 } // namespace types
1569 #endif // SUPPORT_TEST_ITERATORS_H