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