1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: c++03, c++11, c++14, c++17
12 #include "test_iterators.h"
16 constexpr void testProxy() {
23 // constructor reference
27 assert(&p
.data
== &i
);
30 // constructor conversion
38 assert(&(p3
.data
) == &(p2
.data
));
41 Proxy
<MoveOnly
&&> p4
= std::move(m1
);
43 Proxy
<MoveOnly
> p5
= std::move(p4
);
44 assert(p5
.data
.get() == 8);
55 Proxy
<MoveOnly
&&> p3
= std::move(m1
);
56 Proxy
<MoveOnly
> p4
{MoveOnly
{9}};
58 assert(p4
.data
.get() == 8);
60 // `T` is a reference type.
61 int i
= 5, j
= 6, k
= 7, x
= 8;
63 // `Other` is a prvalue.
66 // `Other` is a const lvalue.
67 const Proxy
<int&> p_ref
{k
};
70 // `Other` is an xvalue.
80 const Proxy
<int&> p1
{i
};
81 const Proxy
<int&> p2
{j
};
87 Proxy
<MoveOnly
&&> p3
= std::move(m1
);
88 const Proxy
<MoveOnly
&&> p4
= std::move(m2
);
90 assert(p4
.data
.get() == 8);
100 // Comparing `T` and `T&`.
102 Proxy
<int&> p_ref
{i
};
103 Proxy
<const int&> p_cref
{j
};
105 assert(p2
== p_cref
);
107 assert(p_cref
== p2
);
108 assert(p_ref
== p_ref
);
109 assert(p_cref
== p_cref
);
110 assert(p_ref
!= p_cref
);
114 static_assert(std::input_iterator
<ProxyIterator
<cpp20_input_iterator
<int*>>>);
115 static_assert(!std::forward_iterator
<ProxyIterator
<cpp20_input_iterator
<int*>>>);
117 static_assert(std::forward_iterator
<ProxyIterator
<forward_iterator
<int*>>>);
118 static_assert(!std::bidirectional_iterator
<ProxyIterator
<forward_iterator
<int*>>>);
120 static_assert(std::bidirectional_iterator
<ProxyIterator
<bidirectional_iterator
<int*>>>);
121 static_assert(!std::random_access_iterator
<ProxyIterator
<bidirectional_iterator
<int*>>>);
123 static_assert(std::random_access_iterator
<ProxyIterator
<random_access_iterator
<int*>>>);
124 static_assert(!std::contiguous_iterator
<ProxyIterator
<random_access_iterator
<int*>>>);
126 static_assert(std::random_access_iterator
<ProxyIterator
<contiguous_iterator
<int*>>>);
127 static_assert(!std::contiguous_iterator
<ProxyIterator
<contiguous_iterator
<int*>>>);
129 template <class Iter
>
130 constexpr void testInputIteratorOperation() {
132 ProxyIterator
<Iter
> iter
{Iter
{data
}};
133 sentinel_wrapper
<ProxyIterator
<Iter
>> sent
{ProxyIterator
<Iter
>{Iter
{data
+ 2}}};
135 std::same_as
<Proxy
<int&>> decltype(auto) result
= *iter
;
136 assert(result
.data
== 1);
137 auto& iter2
= ++iter
;
138 static_assert(std::is_same_v
<decltype(++iter
), ProxyIterator
<Iter
>&>);
139 assert(&iter2
== &iter
);
140 assert((*iter
).data
== 2);
142 assert(iter
== sent
);
145 template <class Iter
>
146 constexpr void testForwardIteratorOperation() {
148 ProxyIterator
<Iter
> iter
{Iter
{data
}};
150 std::same_as
<ProxyIterator
<Iter
>> decltype(auto) it2
= iter
++;
151 assert((*it2
).data
== 1);
152 assert((*iter
).data
== 2);
155 template <class Iter
>
156 constexpr void testBidirectionalIteratorOperation() {
158 ProxyIterator
<Iter
> iter
{Iter
{data
}};
160 assert((*iter
).data
== 2);
162 auto& iter2
= --iter
;
163 static_assert(std::is_same_v
<decltype(--iter
), ProxyIterator
<Iter
>&>);
164 assert(&iter2
== &iter
);
165 assert((*iter
).data
== 1);
168 std::same_as
<ProxyIterator
<Iter
>> decltype(auto) iter3
= iter
--;
169 assert((*iter
).data
== 1);
170 assert((*iter3
).data
== 2);
173 template <class Iter
>
174 constexpr void testRandomAccessIteratorOperation() {
175 int data
[] = {1, 2, 3, 4, 5};
176 ProxyIterator
<Iter
> iter
{Iter
{data
}};
178 auto& iter2
= iter
+= 2;
179 static_assert(std::is_same_v
<decltype(iter
+= 2), ProxyIterator
<Iter
>&>);
180 assert(&iter2
== &iter
);
181 assert((*iter
).data
== 3);
183 auto& iter3
= iter
-= 1;
184 static_assert(std::is_same_v
<decltype(iter
-= 1), ProxyIterator
<Iter
>&>);
185 assert(&iter3
== &iter
);
186 assert((*iter
).data
== 2);
188 std::same_as
<Proxy
<int&>> decltype(auto) r
= iter
[2];
191 std::same_as
<ProxyIterator
<Iter
>> decltype(auto) iter4
= iter
- 1;
192 assert((*iter4
).data
== 1);
194 std::same_as
<ProxyIterator
<Iter
>> decltype(auto) iter5
= iter4
+ 2;
195 assert((*iter5
).data
== 3);
197 std::same_as
<ProxyIterator
<Iter
>> decltype(auto) iter6
= 3 + iter4
;
198 assert((*iter6
).data
== 4);
200 std::same_as
<std::iter_difference_t
<Iter
>> decltype(auto) n
= iter6
- iter5
;
203 assert(iter4
< iter5
);
204 assert(iter3
<= iter5
);
205 assert(iter5
> iter4
);
206 assert(iter6
>= iter4
);
209 constexpr void testProxyIterator() {
210 // input iterator operations
212 testInputIteratorOperation
<cpp20_input_iterator
<int*>>();
213 testInputIteratorOperation
<forward_iterator
<int*>>();
214 testInputIteratorOperation
<bidirectional_iterator
<int*>>();
215 testInputIteratorOperation
<random_access_iterator
<int*>>();
216 testInputIteratorOperation
<contiguous_iterator
<int*>>();
219 // forward iterator operations
221 testForwardIteratorOperation
<forward_iterator
<int*>>();
222 testForwardIteratorOperation
<bidirectional_iterator
<int*>>();
223 testForwardIteratorOperation
<random_access_iterator
<int*>>();
224 testForwardIteratorOperation
<contiguous_iterator
<int*>>();
227 // bidirectional iterator operations
229 testBidirectionalIteratorOperation
<bidirectional_iterator
<int*>>();
230 testBidirectionalIteratorOperation
<random_access_iterator
<int*>>();
231 testBidirectionalIteratorOperation
<contiguous_iterator
<int*>>();
234 // random access iterator operations
236 testRandomAccessIteratorOperation
<random_access_iterator
<int*>>();
237 testRandomAccessIteratorOperation
<contiguous_iterator
<int*>>();
241 constexpr void testProxyRange() {
242 int data
[] = {3, 4, 5};
244 std::same_as
<ProxyIterator
<int*>> decltype(auto) it
= std::ranges::begin(r
);
245 assert((*it
).data
== 3);
247 assert(it
== std::ranges::end(r
));
250 template <class Iter
>
251 concept StdMoveWorks
= requires(std::iter_value_t
<Iter
> val
, Iter iter
) { val
= std::move(*iter
); };
253 static_assert(StdMoveWorks
<MoveOnly
*>);
254 static_assert(!StdMoveWorks
<ProxyIterator
<MoveOnly
*>>);
256 // although this "works" but it actually creates a copy instead of move
257 static_assert(StdMoveWorks
<ProxyIterator
<int*>>);
261 template <class Iter
>
262 concept SwapWorks
= requires(Iter iter1
, Iter iter2
) { swap(*iter1
, *iter2
); };
264 static_assert(SwapWorks
<int*>);
265 static_assert(!SwapWorks
<ProxyIterator
<int*>>);
267 constexpr bool test() {
274 MoveOnly data
[] = {5, 6, 7};
277 std::iter_value_t
<decltype(it
)> moved
= std::ranges::iter_move(it
);
278 assert(moved
.data
.get() == 5);
283 MoveOnly data
[] = {5, 6, 7};
285 auto it1
= r
.begin();
287 std::ranges::iter_swap(it1
, it2
);
288 assert(data
[0].get() == 7);
289 assert(data
[2].get() == 5);
295 int main(int, char**) {
297 static_assert(test());