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