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
18 #include <type_traits>
21 #include "double_move_tracker.h"
22 #include "test_macros.h"
23 #include "type_algorithms.h"
26 // This iterator meets C++20's Cpp17OutputIterator requirements, as described
27 // in Table 90 ([output.iterators]).
29 class cpp17_output_iterator
32 support::double_move_tracker tracker_
;
34 template <class U
> friend class cpp17_output_iterator
;
36 typedef std::output_iterator_tag iterator_category
;
37 typedef void value_type
;
38 typedef typename
std::iterator_traits
<It
>::difference_type difference_type
;
40 typedef typename
std::iterator_traits
<It
>::reference reference
;
42 TEST_CONSTEXPR
explicit cpp17_output_iterator(It it
) : it_(std::move(it
)) {}
45 TEST_CONSTEXPR
cpp17_output_iterator(const cpp17_output_iterator
<U
>& u
) : it_(u
.it_
), tracker_(u
.tracker_
) {}
47 template <class U
, class = typename
std::enable_if
<std::is_default_constructible
<U
>::value
>::type
>
48 TEST_CONSTEXPR_CXX14
cpp17_output_iterator(cpp17_output_iterator
<U
>&& u
)
49 : it_(std::move(u
.it_
)), tracker_(std::move(u
.tracker_
)) {
53 TEST_CONSTEXPR reference
operator*() const {return *it_
;}
55 TEST_CONSTEXPR_CXX14 cpp17_output_iterator
& operator++() {++it_
; return *this;}
56 TEST_CONSTEXPR_CXX14 cpp17_output_iterator
operator++(int) {return cpp17_output_iterator(it_
++);}
58 friend TEST_CONSTEXPR It
base(const cpp17_output_iterator
& i
) { return i
.it_
; }
61 void operator,(T
const &) = delete;
65 cpp17_output_iterator(It
) -> cpp17_output_iterator
<It
>;
69 static_assert(std::output_iterator
<cpp17_output_iterator
<int*>, int>);
72 // This iterator meets C++20's Cpp17InputIterator requirements, as described
73 // in Table 89 ([input.iterators]).
74 template <class It
, class ItTraits
= It
>
75 class cpp17_input_iterator
77 typedef std::iterator_traits
<ItTraits
> Traits
;
79 support::double_move_tracker tracker_
;
81 template <class U
, class T
> friend class cpp17_input_iterator
;
83 typedef std::input_iterator_tag iterator_category
;
84 typedef typename
Traits::value_type value_type
;
85 typedef typename
Traits::difference_type difference_type
;
87 typedef typename
Traits::reference reference
;
89 TEST_CONSTEXPR
explicit cpp17_input_iterator(It it
) : it_(it
) {}
91 template <class U
, class T
>
92 TEST_CONSTEXPR
cpp17_input_iterator(const cpp17_input_iterator
<U
, T
>& u
) : it_(u
.it_
), tracker_(u
.tracker_
) {}
94 template <class U
, class T
, class = typename
std::enable_if
<std::is_default_constructible
<U
>::value
>::type
>
95 TEST_CONSTEXPR_CXX14
cpp17_input_iterator(cpp17_input_iterator
<U
, T
>&& u
)
96 : it_(std::move(u
.it_
)), tracker_(std::move(u
.tracker_
)) {
100 TEST_CONSTEXPR reference
operator*() const {return *it_
;}
102 TEST_CONSTEXPR_CXX14 cpp17_input_iterator
& operator++() {++it_
; return *this;}
103 TEST_CONSTEXPR_CXX14 cpp17_input_iterator
operator++(int) {return cpp17_input_iterator(it_
++);}
105 friend TEST_CONSTEXPR
bool operator==(const cpp17_input_iterator
& x
, const cpp17_input_iterator
& y
) {return x
.it_
== y
.it_
;}
106 friend TEST_CONSTEXPR
bool operator!=(const cpp17_input_iterator
& x
, const cpp17_input_iterator
& y
) {return x
.it_
!= y
.it_
;}
108 friend TEST_CONSTEXPR It
base(const cpp17_input_iterator
& i
) { return i
.it_
; }
111 void operator,(T
const &) = delete;
113 #if TEST_STD_VER > 14
115 cpp17_input_iterator(It
) -> cpp17_input_iterator
<It
>;
118 #if TEST_STD_VER > 17
119 static_assert(std::input_iterator
<cpp17_input_iterator
<int*>>);
123 class forward_iterator
126 support::double_move_tracker tracker_
;
128 template <class U
> friend class forward_iterator
;
130 typedef std::forward_iterator_tag iterator_category
;
131 typedef typename
std::iterator_traits
<It
>::value_type value_type
;
132 typedef typename
std::iterator_traits
<It
>::difference_type difference_type
;
134 typedef typename
std::iterator_traits
<It
>::reference reference
;
136 TEST_CONSTEXPR
forward_iterator() : it_() {}
137 TEST_CONSTEXPR
explicit forward_iterator(It it
) : it_(it
) {}
140 TEST_CONSTEXPR
forward_iterator(const forward_iterator
<U
>& u
) : it_(u
.it_
), tracker_(u
.tracker_
) {}
142 template <class U
, class = typename
std::enable_if
<std::is_default_constructible
<U
>::value
>::type
>
143 TEST_CONSTEXPR_CXX14
forward_iterator(forward_iterator
<U
>&& other
)
144 : it_(std::move(other
.it_
)), tracker_(std::move(other
.tracker_
)) {
148 TEST_CONSTEXPR reference
operator*() const {return *it_
;}
150 TEST_CONSTEXPR_CXX14 forward_iterator
& operator++() {++it_
; return *this;}
151 TEST_CONSTEXPR_CXX14 forward_iterator
operator++(int) {return forward_iterator(it_
++);}
153 friend TEST_CONSTEXPR
bool operator==(const forward_iterator
& x
, const forward_iterator
& y
) {return x
.it_
== y
.it_
;}
154 friend TEST_CONSTEXPR
bool operator!=(const forward_iterator
& x
, const forward_iterator
& y
) {return x
.it_
!= y
.it_
;}
156 friend TEST_CONSTEXPR It
base(const forward_iterator
& i
) { return i
.it_
; }
159 void operator,(T
const &) = delete;
161 #if TEST_STD_VER > 14
163 forward_iterator(It
) -> forward_iterator
<It
>;
167 class bidirectional_iterator
170 support::double_move_tracker tracker_
;
172 template <class U
> friend class bidirectional_iterator
;
174 typedef std::bidirectional_iterator_tag iterator_category
;
175 typedef typename
std::iterator_traits
<It
>::value_type value_type
;
176 typedef typename
std::iterator_traits
<It
>::difference_type difference_type
;
178 typedef typename
std::iterator_traits
<It
>::reference reference
;
180 TEST_CONSTEXPR
bidirectional_iterator() : it_() {}
181 TEST_CONSTEXPR
explicit bidirectional_iterator(It it
) : it_(it
) {}
184 TEST_CONSTEXPR
bidirectional_iterator(const bidirectional_iterator
<U
>& u
) : it_(u
.it_
), tracker_(u
.tracker_
) {}
186 template <class U
, class = typename
std::enable_if
<std::is_default_constructible
<U
>::value
>::type
>
187 TEST_CONSTEXPR_CXX14
bidirectional_iterator(bidirectional_iterator
<U
>&& u
)
188 : it_(std::move(u
.it_
)), tracker_(std::move(u
.tracker_
)) {
192 TEST_CONSTEXPR reference
operator*() const {return *it_
;}
194 TEST_CONSTEXPR_CXX14 bidirectional_iterator
& operator++() {++it_
; return *this;}
195 TEST_CONSTEXPR_CXX14 bidirectional_iterator
& operator--() {--it_
; return *this;}
196 TEST_CONSTEXPR_CXX14 bidirectional_iterator
operator++(int) {return bidirectional_iterator(it_
++);}
197 TEST_CONSTEXPR_CXX14 bidirectional_iterator
operator--(int) {return bidirectional_iterator(it_
--);}
199 friend TEST_CONSTEXPR
bool operator==(const bidirectional_iterator
& x
, const bidirectional_iterator
& y
) {return x
.it_
== y
.it_
;}
200 friend TEST_CONSTEXPR
bool operator!=(const bidirectional_iterator
& x
, const bidirectional_iterator
& y
) {return x
.it_
!= y
.it_
;}
202 friend TEST_CONSTEXPR It
base(const bidirectional_iterator
& i
) { return i
.it_
; }
205 void operator,(T
const &) = delete;
207 #if TEST_STD_VER > 14
209 bidirectional_iterator(It
) -> bidirectional_iterator
<It
>;
213 class random_access_iterator
216 support::double_move_tracker tracker_
;
218 template <class U
> friend class random_access_iterator
;
220 typedef std::random_access_iterator_tag iterator_category
;
221 typedef typename
std::iterator_traits
<It
>::value_type value_type
;
222 typedef typename
std::iterator_traits
<It
>::difference_type difference_type
;
224 typedef typename
std::iterator_traits
<It
>::reference reference
;
226 TEST_CONSTEXPR
random_access_iterator() : it_() {}
227 TEST_CONSTEXPR
explicit random_access_iterator(It it
) : it_(it
) {}
230 TEST_CONSTEXPR
random_access_iterator(const random_access_iterator
<U
>& u
) : it_(u
.it_
), tracker_(u
.tracker_
) {}
232 template <class U
, class = typename
std::enable_if
<std::is_default_constructible
<U
>::value
>::type
>
233 TEST_CONSTEXPR_CXX14
random_access_iterator(random_access_iterator
<U
>&& u
)
234 : it_(std::move(u
.it_
)), tracker_(std::move(u
.tracker_
)) {
238 TEST_CONSTEXPR_CXX14 reference
operator*() const {return *it_
;}
239 TEST_CONSTEXPR_CXX14 reference
operator[](difference_type n
) const {return it_
[n
];}
241 TEST_CONSTEXPR_CXX14 random_access_iterator
& operator++() {++it_
; return *this;}
242 TEST_CONSTEXPR_CXX14 random_access_iterator
& operator--() {--it_
; return *this;}
243 TEST_CONSTEXPR_CXX14 random_access_iterator
operator++(int) {return random_access_iterator(it_
++);}
244 TEST_CONSTEXPR_CXX14 random_access_iterator
operator--(int) {return random_access_iterator(it_
--);}
246 TEST_CONSTEXPR_CXX14 random_access_iterator
& operator+=(difference_type n
) {it_
+= n
; return *this;}
247 TEST_CONSTEXPR_CXX14 random_access_iterator
& operator-=(difference_type n
) {it_
-= n
; return *this;}
248 friend TEST_CONSTEXPR_CXX14 random_access_iterator
operator+(random_access_iterator x
, difference_type n
) {x
+= n
; return x
;}
249 friend TEST_CONSTEXPR_CXX14 random_access_iterator
operator+(difference_type n
, random_access_iterator x
) {x
+= n
; return x
;}
250 friend TEST_CONSTEXPR_CXX14 random_access_iterator
operator-(random_access_iterator x
, difference_type n
) {x
-= n
; return x
;}
251 friend TEST_CONSTEXPR difference_type
operator-(random_access_iterator x
, random_access_iterator y
) {return x
.it_
- y
.it_
;}
253 friend TEST_CONSTEXPR
bool operator==(const random_access_iterator
& x
, const random_access_iterator
& y
) {return x
.it_
== y
.it_
;}
254 friend TEST_CONSTEXPR
bool operator!=(const random_access_iterator
& x
, const random_access_iterator
& y
) {return x
.it_
!= y
.it_
;}
255 friend TEST_CONSTEXPR
bool operator< (const random_access_iterator
& x
, const random_access_iterator
& y
) {return x
.it_
< y
.it_
;}
256 friend TEST_CONSTEXPR
bool operator<=(const random_access_iterator
& x
, const random_access_iterator
& y
) {return x
.it_
<= y
.it_
;}
257 friend TEST_CONSTEXPR
bool operator> (const random_access_iterator
& x
, const random_access_iterator
& y
) {return x
.it_
> y
.it_
;}
258 friend TEST_CONSTEXPR
bool operator>=(const random_access_iterator
& x
, const random_access_iterator
& y
) {return x
.it_
>= y
.it_
;}
260 friend TEST_CONSTEXPR It
base(const random_access_iterator
& i
) { return i
.it_
; }
263 void operator,(T
const &) = delete;
265 #if TEST_STD_VER > 14
267 random_access_iterator(It
) -> random_access_iterator
<It
>;
270 #if TEST_STD_VER > 17
272 template <std::random_access_iterator It
>
273 class cpp20_random_access_iterator
{
275 support::double_move_tracker tracker_
;
277 template <std::random_access_iterator
>
278 friend class cpp20_random_access_iterator
;
281 using iterator_category
= std::input_iterator_tag
;
282 using iterator_concept
= std::random_access_iterator_tag
;
283 using value_type
= typename
std::iterator_traits
<It
>::value_type
;
284 using difference_type
= typename
std::iterator_traits
<It
>::difference_type
;
286 constexpr cpp20_random_access_iterator() : it_() {}
287 constexpr explicit cpp20_random_access_iterator(It it
) : it_(it
) {}
290 constexpr cpp20_random_access_iterator(const cpp20_random_access_iterator
<U
>& u
) : it_(u
.it_
), tracker_(u
.tracker_
) {}
293 constexpr cpp20_random_access_iterator(cpp20_random_access_iterator
<U
>&& u
)
294 : it_(std::move(u
.it_
)), tracker_(std::move(u
.tracker_
)) {
298 constexpr decltype(auto) operator*() const { return *it_
; }
299 constexpr decltype(auto) operator[](difference_type n
) const { return it_
[n
]; }
301 constexpr cpp20_random_access_iterator
& operator++() {
305 constexpr cpp20_random_access_iterator
& operator--() {
309 constexpr cpp20_random_access_iterator
operator++(int) { return cpp20_random_access_iterator(it_
++); }
310 constexpr cpp20_random_access_iterator
operator--(int) { return cpp20_random_access_iterator(it_
--); }
312 constexpr cpp20_random_access_iterator
& operator+=(difference_type n
) {
316 constexpr cpp20_random_access_iterator
& operator-=(difference_type n
) {
320 friend constexpr cpp20_random_access_iterator
operator+(cpp20_random_access_iterator x
, difference_type n
) {
324 friend constexpr cpp20_random_access_iterator
operator+(difference_type n
, cpp20_random_access_iterator x
) {
328 friend constexpr cpp20_random_access_iterator
operator-(cpp20_random_access_iterator x
, difference_type n
) {
332 friend constexpr difference_type
operator-(cpp20_random_access_iterator x
, cpp20_random_access_iterator y
) {
333 return x
.it_
- y
.it_
;
336 friend constexpr bool operator==(const cpp20_random_access_iterator
& x
, const cpp20_random_access_iterator
& y
) {
337 return x
.it_
== y
.it_
;
339 friend constexpr bool operator!=(const cpp20_random_access_iterator
& x
, const cpp20_random_access_iterator
& y
) {
340 return x
.it_
!= y
.it_
;
342 friend constexpr bool operator<(const cpp20_random_access_iterator
& x
, const cpp20_random_access_iterator
& y
) {
343 return x
.it_
< y
.it_
;
345 friend constexpr bool operator<=(const cpp20_random_access_iterator
& x
, const cpp20_random_access_iterator
& y
) {
346 return x
.it_
<= y
.it_
;
348 friend constexpr bool operator>(const cpp20_random_access_iterator
& x
, const cpp20_random_access_iterator
& y
) {
349 return x
.it_
> y
.it_
;
351 friend constexpr bool operator>=(const cpp20_random_access_iterator
& x
, const cpp20_random_access_iterator
& y
) {
352 return x
.it_
>= y
.it_
;
355 friend constexpr It
base(const cpp20_random_access_iterator
& i
) { return i
.it_
; }
358 void operator,(T
const&) = delete;
361 cpp20_random_access_iterator(It
) -> cpp20_random_access_iterator
<It
>;
363 static_assert(std::random_access_iterator
<cpp20_random_access_iterator
<int*>>);
365 template <std::contiguous_iterator It
>
366 class contiguous_iterator
{
368 support::double_move_tracker tracker_
;
370 template <std::contiguous_iterator U
>
371 friend class contiguous_iterator
;
374 using iterator_category
= std::contiguous_iterator_tag
;
375 using value_type
= typename
std::iterator_traits
<It
>::value_type
;
376 using difference_type
= typename
std::iterator_traits
<It
>::difference_type
;
377 using pointer
= typename
std::iterator_traits
<It
>::pointer
;
378 using reference
= typename
std::iterator_traits
<It
>::reference
;
379 using element_type
= value_type
;
381 constexpr It
base() const { return it_
; }
383 constexpr contiguous_iterator() : it_() {}
384 constexpr explicit contiguous_iterator(It it
) : it_(it
) {}
387 constexpr contiguous_iterator(const contiguous_iterator
<U
>& u
) : it_(u
.it_
), tracker_(u
.tracker_
) {}
389 template <class U
, class = typename
std::enable_if
<std::is_default_constructible
<U
>::value
>::type
>
390 constexpr contiguous_iterator(contiguous_iterator
<U
>&& u
) : it_(std::move(u
.it_
)), tracker_(std::move(u
.tracker_
)) {
394 constexpr reference
operator*() const { return *it_
; }
395 constexpr pointer
operator->() const { return it_
; }
396 constexpr reference
operator[](difference_type n
) const { return it_
[n
]; }
398 constexpr contiguous_iterator
& operator++() {
402 constexpr contiguous_iterator
& operator--() {
406 constexpr contiguous_iterator
operator++(int) { return contiguous_iterator(it_
++); }
407 constexpr contiguous_iterator
operator--(int) { return contiguous_iterator(it_
--); }
409 constexpr contiguous_iterator
& operator+=(difference_type n
) {
413 constexpr contiguous_iterator
& operator-=(difference_type n
) {
417 friend constexpr contiguous_iterator
operator+(contiguous_iterator x
, difference_type n
) {
421 friend constexpr contiguous_iterator
operator+(difference_type n
, contiguous_iterator x
) {
425 friend constexpr contiguous_iterator
operator-(contiguous_iterator x
, difference_type n
) {
429 friend constexpr difference_type
operator-(contiguous_iterator x
, contiguous_iterator y
) { return x
.it_
- y
.it_
; }
431 friend constexpr bool operator==(const contiguous_iterator
& x
, const contiguous_iterator
& y
) {
432 return x
.it_
== y
.it_
;
434 friend constexpr bool operator!=(const contiguous_iterator
& x
, const contiguous_iterator
& y
) {
435 return x
.it_
!= y
.it_
;
437 friend constexpr bool operator<(const contiguous_iterator
& x
, const contiguous_iterator
& y
) { return x
.it_
< y
.it_
; }
438 friend constexpr bool operator<=(const contiguous_iterator
& x
, const contiguous_iterator
& y
) {
439 return x
.it_
<= y
.it_
;
441 friend constexpr bool operator>(const contiguous_iterator
& x
, const contiguous_iterator
& y
) { return x
.it_
> y
.it_
; }
442 friend constexpr bool operator>=(const contiguous_iterator
& x
, const contiguous_iterator
& y
) {
443 return x
.it_
>= y
.it_
;
446 // Note no operator<=>, use three_way_contiguous_iterator for testing operator<=>
448 friend constexpr It
base(const contiguous_iterator
& i
) { return i
.it_
; }
451 void operator,(T
const&) = delete;
454 contiguous_iterator(It
) -> contiguous_iterator
<It
>;
457 class three_way_contiguous_iterator
459 static_assert(std::is_pointer_v
<It
>, "Things probably break in this case");
462 support::double_move_tracker tracker_
;
464 template <class U
> friend class three_way_contiguous_iterator
;
466 typedef std::contiguous_iterator_tag iterator_category
;
467 typedef typename
std::iterator_traits
<It
>::value_type value_type
;
468 typedef typename
std::iterator_traits
<It
>::difference_type difference_type
;
470 typedef typename
std::iterator_traits
<It
>::reference reference
;
471 typedef typename
std::remove_pointer
<It
>::type element_type
;
473 constexpr It
base() const {return it_
;}
475 constexpr three_way_contiguous_iterator() : it_() {}
476 constexpr explicit three_way_contiguous_iterator(It it
) : it_(it
) {}
479 constexpr three_way_contiguous_iterator(const three_way_contiguous_iterator
<U
>& u
)
480 : it_(u
.it_
), tracker_(u
.tracker_
) {}
482 template <class U
, class = typename
std::enable_if
<std::is_default_constructible
<U
>::value
>::type
>
483 constexpr three_way_contiguous_iterator(three_way_contiguous_iterator
<U
>&& u
)
484 : it_(std::move(u
.it_
)), tracker_(std::move(u
.tracker_
)) {
488 constexpr reference
operator*() const {return *it_
;}
489 constexpr pointer
operator->() const {return it_
;}
490 constexpr reference
operator[](difference_type n
) const {return it_
[n
];}
492 constexpr three_way_contiguous_iterator
& operator++() {++it_
; return *this;}
493 constexpr three_way_contiguous_iterator
& operator--() {--it_
; return *this;}
494 constexpr three_way_contiguous_iterator
operator++(int) {return three_way_contiguous_iterator(it_
++);}
495 constexpr three_way_contiguous_iterator
operator--(int) {return three_way_contiguous_iterator(it_
--);}
497 constexpr three_way_contiguous_iterator
& operator+=(difference_type n
) {it_
+= n
; return *this;}
498 constexpr three_way_contiguous_iterator
& operator-=(difference_type n
) {it_
-= n
; return *this;}
499 friend constexpr three_way_contiguous_iterator
operator+(three_way_contiguous_iterator x
, difference_type n
) {x
+= n
; return x
;}
500 friend constexpr three_way_contiguous_iterator
operator+(difference_type n
, three_way_contiguous_iterator x
) {x
+= n
; return x
;}
501 friend constexpr three_way_contiguous_iterator
operator-(three_way_contiguous_iterator x
, difference_type n
) {x
-= n
; return x
;}
502 friend constexpr difference_type
operator-(three_way_contiguous_iterator x
, three_way_contiguous_iterator y
) {return x
.it_
- y
.it_
;}
504 friend constexpr auto operator<=>(const three_way_contiguous_iterator
& x
, const three_way_contiguous_iterator
& y
) {return x
.it_
<=> y
.it_
;}
505 friend constexpr bool operator==(const three_way_contiguous_iterator
& x
, const three_way_contiguous_iterator
& y
) {return x
.it_
== y
.it_
;}
508 void operator,(T
const &) = delete;
511 three_way_contiguous_iterator(It
) -> three_way_contiguous_iterator
<It
>;
512 #endif // TEST_STD_VER > 17
514 template <class Iter
> // ADL base() for everything else (including pointers)
515 TEST_CONSTEXPR Iter
base(Iter i
) { return i
; }
517 template <typename T
>
518 struct ThrowingIterator
{
519 typedef std::bidirectional_iterator_tag iterator_category
;
520 typedef std::ptrdiff_t difference_type
;
521 typedef const T value_type
;
522 typedef const T
* pointer
;
523 typedef const T
& reference
;
525 enum ThrowingAction
{ TAIncrement
, TADecrement
, TADereference
, TAAssignment
, TAComparison
};
527 TEST_CONSTEXPR
ThrowingIterator()
528 : begin_(nullptr), end_(nullptr), current_(nullptr), action_(TADereference
), index_(0) {}
529 TEST_CONSTEXPR
explicit ThrowingIterator(const T
* first
, const T
* last
, int index
= 0,
530 ThrowingAction action
= TADereference
)
531 : begin_(first
), end_(last
), current_(first
), action_(action
), index_(index
) {}
532 TEST_CONSTEXPR
ThrowingIterator(const ThrowingIterator
&rhs
)
533 : begin_(rhs
.begin_
), end_(rhs
.end_
), current_(rhs
.current_
), action_(rhs
.action_
), index_(rhs
.index_
) {}
535 TEST_CONSTEXPR_CXX14 ThrowingIterator
& operator=(const ThrowingIterator
& rhs
) {
536 if (action_
== TAAssignment
&& --index_
< 0) {
537 #ifndef TEST_HAS_NO_EXCEPTIONS
538 throw std::runtime_error("throw from iterator assignment");
545 current_
= rhs
.current_
;
546 action_
= rhs
.action_
;
551 TEST_CONSTEXPR_CXX14 reference
operator*() const {
552 if (action_
== TADereference
&& --index_
< 0) {
553 #ifndef TEST_HAS_NO_EXCEPTIONS
554 throw std::runtime_error("throw from iterator dereference");
562 TEST_CONSTEXPR_CXX14 ThrowingIterator
& operator++() {
563 if (action_
== TAIncrement
&& --index_
< 0) {
564 #ifndef TEST_HAS_NO_EXCEPTIONS
565 throw std::runtime_error("throw from iterator increment");
574 TEST_CONSTEXPR_CXX14 ThrowingIterator
operator++(int) {
575 ThrowingIterator temp
= *this;
580 TEST_CONSTEXPR_CXX14 ThrowingIterator
& operator--() {
581 if (action_
== TADecrement
&& --index_
< 0) {
582 #ifndef TEST_HAS_NO_EXCEPTIONS
583 throw std::runtime_error("throw from iterator decrement");
592 TEST_CONSTEXPR_CXX14 ThrowingIterator
operator--(int) {
593 ThrowingIterator temp
= *this;
598 TEST_CONSTEXPR_CXX14
friend bool operator==(const ThrowingIterator
& a
, const ThrowingIterator
& b
) {
599 if (a
.action_
== TAComparison
&& --a
.index_
< 0) {
600 #ifndef TEST_HAS_NO_EXCEPTIONS
601 throw std::runtime_error("throw from iterator comparison");
606 bool atEndL
= a
.current_
== a
.end_
;
607 bool atEndR
= b
.current_
== b
.end_
;
608 if (atEndL
!= atEndR
) return false; // one is at the end (or empty), the other is not.
609 if (atEndL
) return true; // both are at the end (or empty)
610 return a
.current_
== b
.current_
;
613 TEST_CONSTEXPR
friend bool operator!=(const ThrowingIterator
& a
, const ThrowingIterator
& b
) {
618 void operator,(T2
const &) = delete;
624 ThrowingAction action_
;
628 template <typename T
>
629 struct NonThrowingIterator
{
630 typedef std::bidirectional_iterator_tag iterator_category
;
631 typedef std::ptrdiff_t difference_type
;
632 typedef const T value_type
;
633 typedef const T
* pointer
;
634 typedef const T
& reference
;
636 NonThrowingIterator()
637 : begin_(nullptr), end_(nullptr), current_(nullptr) {}
638 explicit NonThrowingIterator(const T
*first
, const T
*last
)
639 : begin_(first
), end_(last
), current_(first
) {}
640 NonThrowingIterator(const NonThrowingIterator
& rhs
)
641 : begin_(rhs
.begin_
), end_(rhs
.end_
), current_(rhs
.current_
) {}
643 NonThrowingIterator
& operator=(const NonThrowingIterator
& rhs
) TEST_NOEXCEPT
{
646 current_
= rhs
.current_
;
650 reference
operator*() const TEST_NOEXCEPT
{
654 NonThrowingIterator
& operator++() TEST_NOEXCEPT
{
659 NonThrowingIterator
operator++(int) TEST_NOEXCEPT
{
660 NonThrowingIterator temp
= *this;
665 NonThrowingIterator
& operator--() TEST_NOEXCEPT
{
670 NonThrowingIterator
operator--(int) TEST_NOEXCEPT
{
671 NonThrowingIterator temp
= *this;
676 friend bool operator==(const NonThrowingIterator
& a
, const NonThrowingIterator
& b
) TEST_NOEXCEPT
{
677 bool atEndL
= a
.current_
== a
.end_
;
678 bool atEndR
= b
.current_
== b
.end_
;
679 if (atEndL
!= atEndR
) return false; // one is at the end (or empty), the other is not.
680 if (atEndL
) return true; // both are at the end (or empty)
681 return a
.current_
== b
.current_
;
684 friend bool operator!=(const NonThrowingIterator
& a
, const NonThrowingIterator
& b
) TEST_NOEXCEPT
{
689 void operator,(T2
const &) = delete;
697 #if TEST_STD_VER > 17
700 class cpp20_input_iterator
703 support::double_move_tracker tracker_
;
706 using value_type
= std::iter_value_t
<It
>;
707 using difference_type
= std::iter_difference_t
<It
>;
708 using iterator_concept
= std::input_iterator_tag
;
710 constexpr explicit cpp20_input_iterator(It it
) : it_(it
) {}
711 cpp20_input_iterator(cpp20_input_iterator
&&) = default;
712 cpp20_input_iterator
& operator=(cpp20_input_iterator
&&) = default;
713 constexpr decltype(auto) operator*() const { return *it_
; }
714 constexpr cpp20_input_iterator
& operator++() { ++it_
; return *this; }
715 constexpr void operator++(int) { ++it_
; }
717 friend constexpr It
base(const cpp20_input_iterator
& i
) { return i
.it_
; }
720 void operator,(T
const &) = delete;
723 cpp20_input_iterator(It
) -> cpp20_input_iterator
<It
>;
725 static_assert(std::input_iterator
<cpp20_input_iterator
<int*>>);
727 template<std::input_or_output_iterator
>
728 struct iter_value_or_void
{ using type
= void; };
730 template<std::input_iterator I
>
731 struct iter_value_or_void
<I
> {
732 using type
= std::iter_value_t
<I
>;
736 class cpp20_output_iterator
{
738 support::double_move_tracker tracker_
;
741 using difference_type
= std::iter_difference_t
<It
>;
743 constexpr explicit cpp20_output_iterator(It it
) : it_(it
) {}
744 cpp20_output_iterator(cpp20_output_iterator
&&) = default;
745 cpp20_output_iterator
& operator=(cpp20_output_iterator
&&) = default;
747 constexpr decltype(auto) operator*() const { return *it_
; }
748 constexpr cpp20_output_iterator
& operator++() {
752 constexpr cpp20_output_iterator
operator++(int) { return cpp20_output_iterator(it_
++); }
754 friend constexpr It
base(const cpp20_output_iterator
& i
) { return i
.it_
; }
757 void operator,(T
const&) = delete;
760 cpp20_output_iterator(It
) -> cpp20_output_iterator
<It
>;
762 static_assert(std::output_iterator
<cpp20_output_iterator
<int*>, int>);
764 # if TEST_STD_VER >= 20
766 // An `input_iterator` that can be used in a `std::ranges::common_range`
767 template <class Base
>
768 struct common_input_iterator
{
771 using value_type
= std::iter_value_t
<Base
>;
772 using difference_type
= std::intptr_t;
773 using iterator_concept
= std::input_iterator_tag
;
775 constexpr common_input_iterator() = default;
776 constexpr explicit common_input_iterator(Base it
) : it_(it
) {}
778 constexpr common_input_iterator
& operator++() {
782 constexpr void operator++(int) { ++it_
; }
784 constexpr decltype(auto) operator*() const { return *it_
; }
786 friend constexpr bool operator==(common_input_iterator
const&, common_input_iterator
const&) = default;
789 # endif // TEST_STD_VER >= 20
791 struct IteratorOpCounts
{
792 std::size_t increments
= 0; ///< Number of times the iterator moved forward (++it, it++, it+=positive, it-=negative).
793 std::size_t decrements
= 0; ///< Number of times the iterator moved backward (--it, it--, it-=positive, it+=negative).
794 std::size_t zero_moves
= 0; ///< Number of times a call was made to move the iterator by 0 positions (it+=0, it-=0).
795 std::size_t equal_cmps
= 0; ///< Total number of calls to op== or op!=. If compared against a sentinel object, that
796 /// sentinel object must call the `record_equality_comparison` function so that the
797 /// comparison is counted correctly.
800 // Iterator adaptor that records its operation counts in a IteratorOpCounts
802 class operation_counting_iterator
{
804 using value_type
= typename iter_value_or_void
<It
>::type
;
805 using difference_type
= std::iter_difference_t
<It
>;
806 using iterator_concept
=
807 std::conditional_t
<std::contiguous_iterator
<It
>, std::contiguous_iterator_tag
,
808 std::conditional_t
<std::random_access_iterator
<It
>, std::random_access_iterator_tag
,
809 std::conditional_t
<std::bidirectional_iterator
<It
>, std::bidirectional_iterator_tag
,
810 std::conditional_t
<std::forward_iterator
<It
>, std::forward_iterator_tag
,
811 std::conditional_t
<std::input_iterator
<It
>, std::input_iterator_tag
,
812 /* else */ std::output_iterator_tag
814 using iterator_category
= iterator_concept
;
816 operation_counting_iterator()
817 requires
std::default_initializable
<It
>
820 constexpr explicit operation_counting_iterator(It
const& it
, IteratorOpCounts
* counts
= nullptr)
821 : base_(base(it
)), counts_(counts
) {}
823 constexpr operation_counting_iterator(const operation_counting_iterator
& o
) { *this = o
; }
824 constexpr operation_counting_iterator(operation_counting_iterator
&& o
) { *this = o
; }
826 constexpr operation_counting_iterator
& operator=(const operation_counting_iterator
& o
) = default;
827 constexpr operation_counting_iterator
& operator=(operation_counting_iterator
&& o
) { return *this = o
; }
829 friend constexpr It
base(operation_counting_iterator
const& it
) { return It(it
.base_
); }
831 constexpr decltype(auto) operator*() const { return *It(base_
); }
833 constexpr decltype(auto) operator[](difference_type n
) const { return It(base_
)[n
]; }
835 constexpr operation_counting_iterator
& operator++() {
842 constexpr void operator++(int) { ++*this; }
844 constexpr operation_counting_iterator
operator++(int)
845 requires
std::forward_iterator
<It
>
852 constexpr operation_counting_iterator
& operator--()
853 requires
std::bidirectional_iterator
<It
>
861 constexpr operation_counting_iterator
operator--(int)
862 requires
std::bidirectional_iterator
<It
>
869 constexpr operation_counting_iterator
& operator+=(difference_type
const n
)
870 requires
std::random_access_iterator
<It
>
873 base_
= base(tmp
+= n
);
878 constexpr operation_counting_iterator
& operator-=(difference_type
const n
)
879 requires
std::random_access_iterator
<It
>
882 base_
= base(tmp
-= n
);
887 friend constexpr operation_counting_iterator
operator+(operation_counting_iterator it
, difference_type n
)
888 requires
std::random_access_iterator
<It
>
893 friend constexpr operation_counting_iterator
operator+(difference_type n
, operation_counting_iterator it
)
894 requires
std::random_access_iterator
<It
>
899 friend constexpr operation_counting_iterator
operator-(operation_counting_iterator it
, difference_type n
)
900 requires
std::random_access_iterator
<It
>
905 friend constexpr difference_type
906 operator-(operation_counting_iterator
const& x
, operation_counting_iterator
const& y
)
907 requires
std::sized_sentinel_for
<It
, It
>
909 return base(x
) - base(y
);
912 constexpr void record_equality_comparison() const {
913 if (counts_
!= nullptr)
914 ++counts_
->equal_cmps
;
917 constexpr bool operator==(operation_counting_iterator
const& other
) const
918 requires
std::sentinel_for
<It
, It
>
920 record_equality_comparison();
921 return It(base_
) == It(other
.base_
);
924 friend constexpr bool operator<(operation_counting_iterator
const& x
, operation_counting_iterator
const& y
)
925 requires
std::random_access_iterator
<It
>
927 return It(x
.base_
) < It(y
.base_
);
930 friend constexpr bool operator>(operation_counting_iterator
const& x
, operation_counting_iterator
const& y
)
931 requires
std::random_access_iterator
<It
>
933 return It(x
.base_
) > It(y
.base_
);
936 friend constexpr bool operator<=(operation_counting_iterator
const& x
, operation_counting_iterator
const& y
)
937 requires
std::random_access_iterator
<It
>
939 return It(x
.base_
) <= It(y
.base_
);
942 friend constexpr bool operator>=(operation_counting_iterator
const& x
, operation_counting_iterator
const& y
)
943 requires
std::random_access_iterator
<It
>
945 return It(x
.base_
) >= It(y
.base_
);
949 void operator,(T
const &) = delete;
952 constexpr void moved_by(difference_type n
) {
953 if (counts_
== nullptr)
956 ++counts_
->increments
;
958 ++counts_
->decrements
;
960 ++counts_
->zero_moves
;
963 decltype(base(std::declval
<It
>())) base_
;
964 IteratorOpCounts
* counts_
= nullptr;
967 operation_counting_iterator(It
) -> operation_counting_iterator
<It
>;
969 #endif // TEST_STD_VER > 17
971 #if TEST_STD_VER > 17
973 class sentinel_wrapper
{
975 explicit sentinel_wrapper() = default;
976 constexpr explicit sentinel_wrapper(const It
& it
) : base_(base(it
)) {}
977 constexpr bool operator==(const It
& other
) const {
978 // If supported, record statistics about the equality operator call
980 if constexpr (requires
{ other
.record_equality_comparison(); }) {
981 other
.record_equality_comparison();
983 return base_
== base(other
);
985 friend constexpr It
base(const sentinel_wrapper
& s
) { return It(s
.base_
); }
987 decltype(base(std::declval
<It
>())) base_
;
990 sentinel_wrapper(It
) -> sentinel_wrapper
<It
>;
993 class sized_sentinel
{
995 explicit sized_sentinel() = default;
996 constexpr explicit sized_sentinel(const It
& it
) : base_(base(it
)) {}
997 constexpr bool operator==(const It
& other
) const { return base_
== base(other
); }
998 friend constexpr auto operator-(const sized_sentinel
& s
, const It
& i
) { return s
.base_
- base(i
); }
999 friend constexpr auto operator-(const It
& i
, const sized_sentinel
& s
) { return base(i
) - s
.base_
; }
1000 friend constexpr It
base(const sized_sentinel
& s
) { return It(s
.base_
); }
1002 decltype(base(std::declval
<It
>())) base_
;
1005 sized_sentinel(It
) -> sized_sentinel
<It
>;
1011 using value_type
= int;
1012 using reference
= int&;
1013 using difference_type
= std::ptrdiff_t;
1016 value_type
* ptr_
= nullptr;
1017 int* iter_moves_
= nullptr;
1018 int* iter_swaps_
= nullptr;
1020 constexpr Iterator(int* p
, int* iter_moves
, int* iter_swaps
)
1022 , iter_moves_(iter_moves
)
1023 , iter_swaps_(iter_swaps
) {}
1026 constexpr Iterator() = default;
1027 static constexpr Iterator
TrackMoves(int* p
, int& iter_moves
) {
1028 return Iterator(p
, &iter_moves
, /*iter_swaps=*/nullptr);
1030 static constexpr Iterator
TrackSwaps(int& iter_swaps
) {
1031 return Iterator(/*p=*/nullptr, /*iter_moves=*/nullptr, &iter_swaps
);
1033 static constexpr Iterator
TrackSwaps(int* p
, int& iter_swaps
) {
1034 return Iterator(p
, /*iter_moves=*/nullptr, &iter_swaps
);
1037 constexpr int iter_moves() const { assert(iter_moves_
); return *iter_moves_
; }
1038 constexpr int iter_swaps() const { assert(iter_swaps_
); return *iter_swaps_
; }
1040 constexpr value_type
& operator*() const { return *ptr_
; }
1041 constexpr reference
operator[](difference_type n
) const { return ptr_
[n
]; }
1043 friend constexpr Iterator
operator+(Iterator i
, difference_type n
) {
1044 return Iterator(i
.ptr_
+ n
, i
.iter_moves_
, i
.iter_swaps_
);
1046 friend constexpr Iterator
operator+(difference_type n
, Iterator i
) {
1049 constexpr Iterator
operator-(difference_type n
) const {
1050 return Iterator(ptr_
- n
, iter_moves_
, iter_swaps_
);
1052 constexpr difference_type
operator-(Iterator rhs
) const {
1053 return ptr_
- rhs
.ptr_
;
1055 constexpr Iterator
& operator+=(difference_type n
) {
1059 constexpr Iterator
& operator-=(difference_type n
) {
1064 constexpr Iterator
& operator++() { ++ptr_
; return *this; }
1065 constexpr Iterator
operator++(int) {
1066 Iterator prev
= *this;
1071 constexpr Iterator
& operator--() { --ptr_
; return *this; }
1072 constexpr Iterator
operator--(int) {
1073 Iterator prev
= *this;
1078 constexpr friend void iter_swap(Iterator a
, Iterator b
) {
1079 std::swap(a
.ptr_
, b
.ptr_
);
1080 if (a
.iter_swaps_
) {
1085 constexpr friend value_type
&& iter_move(Iterator iter
) {
1086 if (iter
.iter_moves_
) {
1087 ++(*iter
.iter_moves_
);
1089 return std::move(*iter
);
1092 constexpr friend bool operator==(const Iterator
& lhs
, const Iterator
& rhs
) {
1093 return lhs
.ptr_
== rhs
.ptr_
;
1095 constexpr friend auto operator<=>(const Iterator
& lhs
, const Iterator
& rhs
) {
1096 return lhs
.ptr_
<=> rhs
.ptr_
;
1103 class rvalue_iterator
{
1105 using iterator_category
= std::input_iterator_tag
;
1106 using iterator_concept
= std::random_access_iterator_tag
;
1107 using difference_type
= std::ptrdiff_t;
1108 using reference
= T
&&;
1109 using value_type
= T
;
1111 rvalue_iterator() = default;
1112 constexpr rvalue_iterator(T
* it
) : it_(it
) {}
1114 constexpr reference
operator*() const { return std::move(*it_
); }
1116 constexpr rvalue_iterator
& operator++() {
1121 constexpr rvalue_iterator
operator++(int) {
1127 constexpr rvalue_iterator
& operator--() {
1132 constexpr rvalue_iterator
operator--(int) {
1138 constexpr rvalue_iterator
operator+(difference_type n
) const {
1144 constexpr friend rvalue_iterator
operator+(difference_type n
, rvalue_iterator iter
) {
1149 constexpr rvalue_iterator
operator-(difference_type n
) const {
1155 constexpr difference_type
operator-(const rvalue_iterator
& other
) const { return it_
- other
.it_
; }
1157 constexpr rvalue_iterator
& operator+=(difference_type n
) {
1162 constexpr rvalue_iterator
& operator-=(difference_type n
) {
1167 constexpr reference
operator[](difference_type n
) const { return std::move(it_
[n
]); }
1169 auto operator<=>(const rvalue_iterator
&) const noexcept
= default;
1176 rvalue_iterator(T
*) -> rvalue_iterator
<T
>;
1178 static_assert(std::random_access_iterator
<rvalue_iterator
<int*>>);
1181 // ======================================================================
1182 // Proxy that can wrap a value or a reference. It simulates C++23's tuple
1183 // but simplified to just hold one argument.
1184 // Note that unlike tuple, this class deliberately doesn't have special handling
1185 // of swap to cause a compilation error if it's used in an algorithm that relies
1186 // on plain swap instead of ranges::iter_swap.
1187 // This class is useful for testing that if algorithms support proxy iterator
1188 // properly, i.e. calling ranges::iter_swap and ranges::iter_move instead of
1189 // plain swap and std::move.
1194 inline constexpr bool IsProxy
= false;
1197 inline constexpr bool IsProxy
<Proxy
<T
>> = true;
1203 constexpr T
& getData() & { return data
; }
1205 constexpr const T
& getData() const& { return data
; }
1207 constexpr T
&& getData() && { return static_cast<T
&&>(data
); }
1209 constexpr const T
&& getData() const&& { return static_cast<const T
&&>(data
); }
1212 requires
std::constructible_from
<T
, U
&&>
1213 constexpr Proxy(U
&& u
) : data
{std::forward
<U
>(u
)} {}
1215 // This constructor covers conversion from cvref of Proxy<U>, including non-const/const versions of copy/move constructor
1216 template <class Other
>
1217 requires(IsProxy
<std::decay_t
<Other
>> && std::constructible_from
<T
, decltype(std::declval
<Other
>().getData())>)
1218 constexpr Proxy(Other
&& other
) : data
{std::forward
<Other
>(other
).getData()} {}
1220 template <class Other
>
1221 requires(IsProxy
<std::decay_t
<Other
>> && std::assignable_from
<T
&, decltype(std::declval
<Other
>().getData())>)
1222 constexpr Proxy
& operator=(Other
&& other
) {
1223 data
= std::forward
<Other
>(other
).getData();
1227 // const assignment required to make ProxyIterator model std::indirectly_writable
1228 template <class Other
>
1229 requires(IsProxy
<std::decay_t
<Other
>> && std::assignable_from
<const T
&, decltype(std::declval
<Other
>().getData())>)
1230 constexpr const Proxy
& operator=(Other
&& other
) const {
1231 data
= std::forward
<Other
>(other
).getData();
1235 // If `T` is a reference type, the implicitly-generated assignment operator will be deleted (and would take precedence
1236 // over the templated `operator=` above because it's a better match).
1237 constexpr Proxy
& operator=(const Proxy
& rhs
) {
1242 // no specialised swap function that takes const Proxy& and no specialised const member swap
1243 // Calling swap(Proxy<T>{}, Proxy<T>{}) would fail (pass prvalues)
1245 // Compare operators are defined for the convenience of the tests
1246 friend constexpr bool operator==(const Proxy
&, const Proxy
&)
1247 requires (std::equality_comparable
<T
> && !std::is_reference_v
<T
>)
1250 // Helps compare e.g. `Proxy<int>` and `Proxy<int&>`. Note that the default equality comparison operator is deleted
1251 // when `T` is a reference type.
1253 friend constexpr bool operator==(const Proxy
& lhs
, const Proxy
<U
>& rhs
)
1254 requires
std::equality_comparable_with
<std::decay_t
<T
>, std::decay_t
<U
>> {
1255 return lhs
.data
== rhs
.data
;
1258 friend constexpr auto operator<=>(const Proxy
&, const Proxy
&)
1259 requires (std::three_way_comparable
<T
> && !std::is_reference_v
<T
>)
1262 // Helps compare e.g. `Proxy<int>` and `Proxy<int&>`. Note that the default 3-way comparison operator is deleted when
1263 // `T` is a reference type.
1265 friend constexpr auto operator<=>(const Proxy
& lhs
, const Proxy
<U
>& rhs
)
1266 requires
std::three_way_comparable_with
<std::decay_t
<T
>, std::decay_t
<U
>> {
1267 return lhs
.data
<=> rhs
.data
;
1271 // This is to make ProxyIterator model `std::indirectly_readable`
1272 template <class T
, class U
, template <class> class TQual
, template <class> class UQual
>
1273 requires requires
{ typename
std::common_reference_t
<TQual
<T
>, UQual
<U
>>; }
1274 struct std::basic_common_reference
<Proxy
<T
>, Proxy
<U
>, TQual
, UQual
> {
1275 using type
= Proxy
<std::common_reference_t
<TQual
<T
>, UQual
<U
>>>;
1278 template <class T
, class U
>
1279 requires requires
{ typename
std::common_type_t
<T
, U
>; }
1280 struct std::common_type
<Proxy
<T
>, Proxy
<U
>> {
1281 using type
= Proxy
<std::common_type_t
<T
, U
>>;
1285 // ======================================================================
1286 // It wraps `Base` iterator and when dereferenced it returns a Proxy<ref>
1287 // It simulates C++23's zip_view::iterator but simplified to just wrap
1288 // one base iterator.
1289 // Note it forwards value_type, iter_move, iter_swap. e.g if the base
1290 // iterator is int*,
1291 // operator* -> Proxy<int&>
1292 // iter_value_t -> Proxy<int>
1293 // iter_move -> Proxy<int&&>
1294 template <class Base
>
1295 struct ProxyIteratorBase
{};
1297 template <class Base
>
1298 requires
std::derived_from
<
1299 typename
std::iterator_traits
<Base
>::iterator_category
,
1300 std::input_iterator_tag
>
1301 struct ProxyIteratorBase
<Base
> {
1302 using iterator_category
= std::input_iterator_tag
;
1305 template <std::input_iterator Base
>
1306 consteval
auto get_iterator_concept() {
1307 if constexpr (std::random_access_iterator
<Base
>) {
1308 return std::random_access_iterator_tag
{};
1309 } else if constexpr (std::bidirectional_iterator
<Base
>) {
1310 return std::bidirectional_iterator_tag
{};
1311 } else if constexpr (std::forward_iterator
<Base
>) {
1312 return std::forward_iterator_tag
{};
1314 return std::input_iterator_tag
{};
1318 template <std::input_iterator Base
>
1319 struct ProxyIterator
: ProxyIteratorBase
<Base
> {
1322 using iterator_concept
= decltype(get_iterator_concept
<Base
>());
1323 using value_type
= Proxy
<std::iter_value_t
<Base
>>;
1324 using difference_type
= std::iter_difference_t
<Base
>;
1327 requires
std::default_initializable
<Base
>
1330 constexpr ProxyIterator(Base base
) : base_
{std::move(base
)} {}
1333 requires
std::constructible_from
<Base
, T
&&>
1334 constexpr ProxyIterator(T
&& t
) : base_
{std::forward
<T
>(t
)} {}
1336 friend constexpr decltype(auto) base(const ProxyIterator
& p
) { return base(p
.base_
); }
1338 // Specialization of iter_move
1339 // If operator* returns Proxy<Foo&>, iter_move will return Proxy<Foo&&>
1340 // Note std::move(*it) returns Proxy<Foo&>&&, which is not what we want as
1341 // it will likely result in a copy rather than a move
1342 friend constexpr Proxy
<std::iter_rvalue_reference_t
<Base
>> iter_move(const ProxyIterator
& p
) noexcept
{
1343 return {std::ranges::iter_move(p
.base_
)};
1346 // Specialization of iter_swap
1347 // Note std::swap(*x, *y) would fail to compile as operator* returns prvalues
1348 // and std::swap takes non-const lvalue references
1349 friend constexpr void iter_swap(const ProxyIterator
& x
, const ProxyIterator
& y
) noexcept
{
1350 std::ranges::iter_swap(x
.base_
, y
.base_
);
1353 // to satisfy input_iterator
1354 constexpr Proxy
<std::iter_reference_t
<Base
>> operator*() const { return {*base_
}; }
1356 constexpr ProxyIterator
& operator++() {
1361 constexpr void operator++(int) { ++*this; }
1363 friend constexpr bool operator==(const ProxyIterator
& x
, const ProxyIterator
& y
)
1364 requires
std::equality_comparable
<Base
> {
1365 return x
.base_
== y
.base_
;
1368 // to satisfy forward_iterator
1369 constexpr ProxyIterator
operator++(int)
1370 requires
std::forward_iterator
<Base
> {
1376 // to satisfy bidirectional_iterator
1377 constexpr ProxyIterator
& operator--()
1378 requires
std::bidirectional_iterator
<Base
> {
1383 constexpr ProxyIterator
operator--(int)
1384 requires
std::bidirectional_iterator
<Base
> {
1390 // to satisfy random_access_iterator
1391 constexpr ProxyIterator
& operator+=(difference_type n
)
1392 requires
std::random_access_iterator
<Base
> {
1397 constexpr ProxyIterator
& operator-=(difference_type n
)
1398 requires
std::random_access_iterator
<Base
> {
1403 constexpr Proxy
<std::iter_reference_t
<Base
>> operator[](difference_type n
) const
1404 requires
std::random_access_iterator
<Base
> {
1408 friend constexpr bool operator<(const ProxyIterator
& x
, const ProxyIterator
& y
)
1409 requires
std::random_access_iterator
<Base
> {
1410 return x
.base_
< y
.base_
;
1413 friend constexpr bool operator>(const ProxyIterator
& x
, const ProxyIterator
& y
)
1414 requires
std::random_access_iterator
<Base
> {
1415 return x
.base_
> y
.base_
;
1418 friend constexpr bool operator<=(const ProxyIterator
& x
, const ProxyIterator
& y
)
1419 requires
std::random_access_iterator
<Base
> {
1420 return x
.base_
<= y
.base_
;
1423 friend constexpr bool operator>=(const ProxyIterator
& x
, const ProxyIterator
& y
)
1424 requires
std::random_access_iterator
<Base
> {
1425 return x
.base_
>= y
.base_
;
1428 friend constexpr auto operator<=>(const ProxyIterator
& x
, const ProxyIterator
& y
)
1429 requires(std::random_access_iterator
<Base
> && std::three_way_comparable
<Base
>) {
1430 return x
.base_
<=> y
.base_
;
1433 friend constexpr ProxyIterator
operator+(const ProxyIterator
& x
, difference_type n
)
1434 requires
std::random_access_iterator
<Base
> {
1435 return ProxyIterator
{x
.base_
+ n
};
1438 friend constexpr ProxyIterator
operator+(difference_type n
, const ProxyIterator
& x
)
1439 requires
std::random_access_iterator
<Base
> {
1440 return ProxyIterator
{n
+ x
.base_
};
1443 friend constexpr ProxyIterator
operator-(const ProxyIterator
& x
, difference_type n
)
1444 requires
std::random_access_iterator
<Base
> {
1445 return ProxyIterator
{x
.base_
- n
};
1448 friend constexpr difference_type
operator-(const ProxyIterator
& x
, const ProxyIterator
& y
)
1449 requires
std::random_access_iterator
<Base
> {
1450 return x
.base_
- y
.base_
;
1453 template <class Base
>
1454 ProxyIterator(Base
) -> ProxyIterator
<Base
>;
1456 static_assert(std::indirectly_readable
<ProxyIterator
<int*>>);
1457 static_assert(std::indirectly_writable
<ProxyIterator
<int*>, Proxy
<int>>);
1458 static_assert(std::indirectly_writable
<ProxyIterator
<int*>, Proxy
<int&>>);
1460 template <class Iter
>
1461 using Cpp20InputProxyIterator
= ProxyIterator
<cpp20_input_iterator
<Iter
>>;
1463 template <class Iter
>
1464 using ForwardProxyIterator
= ProxyIterator
<forward_iterator
<Iter
>>;
1466 template <class Iter
>
1467 using BidirectionalProxyIterator
= ProxyIterator
<bidirectional_iterator
<Iter
>>;
1469 template <class Iter
>
1470 using RandomAccessProxyIterator
= ProxyIterator
<random_access_iterator
<Iter
>>;
1472 template <class Iter
>
1473 using ContiguousProxyIterator
= ProxyIterator
<contiguous_iterator
<Iter
>>;
1475 template <class BaseSent
>
1476 struct ProxySentinel
{
1479 ProxySentinel() = default;
1480 constexpr ProxySentinel(BaseSent base
) : base_
{std::move(base
)} {}
1482 template <class Base
>
1483 requires
std::equality_comparable_with
<Base
, BaseSent
>
1484 friend constexpr bool operator==(const ProxyIterator
<Base
>& p
, const ProxySentinel
& sent
) {
1485 return p
.base_
== sent
.base_
;
1488 template <class BaseSent
>
1489 ProxySentinel(BaseSent
) -> ProxySentinel
<BaseSent
>;
1491 template <std::ranges::input_range Base
>
1492 requires
std::ranges::view
<Base
>
1496 constexpr auto begin() { return ProxyIterator
{std::ranges::begin(base_
)}; }
1498 constexpr auto end() { return ProxySentinel
{std::ranges::end(base_
)}; }
1500 constexpr auto begin() const
1501 requires
std::ranges::input_range
<const Base
> {
1502 return ProxyIterator
{std::ranges::begin(base_
)};
1505 constexpr auto end() const
1506 requires
std::ranges::input_range
<const Base
> {
1507 return ProxySentinel
{std::ranges::end(base_
)};
1511 template <std::ranges::input_range R
>
1512 requires
std::ranges::viewable_range
<R
&&>
1513 ProxyRange(R
&&) -> ProxyRange
<std::views::all_t
<R
&&>>;
1515 #endif // TEST_STD_VER > 17
1517 #if TEST_STD_VER >= 17
1520 template <class Derived
, class Iter
>
1521 class iterator_wrapper
{
1524 using iter_traits
= std::iterator_traits
<Iter
>;
1527 using iterator_category
= typename
iter_traits::iterator_category
;
1528 using value_type
= typename
iter_traits::value_type
;
1529 using difference_type
= typename
iter_traits::difference_type
;
1530 using pointer
= typename
iter_traits::pointer
;
1531 using reference
= typename
iter_traits::reference
;
1533 constexpr iterator_wrapper() : iter_() {}
1534 constexpr explicit iterator_wrapper(Iter iter
) : iter_(iter
) {}
1536 decltype(*iter_
) operator*() { return *iter_
; }
1537 decltype(*iter_
) operator*() const { return *iter_
; }
1539 decltype(iter_
[0]) operator[](difference_type v
) const {
1543 Derived
& operator++() {
1545 return static_cast<Derived
&>(*this);
1548 Derived
operator++(int) {
1549 auto tmp
= static_cast<Derived
&>(*this);
1554 Derived
& operator--() {
1556 return static_cast<Derived
&>(*this);
1559 Derived
operator--(int) {
1560 auto tmp
= static_cast<Derived
&>(*this);
1565 Derived
& operator+=(difference_type i
) {
1567 return static_cast<Derived
&>(*this);
1570 Derived
& operator-=(difference_type i
) {
1572 return static_cast<Derived
&>(*this);
1575 friend decltype(iter_
- iter_
) operator-(const iterator_wrapper
& lhs
, const iterator_wrapper
& rhs
) {
1576 return lhs
.iter_
- rhs
.iter_
;
1579 friend Derived
operator-(Derived iter
, difference_type i
) {
1584 friend Derived
operator+(Derived iter
, difference_type i
) {
1589 friend Derived
operator+(difference_type i
, Derived iter
) { return iter
+ i
; }
1591 friend bool operator==(const iterator_wrapper
& lhs
, const iterator_wrapper
& rhs
) { return lhs
.iter_
== rhs
.iter_
; }
1592 friend bool operator!=(const iterator_wrapper
& lhs
, const iterator_wrapper
& rhs
) { return lhs
.iter_
!= rhs
.iter_
; }
1594 friend bool operator>(const iterator_wrapper
& lhs
, const iterator_wrapper
& rhs
) { return lhs
.iter_
> rhs
.iter_
; }
1595 friend bool operator<(const iterator_wrapper
& lhs
, const iterator_wrapper
& rhs
) { return lhs
.iter_
< rhs
.iter_
; }
1596 friend bool operator<=(const iterator_wrapper
& lhs
, const iterator_wrapper
& rhs
) { return lhs
.iter_
<= rhs
.iter_
; }
1597 friend bool operator>=(const iterator_wrapper
& lhs
, const iterator_wrapper
& rhs
) { return lhs
.iter_
>= rhs
.iter_
; }
1600 class iterator_error
: std::runtime_error
{
1602 iterator_error(const char* what
) : std::runtime_error(what
) {}
1605 #ifndef TEST_HAS_NO_EXCEPTIONS
1606 template <class Iter
>
1607 class throw_on_move_iterator
: public iterator_wrapper
<throw_on_move_iterator
<Iter
>, Iter
> {
1608 using base
= iterator_wrapper
<throw_on_move_iterator
<Iter
>, Iter
>;
1610 int moves_until_throw_
= 0;
1613 using difference_type
= typename
base::difference_type
;
1614 using value_type
= typename
base::value_type
;
1615 using iterator_category
= typename
base::iterator_category
;
1617 throw_on_move_iterator() = default;
1618 throw_on_move_iterator(Iter iter
, int moves_until_throw
)
1619 : base(std::move(iter
)), moves_until_throw_(moves_until_throw
) {}
1621 throw_on_move_iterator(const throw_on_move_iterator
& other
) : base(other
) {}
1622 throw_on_move_iterator
& operator=(const throw_on_move_iterator
& other
) {
1623 static_cast<base
&>(*this) = other
;
1627 throw_on_move_iterator(throw_on_move_iterator
&& other
)
1628 : base(std::move(other
)), moves_until_throw_(other
.moves_until_throw_
- 1) {
1629 if (moves_until_throw_
== -1)
1630 throw iterator_error("throw_on_move_iterator");
1633 throw_on_move_iterator
& operator=(throw_on_move_iterator
&& other
) {
1634 moves_until_throw_
= other
.moves_until_throw_
- 1;
1635 if (moves_until_throw_
== -1)
1636 throw iterator_error("throw_on_move_iterator");
1641 template <class Iter
>
1642 throw_on_move_iterator(Iter
) -> throw_on_move_iterator
<Iter
>;
1643 #endif // TEST_HAS_NO_EXCEPTIONS
1646 #endif // TEST_STD_VER >= 17
1649 template <class Ptr
>
1650 using random_access_iterator_list
=
1652 #if TEST_STD_VER >= 20
1653 contiguous_iterator
<Ptr
>,
1655 random_access_iterator
<Ptr
> >;
1657 template <class Ptr
>
1658 using bidirectional_iterator_list
=
1659 concatenate_t
<random_access_iterator_list
<Ptr
>, type_list
<bidirectional_iterator
<Ptr
> > >;
1661 template <class Ptr
>
1662 using forward_iterator_list
= concatenate_t
<bidirectional_iterator_list
<Ptr
>, type_list
<forward_iterator
<Ptr
> > >;
1664 template <class Ptr
>
1665 using cpp17_input_iterator_list
= concatenate_t
<forward_iterator_list
<Ptr
>, type_list
<cpp17_input_iterator
<Ptr
> > >;
1667 #if TEST_STD_VER >= 20
1668 template <class Ptr
>
1669 using cpp20_input_iterator_list
=
1670 concatenate_t
<forward_iterator_list
<Ptr
>, type_list
<cpp20_input_iterator
<Ptr
>, cpp17_input_iterator
<Ptr
>>>;
1672 } // namespace types
1675 #endif // SUPPORT_TEST_ITERATORS_H