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