1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef SUPPORT_TEST_ITERATORS_H
10 #define SUPPORT_TEST_ITERATORS_H
11
12 #include <cassert>
13 #include <concepts>
14 #include <iterator>
15 #include <ranges>
16 #include <stdexcept>
17 #include <type_traits>
18 #include <utility>
19
20 #include "test_macros.h"
21
22
23 // This iterator meets C++20's Cpp17OutputIterator requirements, as described
24 // in Table 90 ([output.iterators]).
25 template <class It>
26 class cpp17_output_iterator
27 {
28 It it_;
29
30 template <class U> friend class cpp17_output_iterator;
31 public:
32 typedef std::output_iterator_tag iterator_category;
33 typedef void value_type;
34 typedef typename std::iterator_traits<It>::difference_type difference_type;
35 typedef It pointer;
36 typedef typename std::iterator_traits<It>::reference reference;
37
cpp17_output_iterator(It it)38 TEST_CONSTEXPR explicit cpp17_output_iterator(It it) : it_(std::move(it)) {}
39
40 template <class U>
cpp17_output_iterator(const cpp17_output_iterator<U> & u)41 TEST_CONSTEXPR cpp17_output_iterator(const cpp17_output_iterator<U>& u) : it_(u.it_) {}
42
43 template <class U, class = typename std::enable_if<std::is_default_constructible<U>::value>::type>
cpp17_output_iterator(cpp17_output_iterator<U> && u)44 TEST_CONSTEXPR_CXX14 cpp17_output_iterator(cpp17_output_iterator<U>&& u) : it_(u.it_) { u.it_ = U(); }
45
46 TEST_CONSTEXPR reference operator*() const {return *it_;}
47
48 TEST_CONSTEXPR_CXX14 cpp17_output_iterator& operator++() {++it_; return *this;}
49 TEST_CONSTEXPR_CXX14 cpp17_output_iterator operator++(int) {return cpp17_output_iterator(it_++);}
50
base(const cpp17_output_iterator & i)51 friend TEST_CONSTEXPR It base(const cpp17_output_iterator& i) { return i.it_; }
52
53 template <class T>
54 void operator,(T const &) = delete;
55 };
56 #if TEST_STD_VER > 17
57 static_assert(std::output_iterator<cpp17_output_iterator<int*>, int>);
58 #endif
59
60 // This iterator meets C++20's Cpp17InputIterator requirements, as described
61 // in Table 89 ([input.iterators]).
62 template <class It, class ItTraits = It>
63 class cpp17_input_iterator
64 {
65 typedef std::iterator_traits<ItTraits> Traits;
66 It it_;
67
68 template <class U, class T> friend class cpp17_input_iterator;
69 public:
70 typedef std::input_iterator_tag iterator_category;
71 typedef typename Traits::value_type value_type;
72 typedef typename Traits::difference_type difference_type;
73 typedef It pointer;
74 typedef typename Traits::reference reference;
75
cpp17_input_iterator(It it)76 TEST_CONSTEXPR explicit cpp17_input_iterator(It it) : it_(it) {}
77
78 template <class U, class T>
cpp17_input_iterator(const cpp17_input_iterator<U,T> & u)79 TEST_CONSTEXPR cpp17_input_iterator(const cpp17_input_iterator<U, T>& u) : it_(u.it_) {}
80
81 template <class U, class T, class = typename std::enable_if<std::is_default_constructible<U>::value>::type>
cpp17_input_iterator(cpp17_input_iterator<U,T> && u)82 TEST_CONSTEXPR_CXX14 cpp17_input_iterator(cpp17_input_iterator<U, T>&& u) : it_(u.it_) { u.it_ = U(); }
83
84 TEST_CONSTEXPR reference operator*() const {return *it_;}
85
86 TEST_CONSTEXPR_CXX14 cpp17_input_iterator& operator++() {++it_; return *this;}
87 TEST_CONSTEXPR_CXX14 cpp17_input_iterator operator++(int) {return cpp17_input_iterator(it_++);}
88
89 friend TEST_CONSTEXPR bool operator==(const cpp17_input_iterator& x, const cpp17_input_iterator& y) {return x.it_ == y.it_;}
90 friend TEST_CONSTEXPR bool operator!=(const cpp17_input_iterator& x, const cpp17_input_iterator& y) {return x.it_ != y.it_;}
91
base(const cpp17_input_iterator & i)92 friend TEST_CONSTEXPR It base(const cpp17_input_iterator& i) { return i.it_; }
93
94 template <class T>
95 void operator,(T const &) = delete;
96 };
97 #if TEST_STD_VER > 17
98 static_assert(std::input_iterator<cpp17_input_iterator<int*>>);
99 #endif
100
101 template <class It>
102 class forward_iterator
103 {
104 It it_;
105
106 template <class U> friend class forward_iterator;
107 public:
108 typedef std::forward_iterator_tag iterator_category;
109 typedef typename std::iterator_traits<It>::value_type value_type;
110 typedef typename std::iterator_traits<It>::difference_type difference_type;
111 typedef It pointer;
112 typedef typename std::iterator_traits<It>::reference reference;
113
forward_iterator()114 TEST_CONSTEXPR forward_iterator() : it_() {}
forward_iterator(It it)115 TEST_CONSTEXPR explicit forward_iterator(It it) : it_(it) {}
116
117 template <class U>
forward_iterator(const forward_iterator<U> & u)118 TEST_CONSTEXPR forward_iterator(const forward_iterator<U>& u) : it_(u.it_) {}
119
120 template <class U, class = typename std::enable_if<std::is_default_constructible<U>::value>::type>
forward_iterator(forward_iterator<U> && other)121 TEST_CONSTEXPR_CXX14 forward_iterator(forward_iterator<U>&& other) : it_(other.it_) { other.it_ = U(); }
122
123 TEST_CONSTEXPR reference operator*() const {return *it_;}
124
125 TEST_CONSTEXPR_CXX14 forward_iterator& operator++() {++it_; return *this;}
126 TEST_CONSTEXPR_CXX14 forward_iterator operator++(int) {return forward_iterator(it_++);}
127
128 friend TEST_CONSTEXPR bool operator==(const forward_iterator& x, const forward_iterator& y) {return x.it_ == y.it_;}
129 friend TEST_CONSTEXPR bool operator!=(const forward_iterator& x, const forward_iterator& y) {return x.it_ != y.it_;}
130
base(const forward_iterator & i)131 friend TEST_CONSTEXPR It base(const forward_iterator& i) { return i.it_; }
132
133 template <class T>
134 void operator,(T const &) = delete;
135 };
136
137 template <class It>
138 class bidirectional_iterator
139 {
140 It it_;
141
142 template <class U> friend class bidirectional_iterator;
143 public:
144 typedef std::bidirectional_iterator_tag iterator_category;
145 typedef typename std::iterator_traits<It>::value_type value_type;
146 typedef typename std::iterator_traits<It>::difference_type difference_type;
147 typedef It pointer;
148 typedef typename std::iterator_traits<It>::reference reference;
149
bidirectional_iterator()150 TEST_CONSTEXPR bidirectional_iterator() : it_() {}
bidirectional_iterator(It it)151 TEST_CONSTEXPR explicit bidirectional_iterator(It it) : it_(it) {}
152
153 template <class U>
bidirectional_iterator(const bidirectional_iterator<U> & u)154 TEST_CONSTEXPR bidirectional_iterator(const bidirectional_iterator<U>& u) : it_(u.it_) {}
155
156 template <class U, class = typename std::enable_if<std::is_default_constructible<U>::value>::type>
bidirectional_iterator(bidirectional_iterator<U> && u)157 TEST_CONSTEXPR_CXX14 bidirectional_iterator(bidirectional_iterator<U>&& u) : it_(u.it_) { u.it_ = U(); }
158
159 TEST_CONSTEXPR reference operator*() const {return *it_;}
160
161 TEST_CONSTEXPR_CXX14 bidirectional_iterator& operator++() {++it_; return *this;}
162 TEST_CONSTEXPR_CXX14 bidirectional_iterator& operator--() {--it_; return *this;}
163 TEST_CONSTEXPR_CXX14 bidirectional_iterator operator++(int) {return bidirectional_iterator(it_++);}
164 TEST_CONSTEXPR_CXX14 bidirectional_iterator operator--(int) {return bidirectional_iterator(it_--);}
165
166 friend TEST_CONSTEXPR bool operator==(const bidirectional_iterator& x, const bidirectional_iterator& y) {return x.it_ == y.it_;}
167 friend TEST_CONSTEXPR bool operator!=(const bidirectional_iterator& x, const bidirectional_iterator& y) {return x.it_ != y.it_;}
168
base(const bidirectional_iterator & i)169 friend TEST_CONSTEXPR It base(const bidirectional_iterator& i) { return i.it_; }
170
171 template <class T>
172 void operator,(T const &) = delete;
173 };
174
175 template <class It>
176 class random_access_iterator
177 {
178 It it_;
179
180 template <class U> friend class random_access_iterator;
181 public:
182 typedef std::random_access_iterator_tag iterator_category;
183 typedef typename std::iterator_traits<It>::value_type value_type;
184 typedef typename std::iterator_traits<It>::difference_type difference_type;
185 typedef It pointer;
186 typedef typename std::iterator_traits<It>::reference reference;
187
random_access_iterator()188 TEST_CONSTEXPR random_access_iterator() : it_() {}
random_access_iterator(It it)189 TEST_CONSTEXPR explicit random_access_iterator(It it) : it_(it) {}
190
191 template <class U>
random_access_iterator(const random_access_iterator<U> & u)192 TEST_CONSTEXPR random_access_iterator(const random_access_iterator<U>& u) : it_(u.it_) {}
193
194 template <class U, class = typename std::enable_if<std::is_default_constructible<U>::value>::type>
random_access_iterator(random_access_iterator<U> && u)195 TEST_CONSTEXPR_CXX14 random_access_iterator(random_access_iterator<U>&& u) : it_(u.it_) { u.it_ = U(); }
196
197 TEST_CONSTEXPR_CXX14 reference operator*() const {return *it_;}
198 TEST_CONSTEXPR_CXX14 reference operator[](difference_type n) const {return it_[n];}
199
200 TEST_CONSTEXPR_CXX14 random_access_iterator& operator++() {++it_; return *this;}
201 TEST_CONSTEXPR_CXX14 random_access_iterator& operator--() {--it_; return *this;}
202 TEST_CONSTEXPR_CXX14 random_access_iterator operator++(int) {return random_access_iterator(it_++);}
203 TEST_CONSTEXPR_CXX14 random_access_iterator operator--(int) {return random_access_iterator(it_--);}
204
205 TEST_CONSTEXPR_CXX14 random_access_iterator& operator+=(difference_type n) {it_ += n; return *this;}
206 TEST_CONSTEXPR_CXX14 random_access_iterator& operator-=(difference_type n) {it_ -= n; return *this;}
207 friend TEST_CONSTEXPR_CXX14 random_access_iterator operator+(random_access_iterator x, difference_type n) {x += n; return x;}
208 friend TEST_CONSTEXPR_CXX14 random_access_iterator operator+(difference_type n, random_access_iterator x) {x += n; return x;}
209 friend TEST_CONSTEXPR_CXX14 random_access_iterator operator-(random_access_iterator x, difference_type n) {x -= n; return x;}
210 friend TEST_CONSTEXPR difference_type operator-(random_access_iterator x, random_access_iterator y) {return x.it_ - y.it_;}
211
212 friend TEST_CONSTEXPR bool operator==(const random_access_iterator& x, const random_access_iterator& y) {return x.it_ == y.it_;}
213 friend TEST_CONSTEXPR bool operator!=(const random_access_iterator& x, const random_access_iterator& y) {return x.it_ != y.it_;}
214 friend TEST_CONSTEXPR bool operator< (const random_access_iterator& x, const random_access_iterator& y) {return x.it_ < y.it_;}
215 friend TEST_CONSTEXPR bool operator<=(const random_access_iterator& x, const random_access_iterator& y) {return x.it_ <= y.it_;}
216 friend TEST_CONSTEXPR bool operator> (const random_access_iterator& x, const random_access_iterator& y) {return x.it_ > y.it_;}
217 friend TEST_CONSTEXPR bool operator>=(const random_access_iterator& x, const random_access_iterator& y) {return x.it_ >= y.it_;}
218
base(const random_access_iterator & i)219 friend TEST_CONSTEXPR It base(const random_access_iterator& i) { return i.it_; }
220
221 template <class T>
222 void operator,(T const &) = delete;
223 };
224
225 #if TEST_STD_VER > 17
226
227 template <std::random_access_iterator It>
228 class cpp20_random_access_iterator {
229 It it_;
230
231 template <std::random_access_iterator>
232 friend class cpp20_random_access_iterator;
233
234 public:
235 using iterator_category = std::input_iterator_tag;
236 using iterator_concept = std::random_access_iterator_tag;
237 using value_type = typename std::iterator_traits<It>::value_type;
238 using difference_type = typename std::iterator_traits<It>::difference_type;
239
cpp20_random_access_iterator()240 constexpr cpp20_random_access_iterator() : it_() {}
cpp20_random_access_iterator(It it)241 constexpr explicit cpp20_random_access_iterator(It it) : it_(it) {}
242
243 template <class U>
cpp20_random_access_iterator(const cpp20_random_access_iterator<U> & u)244 constexpr cpp20_random_access_iterator(const cpp20_random_access_iterator<U>& u) : it_(u.it_) {}
245
246 template <class U>
cpp20_random_access_iterator(cpp20_random_access_iterator<U> && u)247 constexpr cpp20_random_access_iterator(cpp20_random_access_iterator<U>&& u) : it_(u.it_) {
248 u.it_ = U();
249 }
250
decltype(auto)251 constexpr decltype(auto) operator*() const { return *it_; }
decltype(auto)252 constexpr decltype(auto) operator[](difference_type n) const { return it_[n]; }
253
254 constexpr cpp20_random_access_iterator& operator++() {
255 ++it_;
256 return *this;
257 }
258 constexpr cpp20_random_access_iterator& operator--() {
259 --it_;
260 return *this;
261 }
262 constexpr cpp20_random_access_iterator operator++(int) { return cpp20_random_access_iterator(it_++); }
263 constexpr cpp20_random_access_iterator operator--(int) { return cpp20_random_access_iterator(it_--); }
264
265 constexpr cpp20_random_access_iterator& operator+=(difference_type n) {
266 it_ += n;
267 return *this;
268 }
269 constexpr cpp20_random_access_iterator& operator-=(difference_type n) {
270 it_ -= n;
271 return *this;
272 }
273 friend constexpr cpp20_random_access_iterator operator+(cpp20_random_access_iterator x, difference_type n) {
274 x += n;
275 return x;
276 }
277 friend constexpr cpp20_random_access_iterator operator+(difference_type n, cpp20_random_access_iterator x) {
278 x += n;
279 return x;
280 }
281 friend constexpr cpp20_random_access_iterator operator-(cpp20_random_access_iterator x, difference_type n) {
282 x -= n;
283 return x;
284 }
285 friend constexpr difference_type operator-(cpp20_random_access_iterator x, cpp20_random_access_iterator y) {
286 return x.it_ - y.it_;
287 }
288
289 friend constexpr bool operator==(const cpp20_random_access_iterator& x, const cpp20_random_access_iterator& y) {
290 return x.it_ == y.it_;
291 }
292 friend constexpr bool operator!=(const cpp20_random_access_iterator& x, const cpp20_random_access_iterator& y) {
293 return x.it_ != y.it_;
294 }
295 friend constexpr bool operator<(const cpp20_random_access_iterator& x, const cpp20_random_access_iterator& y) {
296 return x.it_ < y.it_;
297 }
298 friend constexpr bool operator<=(const cpp20_random_access_iterator& x, const cpp20_random_access_iterator& y) {
299 return x.it_ <= y.it_;
300 }
301 friend constexpr bool operator>(const cpp20_random_access_iterator& x, const cpp20_random_access_iterator& y) {
302 return x.it_ > y.it_;
303 }
304 friend constexpr bool operator>=(const cpp20_random_access_iterator& x, const cpp20_random_access_iterator& y) {
305 return x.it_ >= y.it_;
306 }
307
base(const cpp20_random_access_iterator & i)308 friend constexpr It base(const cpp20_random_access_iterator& i) { return i.it_; }
309
310 template <class T>
311 void operator,(T const&) = delete;
312 };
313
314 static_assert(std::random_access_iterator<cpp20_random_access_iterator<int*>>);
315
316 template <class It>
317 class contiguous_iterator
318 {
319 static_assert(std::is_pointer_v<It>, "Things probably break in this case");
320
321 It it_;
322
323 template <class U> friend class contiguous_iterator;
324 public:
325 typedef std::contiguous_iterator_tag iterator_category;
326 typedef typename std::iterator_traits<It>::value_type value_type;
327 typedef typename std::iterator_traits<It>::difference_type difference_type;
328 typedef It pointer;
329 typedef typename std::iterator_traits<It>::reference reference;
330 typedef typename std::remove_pointer<It>::type element_type;
331
base()332 TEST_CONSTEXPR_CXX14 It base() const {return it_;}
333
contiguous_iterator()334 TEST_CONSTEXPR_CXX14 contiguous_iterator() : it_() {}
contiguous_iterator(It it)335 TEST_CONSTEXPR_CXX14 explicit contiguous_iterator(It it) : it_(it) {}
336
337 template <class U>
contiguous_iterator(const contiguous_iterator<U> & u)338 TEST_CONSTEXPR_CXX14 contiguous_iterator(const contiguous_iterator<U>& u) : it_(u.it_) {}
339
340 template <class U, class = typename std::enable_if<std::is_default_constructible<U>::value>::type>
contiguous_iterator(contiguous_iterator<U> && u)341 constexpr contiguous_iterator(contiguous_iterator<U>&& u) : it_(u.it_) { u.it_ = U(); }
342
343 TEST_CONSTEXPR reference operator*() const {return *it_;}
344 TEST_CONSTEXPR pointer operator->() const {return it_;}
345 TEST_CONSTEXPR reference operator[](difference_type n) const {return it_[n];}
346
347 TEST_CONSTEXPR_CXX14 contiguous_iterator& operator++() {++it_; return *this;}
348 TEST_CONSTEXPR_CXX14 contiguous_iterator& operator--() {--it_; return *this;}
349 TEST_CONSTEXPR_CXX14 contiguous_iterator operator++(int) {return contiguous_iterator(it_++);}
350 TEST_CONSTEXPR_CXX14 contiguous_iterator operator--(int) {return contiguous_iterator(it_--);}
351
352 TEST_CONSTEXPR_CXX14 contiguous_iterator& operator+=(difference_type n) {it_ += n; return *this;}
353 TEST_CONSTEXPR_CXX14 contiguous_iterator& operator-=(difference_type n) {it_ -= n; return *this;}
354 friend TEST_CONSTEXPR_CXX14 contiguous_iterator operator+(contiguous_iterator x, difference_type n) {x += n; return x;}
355 friend TEST_CONSTEXPR_CXX14 contiguous_iterator operator+(difference_type n, contiguous_iterator x) {x += n; return x;}
356 friend TEST_CONSTEXPR_CXX14 contiguous_iterator operator-(contiguous_iterator x, difference_type n) {x -= n; return x;}
357 friend TEST_CONSTEXPR difference_type operator-(contiguous_iterator x, contiguous_iterator y) {return x.it_ - y.it_;}
358
359 friend TEST_CONSTEXPR bool operator==(const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ == y.it_;}
360 friend TEST_CONSTEXPR bool operator!=(const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ != y.it_;}
361 friend TEST_CONSTEXPR bool operator< (const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ < y.it_;}
362 friend TEST_CONSTEXPR bool operator<=(const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ <= y.it_;}
363 friend TEST_CONSTEXPR bool operator> (const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ > y.it_;}
364 friend TEST_CONSTEXPR bool operator>=(const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ >= y.it_;}
365
base(const contiguous_iterator & i)366 friend TEST_CONSTEXPR It base(const contiguous_iterator& i) { return i.it_; }
367
368 template <class T>
369 void operator,(T const &) = delete;
370 };
371
372 template <class It>
373 class three_way_contiguous_iterator
374 {
375 static_assert(std::is_pointer_v<It>, "Things probably break in this case");
376
377 It it_;
378
379 template <class U> friend class three_way_contiguous_iterator;
380 public:
381 typedef std::contiguous_iterator_tag iterator_category;
382 typedef typename std::iterator_traits<It>::value_type value_type;
383 typedef typename std::iterator_traits<It>::difference_type difference_type;
384 typedef It pointer;
385 typedef typename std::iterator_traits<It>::reference reference;
386 typedef typename std::remove_pointer<It>::type element_type;
387
base()388 constexpr It base() const {return it_;}
389
three_way_contiguous_iterator()390 constexpr three_way_contiguous_iterator() : it_() {}
three_way_contiguous_iterator(It it)391 constexpr explicit three_way_contiguous_iterator(It it) : it_(it) {}
392
393 template <class U>
three_way_contiguous_iterator(const three_way_contiguous_iterator<U> & u)394 constexpr three_way_contiguous_iterator(const three_way_contiguous_iterator<U>& u) : it_(u.it_) {}
395
396 template <class U, class = typename std::enable_if<std::is_default_constructible<U>::value>::type>
three_way_contiguous_iterator(three_way_contiguous_iterator<U> && u)397 constexpr three_way_contiguous_iterator(three_way_contiguous_iterator<U>&& u) : it_(u.it_) { u.it_ = U(); }
398
399 constexpr reference operator*() const {return *it_;}
400 constexpr pointer operator->() const {return it_;}
401 constexpr reference operator[](difference_type n) const {return it_[n];}
402
403 constexpr three_way_contiguous_iterator& operator++() {++it_; return *this;}
404 constexpr three_way_contiguous_iterator& operator--() {--it_; return *this;}
405 constexpr three_way_contiguous_iterator operator++(int) {return three_way_contiguous_iterator(it_++);}
406 constexpr three_way_contiguous_iterator operator--(int) {return three_way_contiguous_iterator(it_--);}
407
408 constexpr three_way_contiguous_iterator& operator+=(difference_type n) {it_ += n; return *this;}
409 constexpr three_way_contiguous_iterator& operator-=(difference_type n) {it_ -= n; return *this;}
410 friend constexpr three_way_contiguous_iterator operator+(three_way_contiguous_iterator x, difference_type n) {x += n; return x;}
411 friend constexpr three_way_contiguous_iterator operator+(difference_type n, three_way_contiguous_iterator x) {x += n; return x;}
412 friend constexpr three_way_contiguous_iterator operator-(three_way_contiguous_iterator x, difference_type n) {x -= n; return x;}
413 friend constexpr difference_type operator-(three_way_contiguous_iterator x, three_way_contiguous_iterator y) {return x.it_ - y.it_;}
414
415 friend constexpr auto operator<=>(const three_way_contiguous_iterator& x, const three_way_contiguous_iterator& y) {return x.it_ <=> y.it_;}
416 friend constexpr bool operator==(const three_way_contiguous_iterator& x, const three_way_contiguous_iterator& y) {return x.it_ == y.it_;}
417
418 template <class T>
419 void operator,(T const &) = delete;
420 };
421 #endif // TEST_STD_VER > 17
422
423 template <class Iter> // ADL base() for everything else (including pointers)
base(Iter i)424 TEST_CONSTEXPR Iter base(Iter i) { return i; }
425
426 template <typename T>
427 struct ThrowingIterator {
428 typedef std::bidirectional_iterator_tag iterator_category;
429 typedef ptrdiff_t difference_type;
430 typedef const T value_type;
431 typedef const T * pointer;
432 typedef const T & reference;
433
434 enum ThrowingAction { TAIncrement, TADecrement, TADereference, TAAssignment, TAComparison };
435
ThrowingIteratorThrowingIterator436 TEST_CONSTEXPR ThrowingIterator()
437 : begin_(nullptr), end_(nullptr), current_(nullptr), action_(TADereference), index_(0) {}
438 TEST_CONSTEXPR explicit ThrowingIterator(const T* first, const T* last, int index = 0,
439 ThrowingAction action = TADereference)
begin_ThrowingIterator440 : begin_(first), end_(last), current_(first), action_(action), index_(index) {}
ThrowingIteratorThrowingIterator441 TEST_CONSTEXPR ThrowingIterator(const ThrowingIterator &rhs)
442 : begin_(rhs.begin_), end_(rhs.end_), current_(rhs.current_), action_(rhs.action_), index_(rhs.index_) {}
443
444 TEST_CONSTEXPR_CXX14 ThrowingIterator& operator=(const ThrowingIterator& rhs) {
445 if (action_ == TAAssignment && --index_ < 0) {
446 #ifndef TEST_HAS_NO_EXCEPTIONS
447 throw std::runtime_error("throw from iterator assignment");
448 #else
449 assert(false);
450 #endif
451 }
452 begin_ = rhs.begin_;
453 end_ = rhs.end_;
454 current_ = rhs.current_;
455 action_ = rhs.action_;
456 index_ = rhs.index_;
457 return *this;
458 }
459
460 TEST_CONSTEXPR_CXX14 reference operator*() const {
461 if (action_ == TADereference && --index_ < 0) {
462 #ifndef TEST_HAS_NO_EXCEPTIONS
463 throw std::runtime_error("throw from iterator dereference");
464 #else
465 assert(false);
466 #endif
467 }
468 return *current_;
469 }
470
471 TEST_CONSTEXPR_CXX14 ThrowingIterator& operator++() {
472 if (action_ == TAIncrement && --index_ < 0) {
473 #ifndef TEST_HAS_NO_EXCEPTIONS
474 throw std::runtime_error("throw from iterator increment");
475 #else
476 assert(false);
477 #endif
478 }
479 ++current_;
480 return *this;
481 }
482
483 TEST_CONSTEXPR_CXX14 ThrowingIterator operator++(int) {
484 ThrowingIterator temp = *this;
485 ++(*this);
486 return temp;
487 }
488
489 TEST_CONSTEXPR_CXX14 ThrowingIterator& operator--() {
490 if (action_ == TADecrement && --index_ < 0) {
491 #ifndef TEST_HAS_NO_EXCEPTIONS
492 throw std::runtime_error("throw from iterator decrement");
493 #else
494 assert(false);
495 #endif
496 }
497 --current_;
498 return *this;
499 }
500
501 TEST_CONSTEXPR_CXX14 ThrowingIterator operator--(int) {
502 ThrowingIterator temp = *this;
503 --(*this);
504 return temp;
505 }
506
507 TEST_CONSTEXPR_CXX14 friend bool operator==(const ThrowingIterator& a, const ThrowingIterator& b) {
508 if (a.action_ == TAComparison && --a.index_ < 0) {
509 #ifndef TEST_HAS_NO_EXCEPTIONS
510 throw std::runtime_error("throw from iterator comparison");
511 #else
512 assert(false);
513 #endif
514 }
515 bool atEndL = a.current_ == a.end_;
516 bool atEndR = b.current_ == b.end_;
517 if (atEndL != atEndR) return false; // one is at the end (or empty), the other is not.
518 if (atEndL) return true; // both are at the end (or empty)
519 return a.current_ == b.current_;
520 }
521
522 TEST_CONSTEXPR friend bool operator!=(const ThrowingIterator& a, const ThrowingIterator& b) {
523 return !(a == b);
524 }
525
526 template <class T2>
527 void operator,(T2 const &) = delete;
528
529 private:
530 const T* begin_;
531 const T* end_;
532 const T* current_;
533 ThrowingAction action_;
534 mutable int index_;
535 };
536
537 template <typename T>
538 struct NonThrowingIterator {
539 typedef std::bidirectional_iterator_tag iterator_category;
540 typedef ptrdiff_t difference_type;
541 typedef const T value_type;
542 typedef const T * pointer;
543 typedef const T & reference;
544
NonThrowingIteratorNonThrowingIterator545 NonThrowingIterator()
546 : begin_(nullptr), end_(nullptr), current_(nullptr) {}
NonThrowingIteratorNonThrowingIterator547 explicit NonThrowingIterator(const T *first, const T *last)
548 : begin_(first), end_(last), current_(first) {}
NonThrowingIteratorNonThrowingIterator549 NonThrowingIterator(const NonThrowingIterator& rhs)
550 : begin_(rhs.begin_), end_(rhs.end_), current_(rhs.current_) {}
551
552 NonThrowingIterator& operator=(const NonThrowingIterator& rhs) TEST_NOEXCEPT {
553 begin_ = rhs.begin_;
554 end_ = rhs.end_;
555 current_ = rhs.current_;
556 return *this;
557 }
558
559 reference operator*() const TEST_NOEXCEPT {
560 return *current_;
561 }
562
563 NonThrowingIterator& operator++() TEST_NOEXCEPT {
564 ++current_;
565 return *this;
566 }
567
568 NonThrowingIterator operator++(int) TEST_NOEXCEPT {
569 NonThrowingIterator temp = *this;
570 ++(*this);
571 return temp;
572 }
573
574 NonThrowingIterator & operator--() TEST_NOEXCEPT {
575 --current_;
576 return *this;
577 }
578
579 NonThrowingIterator operator--(int) TEST_NOEXCEPT {
580 NonThrowingIterator temp = *this;
581 --(*this);
582 return temp;
583 }
584
585 friend bool operator==(const NonThrowingIterator& a, const NonThrowingIterator& b) TEST_NOEXCEPT {
586 bool atEndL = a.current_ == a.end_;
587 bool atEndR = b.current_ == b.end_;
588 if (atEndL != atEndR) return false; // one is at the end (or empty), the other is not.
589 if (atEndL) return true; // both are at the end (or empty)
590 return a.current_ == b.current_;
591 }
592
593 friend bool operator!=(const NonThrowingIterator& a, const NonThrowingIterator& b) TEST_NOEXCEPT {
594 return !(a == b);
595 }
596
597 template <class T2>
598 void operator,(T2 const &) = delete;
599
600 private:
601 const T *begin_;
602 const T *end_;
603 const T *current_;
604 };
605
606 #if TEST_STD_VER > 17
607
608 template <class It>
609 class cpp20_input_iterator
610 {
611 It it_;
612
613 public:
614 using value_type = std::iter_value_t<It>;
615 using difference_type = std::iter_difference_t<It>;
616 using iterator_concept = std::input_iterator_tag;
617
cpp20_input_iterator(It it)618 constexpr explicit cpp20_input_iterator(It it) : it_(it) {}
619 cpp20_input_iterator(cpp20_input_iterator&&) = default;
620 cpp20_input_iterator& operator=(cpp20_input_iterator&&) = default;
decltype(auto)621 constexpr decltype(auto) operator*() const { return *it_; }
622 constexpr cpp20_input_iterator& operator++() { ++it_; return *this; }
623 constexpr void operator++(int) { ++it_; }
624
base(const cpp20_input_iterator & i)625 friend constexpr It base(const cpp20_input_iterator& i) { return i.it_; }
626
627 template <class T>
628 void operator,(T const &) = delete;
629 };
630 static_assert(std::input_iterator<cpp20_input_iterator<int*>>);
631
632 template<std::input_or_output_iterator>
633 struct iter_value_or_void { using type = void; };
634
635 template<std::input_iterator I>
636 struct iter_value_or_void<I> {
637 using type = std::iter_value_t<I>;
638 };
639
640 template <class It>
641 class cpp20_output_iterator {
642 It it_;
643
644 public:
645 using difference_type = std::iter_difference_t<It>;
646
647 constexpr explicit cpp20_output_iterator(It it) : it_(it) {}
648 cpp20_output_iterator(cpp20_output_iterator&&) = default;
649 cpp20_output_iterator& operator=(cpp20_output_iterator&&) = default;
650
651 constexpr decltype(auto) operator*() const { return *it_; }
652 constexpr cpp20_output_iterator& operator++() {
653 ++it_;
654 return *this;
655 }
656 constexpr cpp20_output_iterator operator++(int) { return cpp20_output_iterator(it_++); }
657
658 friend constexpr It base(const cpp20_output_iterator& i) { return i.it_; }
659
660 template <class T>
661 void operator,(T const&) = delete;
662 };
663
664 static_assert(std::output_iterator<cpp20_output_iterator<int*>, int>);
665
666 // Iterator adaptor that counts the number of times the iterator has had a successor/predecessor
667 // operation called. Has two recorders:
668 // * `stride_count`, which records the total number of calls to an op++, op--, op+=, or op-=.
669 // * `stride_displacement`, which records the displacement of the calls. This means that both
670 // op++/op+= will increase the displacement counter by 1, and op--/op-= will decrease the
671 // displacement counter by 1.
672 template <class It>
673 class stride_counting_iterator {
674 public:
675 using value_type = typename iter_value_or_void<It>::type;
676 using difference_type = std::iter_difference_t<It>;
677 using iterator_concept =
678 std::conditional_t<std::contiguous_iterator<It>, std::contiguous_iterator_tag,
679 std::conditional_t<std::random_access_iterator<It>, std::random_access_iterator_tag,
680 std::conditional_t<std::bidirectional_iterator<It>, std::bidirectional_iterator_tag,
681 std::conditional_t<std::forward_iterator<It>, std::forward_iterator_tag,
682 std::conditional_t<std::input_iterator<It>, std::input_iterator_tag,
683 /* else */ std::output_iterator_tag
684 >>>>>;
685
686 stride_counting_iterator() requires std::default_initializable<It> = default;
687
688 constexpr explicit stride_counting_iterator(It const& it) : base_(base(it)) { }
689
690 friend constexpr It base(stride_counting_iterator const& it) { return It(it.base_); }
691
692 constexpr difference_type stride_count() const { return stride_count_; }
693
694 constexpr difference_type stride_displacement() const { return stride_displacement_; }
695
696 constexpr decltype(auto) operator*() const { return *It(base_); }
697
698 constexpr decltype(auto) operator[](difference_type n) const { return It(base_)[n]; }
699
700 constexpr stride_counting_iterator& operator++() {
701 It tmp(base_);
702 base_ = base(++tmp);
703 ++stride_count_;
704 ++stride_displacement_;
705 return *this;
706 }
707
708 constexpr void operator++(int) { ++*this; }
709
710 constexpr stride_counting_iterator operator++(int)
711 requires std::forward_iterator<It>
712 {
713 auto temp = *this;
714 ++*this;
715 return temp;
716 }
717
718 constexpr stride_counting_iterator& operator--()
719 requires std::bidirectional_iterator<It>
720 {
721 It tmp(base_);
722 base_ = base(--tmp);
723 ++stride_count_;
724 --stride_displacement_;
725 return *this;
726 }
727
728 constexpr stride_counting_iterator operator--(int)
729 requires std::bidirectional_iterator<It>
730 {
731 auto temp = *this;
732 --*this;
733 return temp;
734 }
735
736 constexpr stride_counting_iterator& operator+=(difference_type const n)
737 requires std::random_access_iterator<It>
738 {
739 It tmp(base_);
740 base_ = base(tmp += n);
741 ++stride_count_;
742 ++stride_displacement_;
743 return *this;
744 }
745
746 constexpr stride_counting_iterator& operator-=(difference_type const n)
747 requires std::random_access_iterator<It>
748 {
749 It tmp(base_);
750 base_ = base(tmp -= n);
751 ++stride_count_;
752 --stride_displacement_;
753 return *this;
754 }
755
756 friend constexpr stride_counting_iterator operator+(stride_counting_iterator it, difference_type n)
757 requires std::random_access_iterator<It>
758 {
759 return it += n;
760 }
761
762 friend constexpr stride_counting_iterator operator+(difference_type n, stride_counting_iterator it)
763 requires std::random_access_iterator<It>
764 {
765 return it += n;
766 }
767
768 friend constexpr stride_counting_iterator operator-(stride_counting_iterator it, difference_type n)
769 requires std::random_access_iterator<It>
770 {
771 return it -= n;
772 }
773
774 friend constexpr difference_type operator-(stride_counting_iterator const& x, stride_counting_iterator const& y)
775 requires std::sized_sentinel_for<It, It>
776 {
777 return base(x) - base(y);
778 }
779
780 constexpr bool operator==(stride_counting_iterator const& other) const
781 requires std::sentinel_for<It, It>
782 {
783 return It(base_) == It(other.base_);
784 }
785
786 friend constexpr bool operator<(stride_counting_iterator const& x, stride_counting_iterator const& y)
787 requires std::random_access_iterator<It>
788 {
789 return It(x.base_) < It(y.base_);
790 }
791
792 friend constexpr bool operator>(stride_counting_iterator const& x, stride_counting_iterator const& y)
793 requires std::random_access_iterator<It>
794 {
795 return It(x.base_) > It(y.base_);
796 }
797
798 friend constexpr bool operator<=(stride_counting_iterator const& x, stride_counting_iterator const& y)
799 requires std::random_access_iterator<It>
800 {
801 return It(x.base_) <= It(y.base_);
802 }
803
804 friend constexpr bool operator>=(stride_counting_iterator const& x, stride_counting_iterator const& y)
805 requires std::random_access_iterator<It>
806 {
807 return It(x.base_) >= It(y.base_);
808 }
809
810 template <class T>
811 void operator,(T const &) = delete;
812
813 private:
814 decltype(base(std::declval<It>())) base_;
815 difference_type stride_count_ = 0;
816 difference_type stride_displacement_ = 0;
817 };
818
819 #endif // TEST_STD_VER > 17
820
821 #if TEST_STD_VER > 17
822 template <class It>
823 class sentinel_wrapper {
824 public:
825 explicit sentinel_wrapper() = default;
826 constexpr explicit sentinel_wrapper(const It& it) : base_(base(it)) {}
827 constexpr bool operator==(const It& other) const { return base_ == base(other); }
828 friend constexpr It base(const sentinel_wrapper& s) { return It(s.base_); }
829 private:
830 decltype(base(std::declval<It>())) base_;
831 };
832
833 template <class It>
834 class sized_sentinel {
835 public:
836 explicit sized_sentinel() = default;
837 constexpr explicit sized_sentinel(const It& it) : base_(base(it)) {}
838 constexpr bool operator==(const It& other) const { return base_ == base(other); }
839 friend constexpr auto operator-(const sized_sentinel& s, const It& i) { return s.base_ - base(i); }
840 friend constexpr auto operator-(const It& i, const sized_sentinel& s) { return base(i) - s.base_; }
841 friend constexpr It base(const sized_sentinel& s) { return It(s.base_); }
842 private:
843 decltype(base(std::declval<It>())) base_;
844 };
845
846 namespace adl {
847
848 class Iterator {
849 public:
850 using value_type = int;
851 using reference = int&;
852 using difference_type = ptrdiff_t;
853
854 private:
855 value_type* ptr_ = nullptr;
856 int* iter_moves_ = nullptr;
857 int* iter_swaps_ = nullptr;
858
859 constexpr Iterator(int* p, int* iter_moves, int* iter_swaps)
860 : ptr_(p)
861 , iter_moves_(iter_moves)
862 , iter_swaps_(iter_swaps) {}
863
864 public:
865 constexpr Iterator() = default;
866 static constexpr Iterator TrackMoves(int* p, int& iter_moves) {
867 return Iterator(p, &iter_moves, /*iter_swaps=*/nullptr);
868 }
869 static constexpr Iterator TrackSwaps(int& iter_swaps) {
870 return Iterator(/*p=*/nullptr, /*iter_moves=*/nullptr, &iter_swaps);
871 }
872 static constexpr Iterator TrackSwaps(int* p, int& iter_swaps) {
873 return Iterator(p, /*iter_moves=*/nullptr, &iter_swaps);
874 }
875
876 constexpr int iter_moves() const { assert(iter_moves_); return *iter_moves_; }
877 constexpr int iter_swaps() const { assert(iter_swaps_); return *iter_swaps_; }
878
879 constexpr value_type& operator*() const { return *ptr_; }
880 constexpr reference operator[](difference_type n) const { return ptr_[n]; }
881
882 friend constexpr Iterator operator+(Iterator i, difference_type n) {
883 return Iterator(i.ptr_ + n, i.iter_moves_, i.iter_swaps_);
884 }
885 friend constexpr Iterator operator+(difference_type n, Iterator i) {
886 return i + n;
887 }
888 constexpr Iterator operator-(difference_type n) const {
889 return Iterator(ptr_ - n, iter_moves_, iter_swaps_);
890 }
891 constexpr difference_type operator-(Iterator rhs) const {
892 return ptr_ - rhs.ptr_;
893 }
894 constexpr Iterator& operator+=(difference_type n) {
895 ptr_ += n;
896 return *this;
897 }
898 constexpr Iterator& operator-=(difference_type n) {
899 ptr_ -= n;
900 return *this;
901 }
902
903 constexpr Iterator& operator++() { ++ptr_; return *this; }
904 constexpr Iterator operator++(int) {
905 Iterator prev = *this;
906 ++ptr_;
907 return prev;
908 }
909
910 constexpr Iterator& operator--() { --ptr_; return *this; }
911 constexpr Iterator operator--(int) {
912 Iterator prev = *this;
913 --ptr_;
914 return prev;
915 }
916
917 constexpr friend void iter_swap(Iterator a, Iterator b) {
918 std::swap(a.ptr_, b.ptr_);
919 if (a.iter_swaps_) {
920 ++(*a.iter_swaps_);
921 }
922 }
923
924 constexpr friend value_type&& iter_move(Iterator iter) {
925 if (iter.iter_moves_) {
926 ++(*iter.iter_moves_);
927 }
928 return std::move(*iter);
929 }
930
931 constexpr friend bool operator==(const Iterator& lhs, const Iterator& rhs) {
932 return lhs.ptr_ == rhs.ptr_;
933 }
934 constexpr friend auto operator<=>(const Iterator& lhs, const Iterator& rhs) {
935 return lhs.ptr_ <=> rhs.ptr_;
936 }
937 };
938
939 } // namespace adl
940
941 // Proxy
942 // ======================================================================
943 // Proxy that can wrap a value or a reference. It simulates C++23's tuple
944 // but simplified to just hold one argument.
945 // Note that unlike tuple, this class deliberately doesn't have special handling
946 // of swap to cause a compilation error if it's used in an algorithm that relies
947 // on plain swap instead of ranges::iter_swap.
948 // This class is useful for testing that if algorithms support proxy iterator
949 // properly, i.e. calling ranges::iter_swap and ranges::iter_move instead of
950 // plain swap and std::move.
951 template <class T>
952 struct Proxy;
953
954 template <class T>
955 inline constexpr bool IsProxy = false;
956
957 template <class T>
958 inline constexpr bool IsProxy<Proxy<T>> = true;
959
960 template <class T>
961 struct Proxy {
962 T data;
963
964 constexpr T& getData() & { return data; }
965
966 constexpr const T& getData() const& { return data; }
967
968 constexpr T&& getData() && { return static_cast<T&&>(data); }
969
970 constexpr const T&& getData() const&& { return static_cast<const T&&>(data); }
971
972 template <class U>
973 requires std::constructible_from<T, U&&>
974 constexpr Proxy(U&& u) : data{std::forward<U>(u)} {}
975
976 // This constructor covers conversion from cvref of Proxy<U>, including non-const/const versions of copy/move constructor
977 template <class Other>
978 requires(IsProxy<std::decay_t<Other>> && std::constructible_from<T, decltype(std::declval<Other>().getData())>)
979 constexpr Proxy(Other&& other) : data{std::forward<Other>(other).getData()} {}
980
981 template <class Other>
982 requires(IsProxy<std::decay_t<Other>> && std::assignable_from<T&, decltype(std::declval<Other>().getData())>)
983 constexpr Proxy& operator=(Other&& other) {
984 data = std::forward<Other>(other).getData();
985 return *this;
986 }
987
988 // const assignment required to make ProxyIterator model std::indirectly_writable
989 template <class Other>
990 requires(IsProxy<std::decay_t<Other>> && std::assignable_from<const T&, decltype(std::declval<Other>().getData())>)
991 constexpr const Proxy& operator=(Other&& other) const {
992 data = std::forward<Other>(other).getData();
993 return *this;
994 }
995
996 // If `T` is a reference type, the implicitly-generated assignment operator will be deleted (and would take precedence
997 // over the templated `operator=` above because it's a better match).
998 constexpr Proxy& operator=(const Proxy& rhs) {
999 data = rhs.data;
1000 return *this;
1001 }
1002
1003 // no specialised swap function that takes const Proxy& and no specialised const member swap
1004 // Calling swap(Proxy<T>{}, Proxy<T>{}) would fail (pass prvalues)
1005
1006 // Compare operators are defined for the convenience of the tests
1007 friend constexpr bool operator==(const Proxy&, const Proxy&)
1008 requires (std::equality_comparable<T> && !std::is_reference_v<T>)
1009 = default;
1010
1011 // Helps compare e.g. `Proxy<int>` and `Proxy<int&>`. Note that the default equality comparison operator is deleted
1012 // when `T` is a reference type.
1013 template <class U>
1014 friend constexpr bool operator==(const Proxy& lhs, const Proxy<U>& rhs)
1015 requires std::equality_comparable_with<std::decay_t<T>, std::decay_t<U>> {
1016 return lhs.data == rhs.data;
1017 }
1018
1019 friend constexpr auto operator<=>(const Proxy&, const Proxy&)
1020 requires (std::three_way_comparable<T> && !std::is_reference_v<T>)
1021 = default;
1022
1023 // Helps compare e.g. `Proxy<int>` and `Proxy<int&>`. Note that the default 3-way comparison operator is deleted when
1024 // `T` is a reference type.
1025 template <class U>
1026 friend constexpr auto operator<=>(const Proxy& lhs, const Proxy<U>& rhs)
1027 requires std::three_way_comparable_with<std::decay_t<T>, std::decay_t<U>> {
1028 return lhs.data <=> rhs.data;
1029 }
1030 };
1031
1032 // This is to make ProxyIterator model `std::indirectly_readable`
1033 template <class T, class U, template <class> class TQual, template <class> class UQual>
1034 requires requires { typename std::common_reference_t<TQual<T>, UQual<U>>; }
1035 struct std::basic_common_reference<Proxy<T>, Proxy<U>, TQual, UQual> {
1036 using type = Proxy<std::common_reference_t<TQual<T>, UQual<U>>>;
1037 };
1038
1039 template <class T, class U>
1040 requires requires { typename std::common_type_t<T, U>; }
1041 struct std::common_type<Proxy<T>, Proxy<U>> {
1042 using type = Proxy<std::common_type_t<T, U>>;
1043 };
1044
1045 // ProxyIterator
1046 // ======================================================================
1047 // It wraps `Base` iterator and when dereferenced it returns a Proxy<ref>
1048 // It simulates C++23's zip_view::iterator but simplified to just wrap
1049 // one base iterator.
1050 // Note it forwards value_type, iter_move, iter_swap. e.g if the base
1051 // iterator is int*,
1052 // operator* -> Proxy<int&>
1053 // iter_value_t -> Proxy<int>
1054 // iter_move -> Proxy<int&&>
1055 template <class Base>
1056 struct ProxyIteratorBase {};
1057
1058 template <class Base>
1059 requires std::derived_from<
1060 typename std::iterator_traits<Base>::iterator_category,
1061 std::input_iterator_tag>
1062 struct ProxyIteratorBase<Base> {
1063 using iterator_category = std::input_iterator_tag;
1064 };
1065
1066 template <std::input_iterator Base>
1067 consteval auto get_iterator_concept() {
1068 if constexpr (std::random_access_iterator<Base>) {
1069 return std::random_access_iterator_tag{};
1070 } else if constexpr (std::bidirectional_iterator<Base>) {
1071 return std::bidirectional_iterator_tag{};
1072 } else if constexpr (std::forward_iterator<Base>) {
1073 return std::forward_iterator_tag{};
1074 } else {
1075 return std::input_iterator_tag{};
1076 }
1077 }
1078
1079 template <std::input_iterator Base>
1080 struct ProxyIterator : ProxyIteratorBase<Base> {
1081 Base base_;
1082
1083 using iterator_concept = decltype(get_iterator_concept<Base>());
1084 using value_type = Proxy<std::iter_value_t<Base>>;
1085 using difference_type = std::iter_difference_t<Base>;
1086
1087 ProxyIterator()
1088 requires std::default_initializable<Base>
1089 = default;
1090
1091 constexpr ProxyIterator(Base base) : base_{std::move(base)} {}
1092
1093 template <class T>
1094 requires std::constructible_from<Base, T&&>
1095 constexpr ProxyIterator(T&& t) : base_{std::forward<T>(t)} {}
1096
1097 friend constexpr decltype(auto) base(const ProxyIterator& p) { return base(p.base_); }
1098
1099 // Specialization of iter_move
1100 // If operator* returns Proxy<Foo&>, iter_move will return Proxy<Foo&&>
1101 // Note std::move(*it) returns Proxy<Foo&>&&, which is not what we want as
1102 // it will likely result in a copy rather than a move
1103 friend constexpr Proxy<std::iter_rvalue_reference_t<Base>> iter_move(const ProxyIterator& p) noexcept {
1104 return {std::ranges::iter_move(p.base_)};
1105 }
1106
1107 // Specialization of iter_swap
1108 // Note std::swap(*x, *y) would fail to compile as operator* returns prvalues
1109 // and std::swap takes non-const lvalue references
1110 friend constexpr void iter_swap(const ProxyIterator& x, const ProxyIterator& y) noexcept {
1111 std::ranges::iter_swap(x.base_, y.base_);
1112 }
1113
1114 // to satisfy input_iterator
1115 constexpr Proxy<std::iter_reference_t<Base>> operator*() const { return {*base_}; }
1116
1117 constexpr ProxyIterator& operator++() {
1118 ++base_;
1119 return *this;
1120 }
1121
1122 constexpr void operator++(int) { ++*this; }
1123
1124 friend constexpr bool operator==(const ProxyIterator& x, const ProxyIterator& y)
1125 requires std::equality_comparable<Base> {
1126 return x.base_ == y.base_;
1127 }
1128
1129 // to satisfy forward_iterator
1130 constexpr ProxyIterator operator++(int)
1131 requires std::forward_iterator<Base> {
1132 auto tmp = *this;
1133 ++*this;
1134 return tmp;
1135 }
1136
1137 // to satisfy bidirectional_iterator
1138 constexpr ProxyIterator& operator--()
1139 requires std::bidirectional_iterator<Base> {
1140 --base_;
1141 return *this;
1142 }
1143
1144 constexpr ProxyIterator operator--(int)
1145 requires std::bidirectional_iterator<Base> {
1146 auto tmp = *this;
1147 --*this;
1148 return tmp;
1149 }
1150
1151 // to satisfy random_access_iterator
1152 constexpr ProxyIterator& operator+=(difference_type n)
1153 requires std::random_access_iterator<Base> {
1154 base_ += n;
1155 return *this;
1156 }
1157
1158 constexpr ProxyIterator& operator-=(difference_type n)
1159 requires std::random_access_iterator<Base> {
1160 base_ -= n;
1161 return *this;
1162 }
1163
1164 constexpr Proxy<std::iter_reference_t<Base>> operator[](difference_type n) const
1165 requires std::random_access_iterator<Base> {
1166 return {base_[n]};
1167 }
1168
1169 friend constexpr bool operator<(const ProxyIterator& x, const ProxyIterator& y)
1170 requires std::random_access_iterator<Base> {
1171 return x.base_ < y.base_;
1172 }
1173
1174 friend constexpr bool operator>(const ProxyIterator& x, const ProxyIterator& y)
1175 requires std::random_access_iterator<Base> {
1176 return x.base_ > y.base_;
1177 }
1178
1179 friend constexpr bool operator<=(const ProxyIterator& x, const ProxyIterator& y)
1180 requires std::random_access_iterator<Base> {
1181 return x.base_ <= y.base_;
1182 }
1183
1184 friend constexpr bool operator>=(const ProxyIterator& x, const ProxyIterator& y)
1185 requires std::random_access_iterator<Base> {
1186 return x.base_ >= y.base_;
1187 }
1188
1189 friend constexpr auto operator<=>(const ProxyIterator& x, const ProxyIterator& y)
1190 requires(std::random_access_iterator<Base> && std::three_way_comparable<Base>) {
1191 return x.base_ <=> y.base_;
1192 }
1193
1194 friend constexpr ProxyIterator operator+(const ProxyIterator& x, difference_type n)
1195 requires std::random_access_iterator<Base> {
1196 return ProxyIterator{x.base_ + n};
1197 }
1198
1199 friend constexpr ProxyIterator operator+(difference_type n, const ProxyIterator& x)
1200 requires std::random_access_iterator<Base> {
1201 return ProxyIterator{n + x.base_};
1202 }
1203
1204 friend constexpr ProxyIterator operator-(const ProxyIterator& x, difference_type n)
1205 requires std::random_access_iterator<Base> {
1206 return ProxyIterator{x.base_ - n};
1207 }
1208
1209 friend constexpr difference_type operator-(const ProxyIterator& x, const ProxyIterator& y)
1210 requires std::random_access_iterator<Base> {
1211 return x.base_ - y.base_;
1212 }
1213 };
1214
1215 static_assert(std::indirectly_readable<ProxyIterator<int*>>);
1216 static_assert(std::indirectly_writable<ProxyIterator<int*>, Proxy<int>>);
1217 static_assert(std::indirectly_writable<ProxyIterator<int*>, Proxy<int&>>);
1218
1219 template <class BaseSent>
1220 struct ProxySentinel {
1221 BaseSent base_;
1222
1223 ProxySentinel() = default;
1224 constexpr ProxySentinel(BaseSent base) : base_{std::move(base)} {}
1225
1226 template <class Base>
1227 requires std::equality_comparable_with<Base, BaseSent>
1228 friend constexpr bool operator==(const ProxyIterator<Base>& p, const ProxySentinel& sent) {
1229 return p.base_ == sent.base_;
1230 }
1231 };
1232
1233 #if !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
1234 template <std::ranges::input_range Base>
1235 requires std::ranges::view<Base>
1236 struct ProxyRange {
1237 Base base_;
1238
1239 constexpr auto begin() { return ProxyIterator{std::ranges::begin(base_)}; }
1240
1241 constexpr auto end() { return ProxySentinel{std::ranges::end(base_)}; }
1242
1243 constexpr auto begin() const
1244 requires std::ranges::input_range<const Base> {
1245 return ProxyIterator{std::ranges::begin(base_)};
1246 }
1247
1248 constexpr auto end() const
1249 requires std::ranges::input_range<const Base> {
1250 return ProxySentinel{std::ranges::end(base_)};
1251 }
1252 };
1253
1254 template <std::ranges::input_range R>
1255 requires std::ranges::viewable_range<R&&>
1256 ProxyRange(R&&) -> ProxyRange<std::views::all_t<R&&>>;
1257 #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
1258
1259 #endif // TEST_STD_VER > 17
1260
1261 #endif // SUPPORT_TEST_ITERATORS_H
1262