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 // UNSUPPORTED: c++03, c++11, c++14, c++17
10 
11 // <iterator>
12 //
13 // reverse_iterator
14 //
15 // template<indirectly_swappable<Iterator> Iterator2>
16 //   friend constexpr void
17 //     iter_swap(const reverse_iterator& x,
18 //               const reverse_iterator<Iterator2>& y) noexcept(see below);
19 
20 #include <iterator>
21 
22 #include <cassert>
23 #include <type_traits>
24 #include <utility>
25 #include "test_iterators.h"
26 #include "test_macros.h"
27 
test()28 constexpr bool test() {
29   // Can use `iter_swap` with a regular array.
30   {
31     constexpr int N = 3;
32     int a[N] = {0, 1, 2};
33 
34     std::reverse_iterator<int*> rb(a + N);
35     std::reverse_iterator<int*> re(a + 1);
36     assert(a[0] == 0);
37     assert(a[2] == 2);
38 
39     static_assert(std::same_as<decltype(iter_swap(rb, re)), void>);
40     iter_swap(rb, re);
41     assert(a[0] == 2);
42     assert(a[2] == 0);
43   }
44 
45   // Check that the `iter_swap` customization point is being used.
46   {
47     int iter_swap_invocations = 0;
48     int a[] = {0, 1, 2};
49     adl::Iterator base1 = adl::Iterator::TrackSwaps(a + 1, iter_swap_invocations);
50     adl::Iterator base2 = adl::Iterator::TrackSwaps(a + 2, iter_swap_invocations);
51     std::reverse_iterator<adl::Iterator> ri1(base1), ri2(base2);
52     iter_swap(ri1, ri2);
53     assert(iter_swap_invocations == 1);
54 
55     iter_swap(ri2, ri1);
56     assert(iter_swap_invocations == 2);
57   }
58 
59   // Check the `noexcept` specification.
60   {
61     {
62       struct ThrowingCopyNoexceptDecrement {
63         using value_type = int;
64         using difference_type = std::ptrdiff_t;
65 
66         ThrowingCopyNoexceptDecrement();
67         ThrowingCopyNoexceptDecrement(const ThrowingCopyNoexceptDecrement&);
68 
69         int& operator*() const noexcept { static int x; return x; }
70 
71         ThrowingCopyNoexceptDecrement& operator++();
72         ThrowingCopyNoexceptDecrement operator++(int);
73         ThrowingCopyNoexceptDecrement& operator--() noexcept;
74         ThrowingCopyNoexceptDecrement operator--(int) noexcept;
75 
76         bool operator==(const ThrowingCopyNoexceptDecrement&) const = default;
77       };
78       static_assert(std::bidirectional_iterator<ThrowingCopyNoexceptDecrement>);
79 
80       static_assert(!std::is_nothrow_copy_constructible_v<ThrowingCopyNoexceptDecrement>);
81       static_assert( std::is_nothrow_copy_constructible_v<int*>);
82       ASSERT_NOEXCEPT(std::ranges::iter_swap(--std::declval<ThrowingCopyNoexceptDecrement&>(), --std::declval<int*&>()));
83       using RI1 = std::reverse_iterator<ThrowingCopyNoexceptDecrement>;
84       using RI2 = std::reverse_iterator<int*>;
85       ASSERT_NOT_NOEXCEPT(iter_swap(std::declval<RI1>(), std::declval<RI2>()));
86       ASSERT_NOT_NOEXCEPT(iter_swap(std::declval<RI2>(), std::declval<RI1>()));
87     }
88 
89     {
90       struct NoexceptCopyThrowingDecrement {
91         using value_type = int;
92         using difference_type = std::ptrdiff_t;
93 
94         NoexceptCopyThrowingDecrement();
95         NoexceptCopyThrowingDecrement(const NoexceptCopyThrowingDecrement&) noexcept;
96 
97         int& operator*() const { static int x; return x; }
98 
99         NoexceptCopyThrowingDecrement& operator++();
100         NoexceptCopyThrowingDecrement operator++(int);
101         NoexceptCopyThrowingDecrement& operator--();
102         NoexceptCopyThrowingDecrement operator--(int);
103 
104         bool operator==(const NoexceptCopyThrowingDecrement&) const = default;
105       };
106       static_assert(std::bidirectional_iterator<NoexceptCopyThrowingDecrement>);
107 
108       static_assert( std::is_nothrow_copy_constructible_v<NoexceptCopyThrowingDecrement>);
109       static_assert( std::is_nothrow_copy_constructible_v<int*>);
110       ASSERT_NOT_NOEXCEPT(std::ranges::iter_swap(--std::declval<NoexceptCopyThrowingDecrement&>(), --std::declval<int*&>()));
111       using RI1 = std::reverse_iterator<NoexceptCopyThrowingDecrement>;
112       using RI2 = std::reverse_iterator<int*>;
113       ASSERT_NOT_NOEXCEPT(iter_swap(std::declval<RI1>(), std::declval<RI2>()));
114       ASSERT_NOT_NOEXCEPT(iter_swap(std::declval<RI2>(), std::declval<RI1>()));
115     }
116 
117     {
118       struct NoexceptCopyAndDecrement {
119         using value_type = int;
120         using difference_type = std::ptrdiff_t;
121 
122         NoexceptCopyAndDecrement();
123         NoexceptCopyAndDecrement(const NoexceptCopyAndDecrement&) noexcept;
124 
125         int& operator*() const noexcept { static int x; return x; }
126 
127         NoexceptCopyAndDecrement& operator++();
128         NoexceptCopyAndDecrement operator++(int);
129         NoexceptCopyAndDecrement& operator--() noexcept;
130         NoexceptCopyAndDecrement operator--(int) noexcept;
131 
132         bool operator==(const NoexceptCopyAndDecrement&) const = default;
133       };
134       static_assert(std::bidirectional_iterator<NoexceptCopyAndDecrement>);
135 
136       static_assert( std::is_nothrow_copy_constructible_v<NoexceptCopyAndDecrement>);
137       static_assert( std::is_nothrow_copy_constructible_v<int*>);
138       ASSERT_NOEXCEPT(std::ranges::iter_swap(--std::declval<NoexceptCopyAndDecrement&>(), --std::declval<int*&>()));
139       using RI1 = std::reverse_iterator<NoexceptCopyAndDecrement>;
140       using RI2 = std::reverse_iterator<int*>;
141       ASSERT_NOEXCEPT(iter_swap(std::declval<RI1>(), std::declval<RI2>()));
142       ASSERT_NOEXCEPT(iter_swap(std::declval<RI2>(), std::declval<RI1>()));
143     }
144   }
145 
146   return true;
147 }
148 
main(int,char **)149 int main(int, char**) {
150   test();
151   static_assert(test());
152 
153   return 0;
154 }
155