xref: /llvm-project/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.pass.cpp (revision d05bada59205b9bcf1195a6eac7e09b721e3b79b)
12c3bbac0SNikolas Klauser //===----------------------------------------------------------------------===//
22c3bbac0SNikolas Klauser //
32c3bbac0SNikolas Klauser // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42c3bbac0SNikolas Klauser // See https://llvm.org/LICENSE.txt for license information.
52c3bbac0SNikolas Klauser // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
62c3bbac0SNikolas Klauser //
72c3bbac0SNikolas Klauser //===----------------------------------------------------------------------===//
82c3bbac0SNikolas Klauser 
92c3bbac0SNikolas Klauser // <algorithm>
102c3bbac0SNikolas Klauser 
112c3bbac0SNikolas Klauser // UNSUPPORTED: c++03, c++11, c++14, c++17
12520c7fbbSLouis Dionne // UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
132c3bbac0SNikolas Klauser 
142c3bbac0SNikolas Klauser // template<input_iterator I, sentinel_for<I> S, weakly_incrementable O>
152c3bbac0SNikolas Klauser //   requires indirectly_movable<I, O>
162c3bbac0SNikolas Klauser //   constexpr ranges::move_result<I, O>
172c3bbac0SNikolas Klauser //     ranges::move(I first, S last, O result);
182c3bbac0SNikolas Klauser // template<input_range R, weakly_incrementable O>
192c3bbac0SNikolas Klauser //   requires indirectly_movable<iterator_t<R>, O>
202c3bbac0SNikolas Klauser //   constexpr ranges::move_result<borrowed_iterator_t<R>, O>
212c3bbac0SNikolas Klauser //     ranges::move(R&& r, O result);
222c3bbac0SNikolas Klauser 
232c3bbac0SNikolas Klauser #include <algorithm>
242c3bbac0SNikolas Klauser #include <array>
252c3bbac0SNikolas Klauser #include <cassert>
26c9080145SNikolas Klauser #include <deque>
276f36ead5SLouis Dionne #include <iterator>
282c3bbac0SNikolas Klauser #include <ranges>
29c9080145SNikolas Klauser #include <vector>
302c3bbac0SNikolas Klauser 
312c3bbac0SNikolas Klauser #include "almost_satisfies_types.h"
322c3bbac0SNikolas Klauser #include "MoveOnly.h"
332c3bbac0SNikolas Klauser #include "test_iterators.h"
342c3bbac0SNikolas Klauser 
352c3bbac0SNikolas Klauser template <class In, class Out = In, class Sent = sentinel_wrapper<In>>
362c3bbac0SNikolas Klauser concept HasMoveIt = requires(In in, Sent sent, Out out) { std::ranges::move(in, sent, out); };
372c3bbac0SNikolas Klauser 
382c3bbac0SNikolas Klauser static_assert(HasMoveIt<int*>);
392c3bbac0SNikolas Klauser static_assert(!HasMoveIt<InputIteratorNotDerivedFrom>);
402c3bbac0SNikolas Klauser static_assert(!HasMoveIt<InputIteratorNotIndirectlyReadable>);
412c3bbac0SNikolas Klauser static_assert(!HasMoveIt<InputIteratorNotInputOrOutputIterator>);
422c3bbac0SNikolas Klauser static_assert(!HasMoveIt<int*, WeaklyIncrementableNotMovable>);
432c3bbac0SNikolas Klauser struct NotIndirectlyMovable {};
442c3bbac0SNikolas Klauser static_assert(!HasMoveIt<int*, NotIndirectlyMovable*>);
452c3bbac0SNikolas Klauser static_assert(!HasMoveIt<int*, int*, SentinelForNotSemiregular>);
462c3bbac0SNikolas Klauser static_assert(!HasMoveIt<int*, int*, SentinelForNotWeaklyEqualityComparableWith>);
472c3bbac0SNikolas Klauser 
482c3bbac0SNikolas Klauser template <class Range, class Out>
492c3bbac0SNikolas Klauser concept HasMoveR = requires(Range range, Out out) { std::ranges::move(range, out); };
502c3bbac0SNikolas Klauser 
512c3bbac0SNikolas Klauser static_assert(HasMoveR<std::array<int, 10>, int*>);
522c3bbac0SNikolas Klauser static_assert(!HasMoveR<InputRangeNotDerivedFrom, int*>);
532c3bbac0SNikolas Klauser static_assert(!HasMoveR<InputRangeNotIndirectlyReadable, int*>);
542c3bbac0SNikolas Klauser static_assert(!HasMoveR<InputRangeNotInputOrOutputIterator, int*>);
552c3bbac0SNikolas Klauser static_assert(!HasMoveR<WeaklyIncrementableNotMovable, int*>);
562c3bbac0SNikolas Klauser static_assert(!HasMoveR<UncheckedRange<NotIndirectlyMovable*>, int*>);
572c3bbac0SNikolas Klauser static_assert(!HasMoveR<InputRangeNotSentinelSemiregular, int*>);
582c3bbac0SNikolas Klauser static_assert(!HasMoveR<InputRangeNotSentinelEqualityComparableWith, int*>);
592c3bbac0SNikolas Klauser static_assert(!HasMoveR<UncheckedRange<int*>, WeaklyIncrementableNotMovable>);
602c3bbac0SNikolas Klauser 
612c3bbac0SNikolas Klauser static_assert(std::is_same_v<std::ranges::move_result<int, long>, std::ranges::in_out_result<int, long>>);
622c3bbac0SNikolas Klauser 
632c3bbac0SNikolas Klauser template <class In, class Out, class Sent, int N>
test(std::array<int,N> in)642c3bbac0SNikolas Klauser constexpr void test(std::array<int, N> in) {
652c3bbac0SNikolas Klauser   {
662c3bbac0SNikolas Klauser     std::array<int, N> out;
672c3bbac0SNikolas Klauser     std::same_as<std::ranges::in_out_result<In, Out>> decltype(auto) ret =
682c3bbac0SNikolas Klauser       std::ranges::move(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data()));
692c3bbac0SNikolas Klauser     assert(in == out);
702c3bbac0SNikolas Klauser     assert(base(ret.in) == in.data() + in.size());
712c3bbac0SNikolas Klauser     assert(base(ret.out) == out.data() + out.size());
722c3bbac0SNikolas Klauser   }
732c3bbac0SNikolas Klauser   {
742c3bbac0SNikolas Klauser     std::array<int, N> out;
752c3bbac0SNikolas Klauser     auto range = std::ranges::subrange(In(in.data()), Sent(In(in.data() + in.size())));
762c3bbac0SNikolas Klauser     std::same_as<std::ranges::in_out_result<In, Out>> decltype(auto) ret =
772c3bbac0SNikolas Klauser         std::ranges::move(range, Out(out.data()));
782c3bbac0SNikolas Klauser     assert(in == out);
792c3bbac0SNikolas Klauser     assert(base(ret.in) == in.data() + in.size());
802c3bbac0SNikolas Klauser     assert(base(ret.out) == out.data() + out.size());
812c3bbac0SNikolas Klauser   }
822c3bbac0SNikolas Klauser }
832c3bbac0SNikolas Klauser 
84c9080145SNikolas Klauser template <class InContainer, class OutContainer, class In, class Out, class Sent = In>
test_containers()85c9080145SNikolas Klauser constexpr void test_containers() {
86c9080145SNikolas Klauser   {
87c9080145SNikolas Klauser     InContainer in {1, 2, 3, 4};
88c9080145SNikolas Klauser     OutContainer out(4);
89c9080145SNikolas Klauser     std::same_as<std::ranges::in_out_result<In, Out>> auto ret =
90c9080145SNikolas Klauser       std::ranges::move(In(in.begin()), Sent(In(in.end())), Out(out.begin()));
91c9080145SNikolas Klauser     assert(std::ranges::equal(in, out));
92c9080145SNikolas Klauser     assert(base(ret.in) == in.end());
93c9080145SNikolas Klauser     assert(base(ret.out) == out.end());
94c9080145SNikolas Klauser   }
95c9080145SNikolas Klauser   {
96c9080145SNikolas Klauser     InContainer in {1, 2, 3, 4};
97c9080145SNikolas Klauser     OutContainer out(4);
98c9080145SNikolas Klauser     auto range = std::ranges::subrange(In(in.begin()), Sent(In(in.end())));
99c9080145SNikolas Klauser     std::same_as<std::ranges::in_out_result<In, Out>> auto ret = std::ranges::move(range, Out(out.begin()));
100c9080145SNikolas Klauser     assert(std::ranges::equal(in, out));
101c9080145SNikolas Klauser     assert(base(ret.in) == in.end());
102c9080145SNikolas Klauser     assert(base(ret.out) == out.end());
103c9080145SNikolas Klauser   }
104c9080145SNikolas Klauser }
105c9080145SNikolas Klauser 
1062c3bbac0SNikolas Klauser template <class In, class Out, class Sent = In>
test_iterators()1072c3bbac0SNikolas Klauser constexpr void test_iterators() {
1082c3bbac0SNikolas Klauser   // simple test
1092c3bbac0SNikolas Klauser   test<In, Out, Sent, 4>({1, 2, 3, 4});
1102c3bbac0SNikolas Klauser   // check that an empty range works
1112c3bbac0SNikolas Klauser   test<In, Out, Sent, 0>({});
1122c3bbac0SNikolas Klauser }
1132c3bbac0SNikolas Klauser 
114c9080145SNikolas Klauser template <template <class> class In, template <class> class Out>
test_sentinels()115c9080145SNikolas Klauser constexpr void test_sentinels() {
116c9080145SNikolas Klauser   test_iterators<In<int*>, Out<int*>>();
117c9080145SNikolas Klauser   test_iterators<In<int*>, Out<int*>, sized_sentinel<In<int*>>>();
118c9080145SNikolas Klauser   test_iterators<In<int*>, Out<int*>, sentinel_wrapper<In<int*>>>();
119c9080145SNikolas Klauser 
120c9080145SNikolas Klauser   if (!std::is_constant_evaluated()) {
121c9080145SNikolas Klauser     if constexpr (!std::is_same_v<In<int*>, contiguous_iterator<int*>> &&
122c9080145SNikolas Klauser                   !std::is_same_v<Out<int*>, contiguous_iterator<int*>> &&
123c9080145SNikolas Klauser                   !std::is_same_v<In<int*>, ContiguousProxyIterator<int*>> &&
124c9080145SNikolas Klauser                   !std::is_same_v<Out<int*>, ContiguousProxyIterator<int*>>) {
125c9080145SNikolas Klauser       test_containers<std::deque<int>,
126c9080145SNikolas Klauser                       std::deque<int>,
127c9080145SNikolas Klauser                       In<std::deque<int>::iterator>,
128c9080145SNikolas Klauser                       Out<std::deque<int>::iterator>>();
129c9080145SNikolas Klauser       test_containers<std::deque<int>,
130c9080145SNikolas Klauser                       std::vector<int>,
131c9080145SNikolas Klauser                       In<std::deque<int>::iterator>,
132c9080145SNikolas Klauser                       Out<std::vector<int>::iterator>>();
133c9080145SNikolas Klauser       test_containers<std::vector<int>,
134c9080145SNikolas Klauser                       std::deque<int>,
135c9080145SNikolas Klauser                       In<std::vector<int>::iterator>,
136c9080145SNikolas Klauser                       Out<std::deque<int>::iterator>>();
137c9080145SNikolas Klauser       test_containers<std::vector<int>,
138c9080145SNikolas Klauser                       std::vector<int>,
139c9080145SNikolas Klauser                       In<std::vector<int>::iterator>,
140c9080145SNikolas Klauser                       Out<std::vector<int>::iterator>>();
141c9080145SNikolas Klauser     }
142c9080145SNikolas Klauser   }
1432c3bbac0SNikolas Klauser }
1442c3bbac0SNikolas Klauser 
145c9080145SNikolas Klauser template <template <class> class Out>
test_in_iterators()146c9080145SNikolas Klauser constexpr void test_in_iterators() {
147c9080145SNikolas Klauser   test_iterators<cpp20_input_iterator<int*>, Out<int*>, sentinel_wrapper<cpp20_input_iterator<int*>>>();
148c9080145SNikolas Klauser   test_sentinels<forward_iterator, Out>();
149c9080145SNikolas Klauser   test_sentinels<bidirectional_iterator, Out>();
150c9080145SNikolas Klauser   test_sentinels<random_access_iterator, Out>();
151c9080145SNikolas Klauser   test_sentinels<contiguous_iterator, Out>();
152c9080145SNikolas Klauser   test_sentinels<std::type_identity_t, Out>();
153c9080145SNikolas Klauser }
154c9080145SNikolas Klauser 
155c9080145SNikolas Klauser template <template <class> class Out>
test_proxy_in_iterators()156a81cc1fcSHui Xie constexpr void test_proxy_in_iterators() {
157c9080145SNikolas Klauser   test_iterators<ProxyIterator<cpp20_input_iterator<int*>>,
158c9080145SNikolas Klauser                  Out<int*>,
159c9080145SNikolas Klauser                  sentinel_wrapper<ProxyIterator<cpp20_input_iterator<int*>>>>();
160c9080145SNikolas Klauser   test_sentinels<ForwardProxyIterator, Out>();
161c9080145SNikolas Klauser   test_sentinels<BidirectionalProxyIterator, Out>();
162c9080145SNikolas Klauser   test_sentinels<RandomAccessProxyIterator, Out>();
163c9080145SNikolas Klauser   test_sentinels<ContiguousProxyIterator, Out>();
164c9080145SNikolas Klauser   test_sentinels<ProxyIterator, Out>();
165a81cc1fcSHui Xie }
166a81cc1fcSHui Xie 
1672c3bbac0SNikolas Klauser struct IteratorWithMoveIter {
1682c3bbac0SNikolas Klauser   using value_type = int;
1692c3bbac0SNikolas Klauser   using difference_type = int;
1702c3bbac0SNikolas Klauser   explicit IteratorWithMoveIter() = default;
1712c3bbac0SNikolas Klauser   int* ptr;
IteratorWithMoveIterIteratorWithMoveIter1722c3bbac0SNikolas Klauser   constexpr IteratorWithMoveIter(int* ptr_) : ptr(ptr_) {}
1732c3bbac0SNikolas Klauser 
1742c3bbac0SNikolas Klauser   constexpr int& operator*() const; // iterator with iter_move should not be dereferenced
1752c3bbac0SNikolas Klauser 
operator ++IteratorWithMoveIter1762c3bbac0SNikolas Klauser   constexpr IteratorWithMoveIter& operator++() { ++ptr; return *this; }
operator ++IteratorWithMoveIter1772c3bbac0SNikolas Klauser   constexpr IteratorWithMoveIter operator++(int) { auto ret = *this; ++*this; return ret; }
1782c3bbac0SNikolas Klauser 
iter_move(const IteratorWithMoveIter &)1792c3bbac0SNikolas Klauser   friend constexpr int iter_move(const IteratorWithMoveIter&) { return 42; }
1802c3bbac0SNikolas Klauser 
1812c3bbac0SNikolas Klauser   constexpr bool operator==(const IteratorWithMoveIter& other) const = default;
1822c3bbac0SNikolas Klauser };
1832c3bbac0SNikolas Klauser 
184c9080145SNikolas Klauser // cpp17_intput_iterator has a defaulted template argument
185c9080145SNikolas Klauser template <class Iter>
186c9080145SNikolas Klauser using Cpp17InIter = cpp17_input_iterator<Iter>;
1872c3bbac0SNikolas Klauser 
test()188c9080145SNikolas Klauser constexpr bool test() {
189c9080145SNikolas Klauser   test_in_iterators<cpp17_output_iterator>();
190c9080145SNikolas Klauser   test_in_iterators<cpp20_output_iterator>();
191c9080145SNikolas Klauser   test_in_iterators<Cpp17InIter>();
192c9080145SNikolas Klauser   test_in_iterators<cpp20_input_iterator>();
193c9080145SNikolas Klauser   test_in_iterators<forward_iterator>();
194c9080145SNikolas Klauser   test_in_iterators<bidirectional_iterator>();
195c9080145SNikolas Klauser   test_in_iterators<random_access_iterator>();
196c9080145SNikolas Klauser   test_in_iterators<contiguous_iterator>();
197c9080145SNikolas Klauser   test_in_iterators<std::type_identity_t>();
198c9080145SNikolas Klauser 
199c9080145SNikolas Klauser   test_proxy_in_iterators<Cpp20InputProxyIterator>();
200c9080145SNikolas Klauser   test_proxy_in_iterators<ForwardProxyIterator>();
201c9080145SNikolas Klauser   test_proxy_in_iterators<BidirectionalProxyIterator>();
202c9080145SNikolas Klauser   test_proxy_in_iterators<RandomAccessProxyIterator>();
203c9080145SNikolas Klauser   test_proxy_in_iterators<ContiguousProxyIterator>();
204c9080145SNikolas Klauser   test_proxy_in_iterators<ProxyIterator>();
205a81cc1fcSHui Xie 
2062c3bbac0SNikolas Klauser   { // check that a move-only type works
2076f36ead5SLouis Dionne     // When non-trivial
2082c3bbac0SNikolas Klauser     {
2092c3bbac0SNikolas Klauser       MoveOnly a[] = {1, 2, 3};
2102c3bbac0SNikolas Klauser       MoveOnly b[3];
2112c3bbac0SNikolas Klauser       std::ranges::move(a, std::begin(b));
2122c3bbac0SNikolas Klauser       assert(b[0].get() == 1);
2132c3bbac0SNikolas Klauser       assert(b[1].get() == 2);
2142c3bbac0SNikolas Klauser       assert(b[2].get() == 3);
2152c3bbac0SNikolas Klauser     }
2162c3bbac0SNikolas Klauser     {
2172c3bbac0SNikolas Klauser       MoveOnly a[] = {1, 2, 3};
2182c3bbac0SNikolas Klauser       MoveOnly b[3];
2192c3bbac0SNikolas Klauser       std::ranges::move(std::begin(a), std::end(a), std::begin(b));
2202c3bbac0SNikolas Klauser       assert(b[0].get() == 1);
2212c3bbac0SNikolas Klauser       assert(b[1].get() == 2);
2222c3bbac0SNikolas Klauser       assert(b[2].get() == 3);
2232c3bbac0SNikolas Klauser     }
2246f36ead5SLouis Dionne 
2256f36ead5SLouis Dionne     // When trivial
2266f36ead5SLouis Dionne     {
2276f36ead5SLouis Dionne       TrivialMoveOnly a[] = {1, 2, 3};
2286f36ead5SLouis Dionne       TrivialMoveOnly b[3];
2296f36ead5SLouis Dionne       std::ranges::move(a, std::begin(b));
2306f36ead5SLouis Dionne       assert(b[0].get() == 1);
2316f36ead5SLouis Dionne       assert(b[1].get() == 2);
2326f36ead5SLouis Dionne       assert(b[2].get() == 3);
2336f36ead5SLouis Dionne     }
2346f36ead5SLouis Dionne     {
2356f36ead5SLouis Dionne       TrivialMoveOnly a[] = {1, 2, 3};
2366f36ead5SLouis Dionne       TrivialMoveOnly b[3];
2376f36ead5SLouis Dionne       std::ranges::move(std::begin(a), std::end(a), std::begin(b));
2386f36ead5SLouis Dionne       assert(b[0].get() == 1);
2396f36ead5SLouis Dionne       assert(b[1].get() == 2);
2406f36ead5SLouis Dionne       assert(b[2].get() == 3);
2416f36ead5SLouis Dionne     }
2422c3bbac0SNikolas Klauser   }
2432c3bbac0SNikolas Klauser 
244a81cc1fcSHui Xie   { // check that a move-only type works for ProxyIterator
245a81cc1fcSHui Xie     {
246a81cc1fcSHui Xie       MoveOnly a[] = {1, 2, 3};
247a81cc1fcSHui Xie       MoveOnly b[3];
248a81cc1fcSHui Xie       ProxyRange proxyA{a};
249a81cc1fcSHui Xie       ProxyRange proxyB{b};
250a81cc1fcSHui Xie       std::ranges::move(proxyA, std::begin(proxyB));
251a81cc1fcSHui Xie       assert(b[0].get() == 1);
252a81cc1fcSHui Xie       assert(b[1].get() == 2);
253a81cc1fcSHui Xie       assert(b[2].get() == 3);
254a81cc1fcSHui Xie     }
255a81cc1fcSHui Xie     {
256a81cc1fcSHui Xie       MoveOnly a[] = {1, 2, 3};
257a81cc1fcSHui Xie       MoveOnly b[3];
258a81cc1fcSHui Xie       ProxyRange proxyA{a};
259a81cc1fcSHui Xie       ProxyRange proxyB{b};
260a81cc1fcSHui Xie       std::ranges::move(std::begin(proxyA), std::end(proxyA), std::begin(proxyB));
261a81cc1fcSHui Xie       assert(b[0].get() == 1);
262a81cc1fcSHui Xie       assert(b[1].get() == 2);
263a81cc1fcSHui Xie       assert(b[2].get() == 3);
264a81cc1fcSHui Xie     }
265a81cc1fcSHui Xie   }
266a81cc1fcSHui Xie 
2672c3bbac0SNikolas Klauser   { // check that ranges::dangling is returned
2682c3bbac0SNikolas Klauser     std::array<int, 4> out;
2692c3bbac0SNikolas Klauser     std::same_as<std::ranges::in_out_result<std::ranges::dangling, int*>> decltype(auto) ret =
2702c3bbac0SNikolas Klauser       std::ranges::move(std::array {1, 2, 3, 4}, out.data());
2712c3bbac0SNikolas Klauser     assert(ret.out == out.data() + 4);
2722c3bbac0SNikolas Klauser     assert((out == std::array{1, 2, 3, 4}));
2732c3bbac0SNikolas Klauser   }
2742c3bbac0SNikolas Klauser 
2752c3bbac0SNikolas Klauser   { // check that an iterator is returned with a borrowing range
2762c3bbac0SNikolas Klauser     std::array in {1, 2, 3, 4};
2772c3bbac0SNikolas Klauser     std::array<int, 4> out;
278*d05bada5SDuo Wang     std::same_as<std::ranges::in_out_result<std::array<int, 4>::iterator, int*>> decltype(auto) ret =
2792c3bbac0SNikolas Klauser         std::ranges::move(std::views::all(in), out.data());
280*d05bada5SDuo Wang     assert(ret.in == in.end());
2812c3bbac0SNikolas Klauser     assert(ret.out == out.data() + 4);
2822c3bbac0SNikolas Klauser     assert(in == out);
2832c3bbac0SNikolas Klauser   }
2842c3bbac0SNikolas Klauser 
2852c3bbac0SNikolas Klauser   { // check that every element is moved exactly once
2862c3bbac0SNikolas Klauser     struct MoveOnce {
2872c3bbac0SNikolas Klauser       bool moved = false;
2882c3bbac0SNikolas Klauser       constexpr MoveOnce() = default;
2892c3bbac0SNikolas Klauser       constexpr MoveOnce(const MoveOnce& other) = delete;
2902c3bbac0SNikolas Klauser       constexpr MoveOnce& operator=(MoveOnce&& other) {
2912c3bbac0SNikolas Klauser         assert(!other.moved);
2922c3bbac0SNikolas Klauser         moved = true;
2932c3bbac0SNikolas Klauser         return *this;
2942c3bbac0SNikolas Klauser       }
2952c3bbac0SNikolas Klauser     };
2962c3bbac0SNikolas Klauser     {
2972c3bbac0SNikolas Klauser       std::array<MoveOnce, 4> in {};
2982c3bbac0SNikolas Klauser       std::array<MoveOnce, 4> out {};
2992c3bbac0SNikolas Klauser       auto ret = std::ranges::move(in.begin(), in.end(), out.begin());
3002c3bbac0SNikolas Klauser       assert(ret.in == in.end());
3012c3bbac0SNikolas Klauser       assert(ret.out == out.end());
3022c3bbac0SNikolas Klauser       assert(std::all_of(out.begin(), out.end(), [](const auto& e) { return e.moved; }));
3032c3bbac0SNikolas Klauser     }
3042c3bbac0SNikolas Klauser     {
3052c3bbac0SNikolas Klauser       std::array<MoveOnce, 4> in {};
3062c3bbac0SNikolas Klauser       std::array<MoveOnce, 4> out {};
3072c3bbac0SNikolas Klauser       auto ret = std::ranges::move(in, out.begin());
3082c3bbac0SNikolas Klauser       assert(ret.in == in.end());
3092c3bbac0SNikolas Klauser       assert(ret.out == out.end());
3102c3bbac0SNikolas Klauser       assert(std::all_of(out.begin(), out.end(), [](const auto& e) { return e.moved; }));
3112c3bbac0SNikolas Klauser     }
3122c3bbac0SNikolas Klauser   }
3132c3bbac0SNikolas Klauser 
3142c3bbac0SNikolas Klauser   { // check that the range is moved forwards
3152c3bbac0SNikolas Klauser     struct OnlyForwardsMovable {
3162c3bbac0SNikolas Klauser       OnlyForwardsMovable* next = nullptr;
3172c3bbac0SNikolas Klauser       bool canMove = false;
3182c3bbac0SNikolas Klauser       OnlyForwardsMovable() = default;
3192c3bbac0SNikolas Klauser       constexpr OnlyForwardsMovable& operator=(OnlyForwardsMovable&&) {
3202c3bbac0SNikolas Klauser         assert(canMove);
3212c3bbac0SNikolas Klauser         if (next != nullptr)
3222c3bbac0SNikolas Klauser           next->canMove = true;
3232c3bbac0SNikolas Klauser         return *this;
3242c3bbac0SNikolas Klauser       }
3252c3bbac0SNikolas Klauser     };
3262c3bbac0SNikolas Klauser     {
3272c3bbac0SNikolas Klauser       std::array<OnlyForwardsMovable, 3> in {};
3282c3bbac0SNikolas Klauser       std::array<OnlyForwardsMovable, 3> out {};
3292c3bbac0SNikolas Klauser       out[0].next = &out[1];
3302c3bbac0SNikolas Klauser       out[1].next = &out[2];
3312c3bbac0SNikolas Klauser       out[0].canMove = true;
3322c3bbac0SNikolas Klauser       auto ret = std::ranges::move(in.begin(), in.end(), out.begin());
3332c3bbac0SNikolas Klauser       assert(ret.in == in.end());
3342c3bbac0SNikolas Klauser       assert(ret.out == out.end());
3352c3bbac0SNikolas Klauser       assert(out[0].canMove);
3362c3bbac0SNikolas Klauser       assert(out[1].canMove);
3372c3bbac0SNikolas Klauser       assert(out[2].canMove);
3382c3bbac0SNikolas Klauser     }
3392c3bbac0SNikolas Klauser     {
3402c3bbac0SNikolas Klauser       std::array<OnlyForwardsMovable, 3> in {};
3412c3bbac0SNikolas Klauser       std::array<OnlyForwardsMovable, 3> out {};
3422c3bbac0SNikolas Klauser       out[0].next = &out[1];
3432c3bbac0SNikolas Klauser       out[1].next = &out[2];
3442c3bbac0SNikolas Klauser       out[0].canMove = true;
3452c3bbac0SNikolas Klauser       auto ret = std::ranges::move(in, out.begin());
3462c3bbac0SNikolas Klauser       assert(ret.in == in.end());
3472c3bbac0SNikolas Klauser       assert(ret.out == out.end());
3482c3bbac0SNikolas Klauser       assert(out[0].canMove);
3492c3bbac0SNikolas Klauser       assert(out[1].canMove);
3502c3bbac0SNikolas Klauser       assert(out[2].canMove);
3512c3bbac0SNikolas Klauser     }
3522c3bbac0SNikolas Klauser   }
3532c3bbac0SNikolas Klauser 
3542c3bbac0SNikolas Klauser   { // check that iter_move is used properly
3552c3bbac0SNikolas Klauser     {
3562c3bbac0SNikolas Klauser       int a[] = {1, 2, 3, 4};
3572c3bbac0SNikolas Klauser       std::array<int, 4> b;
3582c3bbac0SNikolas Klauser       auto ret = std::ranges::move(IteratorWithMoveIter(a), IteratorWithMoveIter(a + 4), b.data());
3592c3bbac0SNikolas Klauser       assert(ret.in == a + 4);
3602c3bbac0SNikolas Klauser       assert(ret.out == b.data() + 4);
3612c3bbac0SNikolas Klauser       assert((b == std::array {42, 42, 42, 42}));
3622c3bbac0SNikolas Klauser     }
3632c3bbac0SNikolas Klauser     {
3642c3bbac0SNikolas Klauser       int a[] = {1, 2, 3, 4};
3652c3bbac0SNikolas Klauser       std::array<int, 4> b;
3662c3bbac0SNikolas Klauser       auto range = std::ranges::subrange(IteratorWithMoveIter(a), IteratorWithMoveIter(a + 4));
3672c3bbac0SNikolas Klauser       auto ret = std::ranges::move(range, b.data());
3682c3bbac0SNikolas Klauser       assert(ret.in == a + 4);
3692c3bbac0SNikolas Klauser       assert(ret.out == b.data() + 4);
3702c3bbac0SNikolas Klauser       assert((b == std::array {42, 42, 42, 42}));
3712c3bbac0SNikolas Klauser     }
3722c3bbac0SNikolas Klauser   }
3732c3bbac0SNikolas Klauser 
3742c3bbac0SNikolas Klauser   return true;
3752c3bbac0SNikolas Klauser }
3762c3bbac0SNikolas Klauser 
main(int,char **)3772c3bbac0SNikolas Klauser int main(int, char**) {
3782c3bbac0SNikolas Klauser   test();
3792c3bbac0SNikolas Klauser   static_assert(test());
3802c3bbac0SNikolas Klauser 
3812c3bbac0SNikolas Klauser   return 0;
3822c3bbac0SNikolas Klauser }
383