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
122c3bbac0SNikolas Klauser // UNSUPPORTED: libcpp-has-no-incomplete-ranges
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>
262c3bbac0SNikolas Klauser #include <ranges>
272c3bbac0SNikolas Klauser 
282c3bbac0SNikolas Klauser #include "almost_satisfies_types.h"
292c3bbac0SNikolas Klauser #include "MoveOnly.h"
302c3bbac0SNikolas Klauser #include "test_iterators.h"
312c3bbac0SNikolas Klauser 
322c3bbac0SNikolas Klauser template <class In, class Out = In, class Sent = sentinel_wrapper<In>>
332c3bbac0SNikolas Klauser concept HasMoveIt = requires(In in, Sent sent, Out out) { std::ranges::move(in, sent, out); };
342c3bbac0SNikolas Klauser 
352c3bbac0SNikolas Klauser static_assert(HasMoveIt<int*>);
362c3bbac0SNikolas Klauser static_assert(!HasMoveIt<InputIteratorNotDerivedFrom>);
372c3bbac0SNikolas Klauser static_assert(!HasMoveIt<InputIteratorNotIndirectlyReadable>);
382c3bbac0SNikolas Klauser static_assert(!HasMoveIt<InputIteratorNotInputOrOutputIterator>);
392c3bbac0SNikolas Klauser static_assert(!HasMoveIt<int*, WeaklyIncrementableNotMovable>);
402c3bbac0SNikolas Klauser struct NotIndirectlyMovable {};
412c3bbac0SNikolas Klauser static_assert(!HasMoveIt<int*, NotIndirectlyMovable*>);
422c3bbac0SNikolas Klauser static_assert(!HasMoveIt<int*, int*, SentinelForNotSemiregular>);
432c3bbac0SNikolas Klauser static_assert(!HasMoveIt<int*, int*, SentinelForNotWeaklyEqualityComparableWith>);
442c3bbac0SNikolas Klauser 
452c3bbac0SNikolas Klauser template <class Range, class Out>
462c3bbac0SNikolas Klauser concept HasMoveR = requires(Range range, Out out) { std::ranges::move(range, out); };
472c3bbac0SNikolas Klauser 
482c3bbac0SNikolas Klauser static_assert(HasMoveR<std::array<int, 10>, int*>);
492c3bbac0SNikolas Klauser static_assert(!HasMoveR<InputRangeNotDerivedFrom, int*>);
502c3bbac0SNikolas Klauser static_assert(!HasMoveR<InputRangeNotIndirectlyReadable, int*>);
512c3bbac0SNikolas Klauser static_assert(!HasMoveR<InputRangeNotInputOrOutputIterator, int*>);
522c3bbac0SNikolas Klauser static_assert(!HasMoveR<WeaklyIncrementableNotMovable, int*>);
532c3bbac0SNikolas Klauser static_assert(!HasMoveR<UncheckedRange<NotIndirectlyMovable*>, int*>);
542c3bbac0SNikolas Klauser static_assert(!HasMoveR<InputRangeNotSentinelSemiregular, int*>);
552c3bbac0SNikolas Klauser static_assert(!HasMoveR<InputRangeNotSentinelEqualityComparableWith, int*>);
562c3bbac0SNikolas Klauser static_assert(!HasMoveR<UncheckedRange<int*>, WeaklyIncrementableNotMovable>);
572c3bbac0SNikolas Klauser 
582c3bbac0SNikolas Klauser static_assert(std::is_same_v<std::ranges::move_result<int, long>, std::ranges::in_out_result<int, long>>);
592c3bbac0SNikolas Klauser 
602c3bbac0SNikolas Klauser template <class In, class Out, class Sent, int N>
test(std::array<int,N> in)612c3bbac0SNikolas Klauser constexpr void test(std::array<int, N> in) {
622c3bbac0SNikolas Klauser   {
632c3bbac0SNikolas Klauser     std::array<int, N> out;
642c3bbac0SNikolas Klauser     std::same_as<std::ranges::in_out_result<In, Out>> decltype(auto) ret =
652c3bbac0SNikolas Klauser       std::ranges::move(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data()));
662c3bbac0SNikolas Klauser     assert(in == out);
672c3bbac0SNikolas Klauser     assert(base(ret.in) == in.data() + in.size());
682c3bbac0SNikolas Klauser     assert(base(ret.out) == out.data() + out.size());
692c3bbac0SNikolas Klauser   }
702c3bbac0SNikolas Klauser   {
712c3bbac0SNikolas Klauser     std::array<int, N> out;
722c3bbac0SNikolas Klauser     auto range = std::ranges::subrange(In(in.data()), Sent(In(in.data() + in.size())));
732c3bbac0SNikolas Klauser     std::same_as<std::ranges::in_out_result<In, Out>> decltype(auto) ret =
742c3bbac0SNikolas Klauser         std::ranges::move(range, Out(out.data()));
752c3bbac0SNikolas Klauser     assert(in == out);
762c3bbac0SNikolas Klauser     assert(base(ret.in) == in.data() + in.size());
772c3bbac0SNikolas Klauser     assert(base(ret.out) == out.data() + out.size());
782c3bbac0SNikolas Klauser   }
792c3bbac0SNikolas Klauser }
802c3bbac0SNikolas Klauser 
812c3bbac0SNikolas Klauser template <class In, class Out, class Sent = In>
test_iterators()822c3bbac0SNikolas Klauser constexpr void test_iterators() {
832c3bbac0SNikolas Klauser   // simple test
842c3bbac0SNikolas Klauser   test<In, Out, Sent, 4>({1, 2, 3, 4});
852c3bbac0SNikolas Klauser   // check that an empty range works
862c3bbac0SNikolas Klauser   test<In, Out, Sent, 0>({});
872c3bbac0SNikolas Klauser }
882c3bbac0SNikolas Klauser 
892c3bbac0SNikolas Klauser template <class Out>
test_in_iterators()902c3bbac0SNikolas Klauser constexpr void test_in_iterators() {
912c3bbac0SNikolas Klauser   test_iterators<cpp20_input_iterator<int*>, Out, sentinel_wrapper<cpp20_input_iterator<int*>>>();
922c3bbac0SNikolas Klauser   test_iterators<forward_iterator<int*>, Out>();
932c3bbac0SNikolas Klauser   test_iterators<bidirectional_iterator<int*>, Out>();
942c3bbac0SNikolas Klauser   test_iterators<random_access_iterator<int*>, Out>();
952c3bbac0SNikolas Klauser   test_iterators<contiguous_iterator<int*>, Out>();
962c3bbac0SNikolas Klauser }
972c3bbac0SNikolas Klauser 
98*a81cc1fcSHui Xie template <class Out>
test_proxy_in_iterators()99*a81cc1fcSHui Xie constexpr void test_proxy_in_iterators() {
100*a81cc1fcSHui Xie   test_iterators<ProxyIterator<cpp20_input_iterator<int*>>, Out, sentinel_wrapper<ProxyIterator<cpp20_input_iterator<int*>>>>();
101*a81cc1fcSHui Xie   test_iterators<ProxyIterator<forward_iterator<int*>>, Out>();
102*a81cc1fcSHui Xie   test_iterators<ProxyIterator<bidirectional_iterator<int*>>, Out>();
103*a81cc1fcSHui Xie   test_iterators<ProxyIterator<random_access_iterator<int*>>, Out>();
104*a81cc1fcSHui Xie   test_iterators<ProxyIterator<contiguous_iterator<int*>>, Out>();
105*a81cc1fcSHui Xie }
106*a81cc1fcSHui Xie 
1072c3bbac0SNikolas Klauser struct IteratorWithMoveIter {
1082c3bbac0SNikolas Klauser   using value_type = int;
1092c3bbac0SNikolas Klauser   using difference_type = int;
1102c3bbac0SNikolas Klauser   explicit IteratorWithMoveIter() = default;
1112c3bbac0SNikolas Klauser   int* ptr;
IteratorWithMoveIterIteratorWithMoveIter1122c3bbac0SNikolas Klauser   constexpr IteratorWithMoveIter(int* ptr_) : ptr(ptr_) {}
1132c3bbac0SNikolas Klauser 
1142c3bbac0SNikolas Klauser   constexpr int& operator*() const; // iterator with iter_move should not be dereferenced
1152c3bbac0SNikolas Klauser 
operator ++IteratorWithMoveIter1162c3bbac0SNikolas Klauser   constexpr IteratorWithMoveIter& operator++() { ++ptr; return *this; }
operator ++IteratorWithMoveIter1172c3bbac0SNikolas Klauser   constexpr IteratorWithMoveIter operator++(int) { auto ret = *this; ++*this; return ret; }
1182c3bbac0SNikolas Klauser 
iter_move(const IteratorWithMoveIter &)1192c3bbac0SNikolas Klauser   friend constexpr int iter_move(const IteratorWithMoveIter&) { return 42; }
1202c3bbac0SNikolas Klauser 
1212c3bbac0SNikolas Klauser   constexpr bool operator==(const IteratorWithMoveIter& other) const = default;
1222c3bbac0SNikolas Klauser };
1232c3bbac0SNikolas Klauser 
test()1242c3bbac0SNikolas Klauser constexpr bool test() {
1252c3bbac0SNikolas Klauser   test_in_iterators<cpp17_output_iterator<int*>>();
1262c3bbac0SNikolas Klauser   test_in_iterators<cpp20_output_iterator<int*>>();
1272c3bbac0SNikolas Klauser   test_in_iterators<cpp17_input_iterator<int*>>();
1282c3bbac0SNikolas Klauser   test_in_iterators<cpp20_input_iterator<int*>>();
1292c3bbac0SNikolas Klauser   test_in_iterators<forward_iterator<int*>>();
1302c3bbac0SNikolas Klauser   test_in_iterators<bidirectional_iterator<int*>>();
1312c3bbac0SNikolas Klauser   test_in_iterators<random_access_iterator<int*>>();
1322c3bbac0SNikolas Klauser   test_in_iterators<contiguous_iterator<int*>>();
1332c3bbac0SNikolas Klauser 
134*a81cc1fcSHui Xie   test_proxy_in_iterators<ProxyIterator<cpp20_input_iterator<int*>>>();
135*a81cc1fcSHui Xie   test_proxy_in_iterators<ProxyIterator<forward_iterator<int*>>>();
136*a81cc1fcSHui Xie   test_proxy_in_iterators<ProxyIterator<bidirectional_iterator<int*>>>();
137*a81cc1fcSHui Xie   test_proxy_in_iterators<ProxyIterator<random_access_iterator<int*>>>();
138*a81cc1fcSHui Xie   test_proxy_in_iterators<ProxyIterator<contiguous_iterator<int*>>>();
139*a81cc1fcSHui Xie 
1402c3bbac0SNikolas Klauser   { // check that a move-only type works
1412c3bbac0SNikolas Klauser     {
1422c3bbac0SNikolas Klauser       MoveOnly a[] = {1, 2, 3};
1432c3bbac0SNikolas Klauser       MoveOnly b[3];
1442c3bbac0SNikolas Klauser       std::ranges::move(a, std::begin(b));
1452c3bbac0SNikolas Klauser       assert(b[0].get() == 1);
1462c3bbac0SNikolas Klauser       assert(b[1].get() == 2);
1472c3bbac0SNikolas Klauser       assert(b[2].get() == 3);
1482c3bbac0SNikolas Klauser     }
1492c3bbac0SNikolas Klauser     {
1502c3bbac0SNikolas Klauser       MoveOnly a[] = {1, 2, 3};
1512c3bbac0SNikolas Klauser       MoveOnly b[3];
1522c3bbac0SNikolas Klauser       std::ranges::move(std::begin(a), std::end(a), std::begin(b));
1532c3bbac0SNikolas Klauser       assert(b[0].get() == 1);
1542c3bbac0SNikolas Klauser       assert(b[1].get() == 2);
1552c3bbac0SNikolas Klauser       assert(b[2].get() == 3);
1562c3bbac0SNikolas Klauser     }
1572c3bbac0SNikolas Klauser   }
1582c3bbac0SNikolas Klauser 
159*a81cc1fcSHui Xie   { // check that a move-only type works for ProxyIterator
160*a81cc1fcSHui Xie     {
161*a81cc1fcSHui Xie       MoveOnly a[] = {1, 2, 3};
162*a81cc1fcSHui Xie       MoveOnly b[3];
163*a81cc1fcSHui Xie       ProxyRange proxyA{a};
164*a81cc1fcSHui Xie       ProxyRange proxyB{b};
165*a81cc1fcSHui Xie       std::ranges::move(proxyA, std::begin(proxyB));
166*a81cc1fcSHui Xie       assert(b[0].get() == 1);
167*a81cc1fcSHui Xie       assert(b[1].get() == 2);
168*a81cc1fcSHui Xie       assert(b[2].get() == 3);
169*a81cc1fcSHui Xie     }
170*a81cc1fcSHui Xie     {
171*a81cc1fcSHui Xie       MoveOnly a[] = {1, 2, 3};
172*a81cc1fcSHui Xie       MoveOnly b[3];
173*a81cc1fcSHui Xie       ProxyRange proxyA{a};
174*a81cc1fcSHui Xie       ProxyRange proxyB{b};
175*a81cc1fcSHui Xie       std::ranges::move(std::begin(proxyA), std::end(proxyA), std::begin(proxyB));
176*a81cc1fcSHui Xie       assert(b[0].get() == 1);
177*a81cc1fcSHui Xie       assert(b[1].get() == 2);
178*a81cc1fcSHui Xie       assert(b[2].get() == 3);
179*a81cc1fcSHui Xie     }
180*a81cc1fcSHui Xie   }
181*a81cc1fcSHui Xie 
1822c3bbac0SNikolas Klauser   { // check that ranges::dangling is returned
1832c3bbac0SNikolas Klauser     std::array<int, 4> out;
1842c3bbac0SNikolas Klauser     std::same_as<std::ranges::in_out_result<std::ranges::dangling, int*>> decltype(auto) ret =
1852c3bbac0SNikolas Klauser       std::ranges::move(std::array {1, 2, 3, 4}, out.data());
1862c3bbac0SNikolas Klauser     assert(ret.out == out.data() + 4);
1872c3bbac0SNikolas Klauser     assert((out == std::array{1, 2, 3, 4}));
1882c3bbac0SNikolas Klauser   }
1892c3bbac0SNikolas Klauser 
1902c3bbac0SNikolas Klauser   { // check that an iterator is returned with a borrowing range
1912c3bbac0SNikolas Klauser     std::array in {1, 2, 3, 4};
1922c3bbac0SNikolas Klauser     std::array<int, 4> out;
1932c3bbac0SNikolas Klauser     std::same_as<std::ranges::in_out_result<int*, int*>> decltype(auto) ret =
1942c3bbac0SNikolas Klauser         std::ranges::move(std::views::all(in), out.data());
1952c3bbac0SNikolas Klauser     assert(ret.in == in.data() + 4);
1962c3bbac0SNikolas Klauser     assert(ret.out == out.data() + 4);
1972c3bbac0SNikolas Klauser     assert(in == out);
1982c3bbac0SNikolas Klauser   }
1992c3bbac0SNikolas Klauser 
2002c3bbac0SNikolas Klauser   { // check that every element is moved exactly once
2012c3bbac0SNikolas Klauser     struct MoveOnce {
2022c3bbac0SNikolas Klauser       bool moved = false;
2032c3bbac0SNikolas Klauser       constexpr MoveOnce() = default;
2042c3bbac0SNikolas Klauser       constexpr MoveOnce(const MoveOnce& other) = delete;
2052c3bbac0SNikolas Klauser       constexpr MoveOnce& operator=(MoveOnce&& other) {
2062c3bbac0SNikolas Klauser         assert(!other.moved);
2072c3bbac0SNikolas Klauser         moved = true;
2082c3bbac0SNikolas Klauser         return *this;
2092c3bbac0SNikolas Klauser       }
2102c3bbac0SNikolas Klauser     };
2112c3bbac0SNikolas Klauser     {
2122c3bbac0SNikolas Klauser       std::array<MoveOnce, 4> in {};
2132c3bbac0SNikolas Klauser       std::array<MoveOnce, 4> out {};
2142c3bbac0SNikolas Klauser       auto ret = std::ranges::move(in.begin(), in.end(), out.begin());
2152c3bbac0SNikolas Klauser       assert(ret.in == in.end());
2162c3bbac0SNikolas Klauser       assert(ret.out == out.end());
2172c3bbac0SNikolas Klauser       assert(std::all_of(out.begin(), out.end(), [](const auto& e) { return e.moved; }));
2182c3bbac0SNikolas Klauser     }
2192c3bbac0SNikolas Klauser     {
2202c3bbac0SNikolas Klauser       std::array<MoveOnce, 4> in {};
2212c3bbac0SNikolas Klauser       std::array<MoveOnce, 4> out {};
2222c3bbac0SNikolas Klauser       auto ret = std::ranges::move(in, out.begin());
2232c3bbac0SNikolas Klauser       assert(ret.in == in.end());
2242c3bbac0SNikolas Klauser       assert(ret.out == out.end());
2252c3bbac0SNikolas Klauser       assert(std::all_of(out.begin(), out.end(), [](const auto& e) { return e.moved; }));
2262c3bbac0SNikolas Klauser     }
2272c3bbac0SNikolas Klauser   }
2282c3bbac0SNikolas Klauser 
2292c3bbac0SNikolas Klauser   { // check that the range is moved forwards
2302c3bbac0SNikolas Klauser     struct OnlyForwardsMovable {
2312c3bbac0SNikolas Klauser       OnlyForwardsMovable* next = nullptr;
2322c3bbac0SNikolas Klauser       bool canMove = false;
2332c3bbac0SNikolas Klauser       OnlyForwardsMovable() = default;
2342c3bbac0SNikolas Klauser       constexpr OnlyForwardsMovable& operator=(OnlyForwardsMovable&&) {
2352c3bbac0SNikolas Klauser         assert(canMove);
2362c3bbac0SNikolas Klauser         if (next != nullptr)
2372c3bbac0SNikolas Klauser           next->canMove = true;
2382c3bbac0SNikolas Klauser         return *this;
2392c3bbac0SNikolas Klauser       }
2402c3bbac0SNikolas Klauser     };
2412c3bbac0SNikolas Klauser     {
2422c3bbac0SNikolas Klauser       std::array<OnlyForwardsMovable, 3> in {};
2432c3bbac0SNikolas Klauser       std::array<OnlyForwardsMovable, 3> out {};
2442c3bbac0SNikolas Klauser       out[0].next = &out[1];
2452c3bbac0SNikolas Klauser       out[1].next = &out[2];
2462c3bbac0SNikolas Klauser       out[0].canMove = true;
2472c3bbac0SNikolas Klauser       auto ret = std::ranges::move(in.begin(), in.end(), out.begin());
2482c3bbac0SNikolas Klauser       assert(ret.in == in.end());
2492c3bbac0SNikolas Klauser       assert(ret.out == out.end());
2502c3bbac0SNikolas Klauser       assert(out[0].canMove);
2512c3bbac0SNikolas Klauser       assert(out[1].canMove);
2522c3bbac0SNikolas Klauser       assert(out[2].canMove);
2532c3bbac0SNikolas Klauser     }
2542c3bbac0SNikolas Klauser     {
2552c3bbac0SNikolas Klauser       std::array<OnlyForwardsMovable, 3> in {};
2562c3bbac0SNikolas Klauser       std::array<OnlyForwardsMovable, 3> out {};
2572c3bbac0SNikolas Klauser       out[0].next = &out[1];
2582c3bbac0SNikolas Klauser       out[1].next = &out[2];
2592c3bbac0SNikolas Klauser       out[0].canMove = true;
2602c3bbac0SNikolas Klauser       auto ret = std::ranges::move(in, out.begin());
2612c3bbac0SNikolas Klauser       assert(ret.in == in.end());
2622c3bbac0SNikolas Klauser       assert(ret.out == out.end());
2632c3bbac0SNikolas Klauser       assert(out[0].canMove);
2642c3bbac0SNikolas Klauser       assert(out[1].canMove);
2652c3bbac0SNikolas Klauser       assert(out[2].canMove);
2662c3bbac0SNikolas Klauser     }
2672c3bbac0SNikolas Klauser   }
2682c3bbac0SNikolas Klauser 
2692c3bbac0SNikolas Klauser   { // check that iter_move is used properly
2702c3bbac0SNikolas Klauser     {
2712c3bbac0SNikolas Klauser       int a[] = {1, 2, 3, 4};
2722c3bbac0SNikolas Klauser       std::array<int, 4> b;
2732c3bbac0SNikolas Klauser       auto ret = std::ranges::move(IteratorWithMoveIter(a), IteratorWithMoveIter(a + 4), b.data());
2742c3bbac0SNikolas Klauser       assert(ret.in == a + 4);
2752c3bbac0SNikolas Klauser       assert(ret.out == b.data() + 4);
2762c3bbac0SNikolas Klauser       assert((b == std::array {42, 42, 42, 42}));
2772c3bbac0SNikolas Klauser     }
2782c3bbac0SNikolas Klauser     {
2792c3bbac0SNikolas Klauser       int a[] = {1, 2, 3, 4};
2802c3bbac0SNikolas Klauser       std::array<int, 4> b;
2812c3bbac0SNikolas Klauser       auto range = std::ranges::subrange(IteratorWithMoveIter(a), IteratorWithMoveIter(a + 4));
2822c3bbac0SNikolas Klauser       auto ret = std::ranges::move(range, b.data());
2832c3bbac0SNikolas Klauser       assert(ret.in == a + 4);
2842c3bbac0SNikolas Klauser       assert(ret.out == b.data() + 4);
2852c3bbac0SNikolas Klauser       assert((b == std::array {42, 42, 42, 42}));
2862c3bbac0SNikolas Klauser     }
2872c3bbac0SNikolas Klauser   }
2882c3bbac0SNikolas Klauser 
2892c3bbac0SNikolas Klauser   return true;
2902c3bbac0SNikolas Klauser }
2912c3bbac0SNikolas Klauser 
main(int,char **)2922c3bbac0SNikolas Klauser int main(int, char**) {
2932c3bbac0SNikolas Klauser   test();
2942c3bbac0SNikolas Klauser   static_assert(test());
2952c3bbac0SNikolas Klauser 
2962c3bbac0SNikolas Klauser   return 0;
2972c3bbac0SNikolas Klauser }
298