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