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