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 // UNSUPPORTED: libcpp-has-no-incomplete-ranges
11
12 #include "MoveOnly.h"
13 #include "test_iterators.h"
14
15 #include <cassert>
16
testProxy()17 constexpr void testProxy() {
18 // constructor value
19 {
20 Proxy<int> p{5};
21 assert(p.data == 5);
22 }
23
24 // constructor reference
25 {
26 int i = 5;
27 Proxy<int&> p{i};
28 assert(&p.data == &i);
29 }
30
31 // constructor conversion
32 {
33 int i = 5;
34 Proxy<int&> p1{i};
35 Proxy<int> p2 = p1;
36 assert(p2.data == 5);
37
38 Proxy<int&> p3{p2};
39 assert(&(p3.data) == &(p2.data));
40
41 MoveOnly m1{8};
42 Proxy<MoveOnly&&> p4 = std::move(m1);
43
44 Proxy<MoveOnly> p5 = std::move(p4);
45 assert(p5.data.get() == 8);
46 }
47
48 // assignment
49 {
50 Proxy<int> p1{5};
51 Proxy<int> p2{6};
52 p1 = p2;
53 assert(p1.data == 6);
54
55 MoveOnly m1{8};
56 Proxy<MoveOnly&&> p3 = std::move(m1);
57 Proxy<MoveOnly> p4{MoveOnly{9}};
58 p4 = std::move(p3);
59 assert(p4.data.get() == 8);
60
61 // `T` is a reference type.
62 int i = 5, j = 6, k = 7, x = 8;
63 Proxy<int&> p5{i};
64 // `Other` is a prvalue.
65 p5 = Proxy<int&>{j};
66 assert(p5.data == 6);
67 // `Other` is a const lvalue.
68 const Proxy<int&> p_ref{k};
69 p5 = p_ref;
70 assert(p5.data == 7);
71 // `Other` is an xvalue.
72 Proxy<int&> px{x};
73 p5 = std::move(px);
74 assert(p5.data == 8);
75 }
76
77 // const assignment
78 {
79 int i = 5;
80 int j = 6;
81 const Proxy<int&> p1{i};
82 const Proxy<int&> p2{j};
83 p1 = p2;
84 assert(i == 6);
85
86 MoveOnly m1{8};
87 MoveOnly m2{9};
88 Proxy<MoveOnly&&> p3 = std::move(m1);
89 const Proxy<MoveOnly&&> p4 = std::move(m2);
90 p4 = std::move(p3);
91 assert(p4.data.get() == 8);
92 }
93
94 // compare
95 {
96 Proxy<int> p1{5};
97 Proxy<int> p2{6};
98 assert(p1 != p2);
99 assert(p1 < p2);
100
101 // Comparing `T` and `T&`.
102 int i = 5, j = 6;
103 Proxy<int&> p_ref{i};
104 Proxy<const int&> p_cref{j};
105 assert(p1 == p_ref);
106 assert(p2 == p_cref);
107 assert(p_ref == p1);
108 assert(p_cref == p2);
109 assert(p_ref == p_ref);
110 assert(p_cref == p_cref);
111 assert(p_ref != p_cref);
112 }
113 }
114
115 static_assert(std::input_iterator<ProxyIterator<cpp20_input_iterator<int*>>>);
116 static_assert(!std::forward_iterator<ProxyIterator<cpp20_input_iterator<int*>>>);
117
118 static_assert(std::forward_iterator<ProxyIterator<forward_iterator<int*>>>);
119 static_assert(!std::bidirectional_iterator<ProxyIterator<forward_iterator<int*>>>);
120
121 static_assert(std::bidirectional_iterator<ProxyIterator<bidirectional_iterator<int*>>>);
122 static_assert(!std::random_access_iterator<ProxyIterator<bidirectional_iterator<int*>>>);
123
124 static_assert(std::random_access_iterator<ProxyIterator<random_access_iterator<int*>>>);
125 static_assert(!std::contiguous_iterator<ProxyIterator<random_access_iterator<int*>>>);
126
127 static_assert(std::random_access_iterator<ProxyIterator<contiguous_iterator<int*>>>);
128 static_assert(!std::contiguous_iterator<ProxyIterator<contiguous_iterator<int*>>>);
129
130 template <class Iter>
testInputIteratorOperation()131 constexpr void testInputIteratorOperation() {
132 int data[] = {1, 2};
133 ProxyIterator<Iter> iter{Iter{data}};
134 sentinel_wrapper<ProxyIterator<Iter>> sent{ProxyIterator<Iter>{Iter{data + 2}}};
135
136 std::same_as<Proxy<int&>> decltype(auto) result = *iter;
137 assert(result.data == 1);
138 auto& iter2 = ++iter;
139 static_assert(std::is_same_v<decltype(++iter), ProxyIterator<Iter>&>);
140 assert(&iter2 == &iter);
141 assert((*iter).data == 2);
142 ++iter;
143 assert(iter == sent);
144 }
145
146 template <class Iter>
testForwardIteratorOperation()147 constexpr void testForwardIteratorOperation() {
148 int data[] = {1, 2};
149 ProxyIterator<Iter> iter{Iter{data}};
150
151 std::same_as<ProxyIterator<Iter>> decltype(auto) it2 = iter++;
152 assert((*it2).data == 1);
153 assert((*iter).data == 2);
154 }
155
156 template <class Iter>
testBidirectionalIteratorOperation()157 constexpr void testBidirectionalIteratorOperation() {
158 int data[] = {1, 2};
159 ProxyIterator<Iter> iter{Iter{data}};
160 ++iter;
161 assert((*iter).data == 2);
162
163 auto& iter2 = --iter;
164 static_assert(std::is_same_v<decltype(--iter), ProxyIterator<Iter>&>);
165 assert(&iter2 == &iter);
166 assert((*iter).data == 1);
167 ++iter;
168
169 std::same_as<ProxyIterator<Iter>> decltype(auto) iter3 = iter--;
170 assert((*iter).data == 1);
171 assert((*iter3).data == 2);
172 }
173
174 template <class Iter>
testRandomAccessIteratorOperation()175 constexpr void testRandomAccessIteratorOperation() {
176 int data[] = {1, 2, 3, 4, 5};
177 ProxyIterator<Iter> iter{Iter{data}};
178
179 auto& iter2 = iter += 2;
180 static_assert(std::is_same_v<decltype(iter += 2), ProxyIterator<Iter>&>);
181 assert(&iter2 == &iter);
182 assert((*iter).data == 3);
183
184 auto& iter3 = iter -= 1;
185 static_assert(std::is_same_v<decltype(iter -= 1), ProxyIterator<Iter>&>);
186 assert(&iter3 == &iter);
187 assert((*iter).data == 2);
188
189 std::same_as<Proxy<int&>> decltype(auto) r = iter[2];
190 assert(r.data == 4);
191
192 std::same_as<ProxyIterator<Iter>> decltype(auto) iter4 = iter - 1;
193 assert((*iter4).data == 1);
194
195 std::same_as<ProxyIterator<Iter>> decltype(auto) iter5 = iter4 + 2;
196 assert((*iter5).data == 3);
197
198 std::same_as<ProxyIterator<Iter>> decltype(auto) iter6 = 3 + iter4;
199 assert((*iter6).data == 4);
200
201 std::same_as<std::iter_difference_t<Iter>> decltype(auto) n = iter6 - iter5;
202 assert(n == 1);
203
204 assert(iter4 < iter5);
205 assert(iter3 <= iter5);
206 assert(iter5 > iter4);
207 assert(iter6 >= iter4);
208 }
209
testProxyIterator()210 constexpr void testProxyIterator() {
211 // input iterator operations
212 {
213 testInputIteratorOperation<cpp20_input_iterator<int*>>();
214 testInputIteratorOperation<forward_iterator<int*>>();
215 testInputIteratorOperation<bidirectional_iterator<int*>>();
216 testInputIteratorOperation<random_access_iterator<int*>>();
217 testInputIteratorOperation<contiguous_iterator<int*>>();
218 }
219
220 // forward iterator operations
221 {
222 testForwardIteratorOperation<forward_iterator<int*>>();
223 testForwardIteratorOperation<bidirectional_iterator<int*>>();
224 testForwardIteratorOperation<random_access_iterator<int*>>();
225 testForwardIteratorOperation<contiguous_iterator<int*>>();
226 }
227
228 // bidirectional iterator operations
229 {
230 testBidirectionalIteratorOperation<bidirectional_iterator<int*>>();
231 testBidirectionalIteratorOperation<random_access_iterator<int*>>();
232 testBidirectionalIteratorOperation<contiguous_iterator<int*>>();
233 }
234
235 // random access iterator operations
236 {
237 testRandomAccessIteratorOperation<random_access_iterator<int*>>();
238 testRandomAccessIteratorOperation<contiguous_iterator<int*>>();
239 }
240 }
241
testProxyRange()242 constexpr void testProxyRange() {
243 int data[] = {3, 4, 5};
244 ProxyRange r{data};
245 std::same_as<ProxyIterator<int*>> decltype(auto) it = std::ranges::begin(r);
246 assert((*it).data == 3);
247 it += 3;
248 assert(it == std::ranges::end(r));
249 }
250
251 template <class Iter>
252 concept StdMoveWorks = requires(std::iter_value_t<Iter> val, Iter iter) { val = std::move(*iter); };
253
254 static_assert(StdMoveWorks<MoveOnly*>);
255 static_assert(!StdMoveWorks<ProxyIterator<MoveOnly*>>);
256
257 // although this "works" but it actually creates a copy instead of move
258 static_assert(StdMoveWorks<ProxyIterator<int*>>);
259
260 using std::swap;
261
262 template <class Iter>
263 concept SwapWorks = requires(Iter iter1, Iter iter2) { swap(*iter1, *iter2); };
264
265 static_assert(SwapWorks<int*>);
266 static_assert(!SwapWorks<ProxyIterator<int*>>);
267
test()268 constexpr bool test() {
269 testProxy();
270 testProxyIterator();
271 testProxyRange();
272
273 // iter_move
274 {
275 MoveOnly data[] = {5, 6, 7};
276 ProxyRange r{data};
277 auto it = r.begin();
278 std::iter_value_t<decltype(it)> moved = std::ranges::iter_move(it);
279 assert(moved.data.get() == 5);
280 }
281
282 // iter_swap
283 {
284 MoveOnly data[] = {5, 6, 7};
285 ProxyRange r{data};
286 auto it1 = r.begin();
287 auto it2 = it1 + 2;
288 std::ranges::iter_swap(it1, it2);
289 assert(data[0].get() == 7);
290 assert(data[2].get() == 5);
291 }
292
293 return true;
294 }
295
main(int,char **)296 int main(int, char**) {
297 test();
298 static_assert(test());
299
300 return 0;
301 }
302