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 //===----------------------------------------------------------------------===//
11 // UNSUPPORTED: c++03, c++11, c++14, c++17
12 // TODO: make `join_view` non-experimental once D2770 is implemented.
13 // UNSUPPORTED: !c++experimental
14 // UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
16 // template<bidirectional_iterator I1, sentinel_for<I1> S1, bidirectional_iterator I2>
17 // requires indirectly_copyable<I1, I2>
18 // constexpr ranges::copy_backward_result<I1, I2>
19 // ranges::copy_backward(I1 first, S1 last, I2 result);
20 // template<bidirectional_range R, bidirectional_iterator I>
21 // requires indirectly_copyable<iterator_t<R>, I>
22 // constexpr ranges::copy_backward_result<borrowed_iterator_t<R>, I>
23 // ranges::copy_backward(R&& r, I result);
32 #include "almost_satisfies_types.h"
33 #include "test_iterators.h"
35 template <class In
, class Out
= In
, class Sent
= sentinel_wrapper
<In
>>
36 concept HasCopyBackwardIt
= requires(In in
, Sent sent
, Out out
) { std::ranges::copy_backward(in
, sent
, out
); };
38 static_assert(HasCopyBackwardIt
<int*>);
39 static_assert(!HasCopyBackwardIt
<InputIteratorNotDerivedFrom
>);
40 static_assert(!HasCopyBackwardIt
<InputIteratorNotIndirectlyReadable
>);
41 static_assert(!HasCopyBackwardIt
<InputIteratorNotInputOrOutputIterator
>);
42 static_assert(!HasCopyBackwardIt
<int*, WeaklyIncrementableNotMovable
>);
43 struct NotIndirectlyCopyable
{};
44 static_assert(!HasCopyBackwardIt
<int*, NotIndirectlyCopyable
*>);
45 static_assert(!HasCopyBackwardIt
<int*, int*, SentinelForNotSemiregular
>);
46 static_assert(!HasCopyBackwardIt
<int*, int*, SentinelForNotWeaklyEqualityComparableWith
>);
48 template <class Range
, class Out
>
49 concept HasCopyBackwardR
= requires(Range range
, Out out
) { std::ranges::copy_backward(range
, out
); };
51 static_assert(HasCopyBackwardR
<std::array
<int, 10>, int*>);
52 static_assert(!HasCopyBackwardR
<InputRangeNotDerivedFrom
, int*>);
53 static_assert(!HasCopyBackwardR
<InputRangeNotIndirectlyReadable
, int*>);
54 static_assert(!HasCopyBackwardR
<InputRangeNotInputOrOutputIterator
, int*>);
55 static_assert(!HasCopyBackwardR
<WeaklyIncrementableNotMovable
, int*>);
56 static_assert(!HasCopyBackwardR
<UncheckedRange
<NotIndirectlyCopyable
*>, int*>);
57 static_assert(!HasCopyBackwardR
<InputRangeNotSentinelSemiregular
, int*>);
58 static_assert(!HasCopyBackwardR
<InputRangeNotSentinelEqualityComparableWith
, int*>);
60 static_assert(std::is_same_v
<std::ranges::copy_result
<int, long>, std::ranges::in_out_result
<int, long>>);
62 template <class In
, class Out
, class Sent
>
63 constexpr void test_iterators() {
66 std::array in
{1, 2, 3, 4};
67 std::array
<int, 4> out
;
68 std::same_as
<std::ranges::in_out_result
<In
, Out
>> auto ret
=
69 std::ranges::copy_backward(In(in
.data()), Sent(In(in
.data() + in
.size())), Out(out
.data() + out
.size()));
71 assert(base(ret
.in
) == in
.data() + in
.size());
72 assert(base(ret
.out
) == out
.data());
75 std::array in
{1, 2, 3, 4};
76 std::array
<int, 4> out
;
77 auto range
= std::ranges::subrange(In(in
.data()), Sent(In(in
.data() + in
.size())));
78 std::same_as
<std::ranges::in_out_result
<In
, Out
>> auto ret
=
79 std::ranges::copy_backward(range
, Out(out
.data() + out
.size()));
81 assert(base(ret
.in
) == in
.data() + in
.size());
82 assert(base(ret
.out
) == out
.data());
86 { // check that an empty range works
88 std::array
<int, 0> in
;
89 std::array
<int, 0> out
;
91 std::ranges::copy_backward(In(in
.data()), Sent(In(in
.data() + in
.size())), Out(out
.data() + out
.size()));
92 assert(base(ret
.in
) == in
.data() + in
.size());
93 assert(base(ret
.out
) == out
.data());
96 std::array
<int, 0> in
;
97 std::array
<int, 0> out
;
98 auto range
= std::ranges::subrange(In(in
.data()), Sent(In(in
.data() + in
.size())));
99 auto ret
= std::ranges::copy_backward(range
, Out(out
.data()));
100 assert(base(ret
.in
) == in
.data() + in
.size());
101 assert(base(ret
.out
) == out
.data());
106 template <class InContainer
, class OutContainer
, class In
, class Out
, class Sent
= In
>
107 constexpr void test_containers() {
109 InContainer in
{1, 2, 3, 4};
111 std::same_as
<std::ranges::in_out_result
<In
, Out
>> auto ret
=
112 std::ranges::copy_backward(In(in
.begin()), Sent(In(in
.end())), Out(out
.end()));
113 assert(std::ranges::equal(in
, out
));
114 assert(base(ret
.in
) == in
.end());
115 assert(base(ret
.out
) == out
.begin());
118 InContainer in
{1, 2, 3, 4};
120 auto range
= std::ranges::subrange(In(in
.begin()), Sent(In(in
.end())));
121 std::same_as
<std::ranges::in_out_result
<In
, Out
>> auto ret
= std::ranges::copy_backward(range
, Out(out
.end()));
122 assert(std::ranges::equal(in
, out
));
123 assert(base(ret
.in
) == in
.end());
124 assert(base(ret
.out
) == out
.begin());
128 template <class Iter
, class Sent
>
129 constexpr void test_join_view() {
130 auto to_subranges
= std::views::transform([](auto& vec
) {
131 return std::ranges::subrange(Iter(vec
.begin()), Sent(Iter(vec
.end())));
134 { // segmented -> contiguous
135 std::vector
<std::vector
<int>> vectors
= {};
136 auto range
= vectors
| to_subranges
;
137 std::vector
<std::ranges::subrange
<Iter
, Sent
>> subrange_vector(range
.begin(), range
.end());
138 std::array
<int, 0> arr
;
140 std::ranges::copy_backward(subrange_vector
| std::views::join
, arr
.end());
141 assert(std::ranges::equal(arr
, std::array
<int, 0>{}));
143 { // segmented -> contiguous
144 std::vector
<std::vector
<int>> vectors
= {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10}, {}};
145 auto range
= vectors
| to_subranges
;
146 std::vector
<std::ranges::subrange
<Iter
, Sent
>> subrange_vector(range
.begin(), range
.end());
147 std::array
<int, 10> arr
;
149 std::ranges::copy_backward(subrange_vector
| std::views::join
, arr
.end());
150 assert(std::ranges::equal(arr
, std::array
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}));
152 { // contiguous -> segmented
153 std::vector
<std::vector
<int>> vectors
= {{0, 0, 0, 0}, {0, 0}, {0, 0, 0, 0}, {}};
154 auto range
= vectors
| to_subranges
;
155 std::vector
<std::ranges::subrange
<Iter
, Sent
>> subrange_vector(range
.begin(), range
.end());
156 std::array arr
= {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
158 std::ranges::copy_backward(arr
, (subrange_vector
| std::views::join
).end());
159 assert(std::ranges::equal(subrange_vector
| std::views::join
, std::array
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}));
161 { // segmented -> segmented
162 std::vector
<std::vector
<int>> vectors
= {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10}, {}};
163 auto range1
= vectors
| to_subranges
;
164 std::vector
<std::ranges::subrange
<Iter
, Sent
>> subrange_vector(range1
.begin(), range1
.end());
165 std::vector
<std::vector
<int>> to_vectors
= {{0, 0, 0, 0}, {0, 0, 0, 0}, {}, {0, 0}};
166 auto range2
= to_vectors
| to_subranges
;
167 std::vector
<std::ranges::subrange
<Iter
, Sent
>> to_subrange_vector(range2
.begin(), range2
.end());
169 std::ranges::copy_backward(subrange_vector
| std::views::join
, (to_subrange_vector
| std::views::join
).end());
170 assert(std::ranges::equal(to_subrange_vector
| std::views::join
, std::array
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}));
175 constexpr bool is_proxy_iterator
= false;
177 template <class Iter
>
178 constexpr bool is_proxy_iterator
<ProxyIterator
<Iter
>> = true;
180 template <template <class> class InIter
, template <class> class OutIter
>
181 constexpr void test_sentinels() {
182 test_iterators
<InIter
<int*>, OutIter
<int*>, InIter
<int*>>();
183 test_iterators
<InIter
<int*>, OutIter
<int*>, sentinel_wrapper
<InIter
<int*>>>();
184 test_iterators
<InIter
<int*>, OutIter
<int*>, sized_sentinel
<InIter
<int*>>>();
186 if constexpr (!std::is_same_v
<InIter
<int*>, contiguous_iterator
<int*>> &&
187 !std::is_same_v
<OutIter
<int*>, contiguous_iterator
<int*>> &&
188 !std::is_same_v
<InIter
<int*>, ContiguousProxyIterator
<int*>> &&
189 !std::is_same_v
<OutIter
<int*>, ContiguousProxyIterator
<int*>>) {
190 if (!std::is_constant_evaluated()) {
191 test_containers
<std::deque
<int>,
193 InIter
<std::deque
<int>::iterator
>,
194 OutIter
<std::deque
<int>::iterator
>>();
195 test_containers
<std::deque
<int>,
197 InIter
<std::deque
<int>::iterator
>,
198 OutIter
<std::vector
<int>::iterator
>>();
199 test_containers
<std::vector
<int>,
201 InIter
<std::vector
<int>::iterator
>,
202 OutIter
<std::deque
<int>::iterator
>>();
203 test_containers
<std::vector
<int>,
205 InIter
<std::vector
<int>::iterator
>,
206 OutIter
<std::vector
<int>::iterator
>>();
208 if constexpr (!is_proxy_iterator
<InIter
<int*>>)
209 test_join_view
<InIter
<std::vector
<int>::iterator
>, InIter
<std::vector
<int>::iterator
>>();
213 template <template <class> class Out
>
214 constexpr void test_in_iterators() {
215 test_sentinels
<bidirectional_iterator
, Out
>();
216 test_sentinels
<random_access_iterator
, Out
>();
217 test_sentinels
<contiguous_iterator
, Out
>();
218 test_sentinels
<std::type_identity_t
, Out
>();
221 template <template <class> class Out
>
222 constexpr void test_proxy_in_iterators() {
223 test_sentinels
<BidirectionalProxyIterator
, Out
>();
224 test_sentinels
<RandomAccessProxyIterator
, Out
>();
225 test_sentinels
<ContiguousProxyIterator
, Out
>();
226 test_sentinels
<ProxyIterator
, Out
>();
229 constexpr bool test() {
230 test_in_iterators
<bidirectional_iterator
>();
231 test_in_iterators
<random_access_iterator
>();
232 test_in_iterators
<contiguous_iterator
>();
233 test_in_iterators
<std::type_identity_t
>();
235 test_proxy_in_iterators
<BidirectionalProxyIterator
>();
236 test_proxy_in_iterators
<RandomAccessProxyIterator
>();
237 test_proxy_in_iterators
<ContiguousProxyIterator
>();
239 { // check that ranges::dangling is returned
240 std::array
<int, 4> out
;
241 std::same_as
<std::ranges::in_out_result
<std::ranges::dangling
, int*>> auto ret
=
242 std::ranges::copy_backward(std::array
{1, 2, 3, 4}, out
.data() + out
.size());
243 assert(ret
.out
== out
.data());
244 assert((out
== std::array
{1, 2, 3, 4}));
247 { // check that an iterator is returned with a borrowing range
248 std::array in
{1, 2, 3, 4};
249 std::array
<int, 4> out
;
250 std::same_as
<std::ranges::in_out_result
<int*, int*>> auto ret
=
251 std::ranges::copy_backward(std::views::all(in
), out
.data() + out
.size());
252 assert(ret
.in
== in
.data() + in
.size());
253 assert(ret
.out
== out
.data());
257 { // check that every element is copied exactly once
260 constexpr CopyOnce() = default;
261 constexpr CopyOnce(const CopyOnce
& other
) = delete;
262 constexpr CopyOnce
& operator=(const CopyOnce
& other
) {
263 assert(!other
.copied
);
269 std::array
<CopyOnce
, 4> in
{};
270 std::array
<CopyOnce
, 4> out
{};
271 auto ret
= std::ranges::copy_backward(in
.begin(), in
.end(), out
.end());
272 assert(ret
.in
== in
.end());
273 assert(ret
.out
== out
.begin());
274 assert(std::all_of(out
.begin(), out
.end(), [](const auto& e
) { return e
.copied
; }));
277 std::array
<CopyOnce
, 4> in
{};
278 std::array
<CopyOnce
, 4> out
{};
279 auto ret
= std::ranges::copy_backward(in
, out
.end());
280 assert(ret
.in
== in
.end());
281 assert(ret
.out
== out
.begin());
282 assert(std::all_of(out
.begin(), out
.end(), [](const auto& e
) { return e
.copied
; }));
286 { // check that the range is copied backwards
287 struct OnlyBackwardsCopyable
{
288 OnlyBackwardsCopyable
* next
= nullptr;
289 bool canCopy
= false;
290 OnlyBackwardsCopyable() = default;
291 constexpr OnlyBackwardsCopyable
& operator=(const OnlyBackwardsCopyable
&) {
294 next
->canCopy
= true;
299 std::array
<OnlyBackwardsCopyable
, 3> in
{};
300 std::array
<OnlyBackwardsCopyable
, 3> out
{};
301 out
[1].next
= &out
[0];
302 out
[2].next
= &out
[1];
303 out
[2].canCopy
= true;
304 auto ret
= std::ranges::copy_backward(in
, out
.end());
305 assert(ret
.in
== in
.end());
306 assert(ret
.out
== out
.begin());
307 assert(out
[0].canCopy
);
308 assert(out
[1].canCopy
);
309 assert(out
[2].canCopy
);
312 std::array
<OnlyBackwardsCopyable
, 3> in
{};
313 std::array
<OnlyBackwardsCopyable
, 3> out
{};
314 out
[1].next
= &out
[0];
315 out
[2].next
= &out
[1];
316 out
[2].canCopy
= true;
317 auto ret
= std::ranges::copy_backward(in
.begin(), in
.end(), out
.end());
318 assert(ret
.in
== in
.end());
319 assert(ret
.out
== out
.begin());
320 assert(out
[0].canCopy
);
321 assert(out
[1].canCopy
);
322 assert(out
[2].canCopy
);
329 int main(int, char**) {
331 static_assert(test());