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