xref: /llvm-project/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy.pass.cpp (revision d05bada59205b9bcf1195a6eac7e09b721e3b79b)
11d83750fSNikolas Klauser //===----------------------------------------------------------------------===//
21d83750fSNikolas Klauser //
31d83750fSNikolas Klauser // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
41d83750fSNikolas Klauser // See https://llvm.org/LICENSE.txt for license information.
51d83750fSNikolas Klauser // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61d83750fSNikolas Klauser //
71d83750fSNikolas Klauser //===----------------------------------------------------------------------===//
81d83750fSNikolas Klauser 
91d83750fSNikolas Klauser // <algorithm>
101d83750fSNikolas Klauser 
111d83750fSNikolas Klauser // UNSUPPORTED: c++03, c++11, c++14, c++17
121d83750fSNikolas Klauser 
131d83750fSNikolas Klauser // template<input_iterator I, sentinel_for<I> S, weakly_incrementable O>
141d83750fSNikolas Klauser //   requires indirectly_copyable<I, O>
151d83750fSNikolas Klauser //   constexpr ranges::copy_result<I, O> ranges::copy(I first, S last, O result);
161d83750fSNikolas Klauser // template<input_range R, weakly_incrementable O>
171d83750fSNikolas Klauser //   requires indirectly_copyable<iterator_t<R>, O>
181d83750fSNikolas Klauser //   constexpr ranges::copy_result<borrowed_iterator_t<R>, O> ranges::copy(R&& r, O result);
191d83750fSNikolas Klauser 
201d83750fSNikolas Klauser #include <algorithm>
211d83750fSNikolas Klauser #include <array>
221d83750fSNikolas Klauser #include <cassert>
23c9080145SNikolas Klauser #include <deque>
241d83750fSNikolas Klauser #include <ranges>
25c9080145SNikolas Klauser #include <vector>
261d83750fSNikolas Klauser 
271d83750fSNikolas Klauser #include "almost_satisfies_types.h"
281d83750fSNikolas Klauser #include "test_iterators.h"
291323461fSNikolas Klauser #include "type_algorithms.h"
301d83750fSNikolas Klauser 
311d83750fSNikolas Klauser template <class In, class Out = In, class Sent = sentinel_wrapper<In>>
321d83750fSNikolas Klauser concept HasCopyIt = requires(In in, Sent sent, Out out) { std::ranges::copy(in, sent, out); };
331d83750fSNikolas Klauser 
341d83750fSNikolas Klauser static_assert(HasCopyIt<int*>);
351d83750fSNikolas Klauser static_assert(!HasCopyIt<InputIteratorNotDerivedFrom>);
361d83750fSNikolas Klauser static_assert(!HasCopyIt<InputIteratorNotIndirectlyReadable>);
371d83750fSNikolas Klauser static_assert(!HasCopyIt<InputIteratorNotInputOrOutputIterator>);
381d83750fSNikolas Klauser static_assert(!HasCopyIt<int*, WeaklyIncrementableNotMovable>);
391d83750fSNikolas Klauser struct NotIndirectlyCopyable {};
401d83750fSNikolas Klauser static_assert(!HasCopyIt<int*, NotIndirectlyCopyable*>);
411d83750fSNikolas Klauser static_assert(!HasCopyIt<int*, int*, SentinelForNotSemiregular>);
421d83750fSNikolas Klauser static_assert(!HasCopyIt<int*, int*, SentinelForNotWeaklyEqualityComparableWith>);
431d83750fSNikolas Klauser 
441d83750fSNikolas Klauser template <class Range, class Out>
451d83750fSNikolas Klauser concept HasCopyR = requires(Range range, Out out) { std::ranges::copy(range, out); };
461d83750fSNikolas Klauser 
471d83750fSNikolas Klauser static_assert(HasCopyR<std::array<int, 10>, int*>);
481d83750fSNikolas Klauser static_assert(!HasCopyR<InputRangeNotDerivedFrom, int*>);
491d83750fSNikolas Klauser static_assert(!HasCopyR<InputRangeNotIndirectlyReadable, int*>);
501d83750fSNikolas Klauser static_assert(!HasCopyR<InputRangeNotInputOrOutputIterator, int*>);
511d83750fSNikolas Klauser static_assert(!HasCopyR<WeaklyIncrementableNotMovable, int*>);
521d83750fSNikolas Klauser static_assert(!HasCopyR<UncheckedRange<NotIndirectlyCopyable*>, int*>);
531d83750fSNikolas Klauser static_assert(!HasCopyR<InputRangeNotSentinelSemiregular, int*>);
541d83750fSNikolas Klauser static_assert(!HasCopyR<InputRangeNotSentinelEqualityComparableWith, int*>);
551d83750fSNikolas Klauser 
561d83750fSNikolas Klauser static_assert(std::is_same_v<std::ranges::copy_result<int, long>, std::ranges::in_out_result<int, long>>);
571d83750fSNikolas Klauser 
58c9080145SNikolas Klauser // clang-format off
591d83750fSNikolas Klauser template <class In, class Out, class Sent = In>
test_iterators()601d83750fSNikolas Klauser constexpr void test_iterators() {
611d83750fSNikolas Klauser   { // simple test
621d83750fSNikolas Klauser     {
631d83750fSNikolas Klauser       std::array in{1, 2, 3, 4};
641d83750fSNikolas Klauser       std::array<int, 4> out;
651d83750fSNikolas Klauser       std::same_as<std::ranges::in_out_result<In, Out>> auto ret =
661d83750fSNikolas Klauser           std::ranges::copy(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data()));
671d83750fSNikolas Klauser       assert(in == out);
681d83750fSNikolas Klauser       assert(base(ret.in) == in.data() + in.size());
691d83750fSNikolas Klauser       assert(base(ret.out) == out.data() + out.size());
701d83750fSNikolas Klauser     }
711d83750fSNikolas Klauser     {
721d83750fSNikolas Klauser       std::array in{1, 2, 3, 4};
731d83750fSNikolas Klauser       std::array<int, 4> out;
741d83750fSNikolas Klauser       auto range = std::ranges::subrange(In(in.data()), Sent(In(in.data() + in.size())));
751d83750fSNikolas Klauser       std::same_as<std::ranges::in_out_result<In, Out>> auto ret = std::ranges::copy(range, Out(out.data()));
761d83750fSNikolas Klauser       assert(in == out);
771d83750fSNikolas Klauser       assert(base(ret.in) == in.data() + in.size());
781d83750fSNikolas Klauser       assert(base(ret.out) == out.data() + out.size());
791d83750fSNikolas Klauser     }
801d83750fSNikolas Klauser   }
811d83750fSNikolas Klauser 
821d83750fSNikolas Klauser   { // check that an empty range works
831d83750fSNikolas Klauser     {
841d83750fSNikolas Klauser       std::array<int, 0> in;
851d83750fSNikolas Klauser       std::array<int, 0> out;
861d83750fSNikolas Klauser       auto ret = std::ranges::copy(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data()));
871d83750fSNikolas Klauser       assert(base(ret.in) == in.data());
881d83750fSNikolas Klauser       assert(base(ret.out) == out.data());
891d83750fSNikolas Klauser     }
901d83750fSNikolas Klauser     {
911d83750fSNikolas Klauser       std::array<int, 0> in;
921d83750fSNikolas Klauser       std::array<int, 0> out;
931d83750fSNikolas Klauser       auto range = std::ranges::subrange(In(in.data()), Sent(In(in.data() + in.size())));
941d83750fSNikolas Klauser       auto ret   = std::ranges::copy(range, Out(out.data()));
951d83750fSNikolas Klauser       assert(base(ret.in) == in.data());
961d83750fSNikolas Klauser       assert(base(ret.out) == out.data());
971d83750fSNikolas Klauser     }
981d83750fSNikolas Klauser   }
991d83750fSNikolas Klauser }
100c9080145SNikolas Klauser // clang-format on
1011d83750fSNikolas Klauser 
test()1021323461fSNikolas Klauser constexpr bool test() {
103f56dfb78SArthur O'Dwyer   types::for_each(types::forward_iterator_list<int*>{}, []<class Out>() {
1041323461fSNikolas Klauser     test_iterators<cpp20_input_iterator<int*>, Out, sentinel_wrapper<cpp20_input_iterator<int*>>>();
1051323461fSNikolas Klauser     test_iterators<ProxyIterator<cpp20_input_iterator<int*>>,
1061323461fSNikolas Klauser                    ProxyIterator<Out>,
1071323461fSNikolas Klauser                    sentinel_wrapper<ProxyIterator<cpp20_input_iterator<int*>>>>();
1081323461fSNikolas Klauser 
109f56dfb78SArthur O'Dwyer     types::for_each(types::forward_iterator_list<int*>{}, []<class In>() {
110e01b4fe9SNikolas Klauser       test_iterators<In, Out>();
111e01b4fe9SNikolas Klauser       test_iterators<In, Out, sized_sentinel<In>>();
112e01b4fe9SNikolas Klauser       test_iterators<In, Out, sentinel_wrapper<In>>();
113e01b4fe9SNikolas Klauser 
1141323461fSNikolas Klauser       test_iterators<ProxyIterator<In>, ProxyIterator<Out>>();
1151323461fSNikolas Klauser       test_iterators<ProxyIterator<In>, ProxyIterator<Out>, sized_sentinel<ProxyIterator<In>>>();
1161323461fSNikolas Klauser       test_iterators<ProxyIterator<In>, ProxyIterator<Out>, sentinel_wrapper<ProxyIterator<In>>>();
1171323461fSNikolas Klauser     });
1181323461fSNikolas Klauser   });
119a81cc1fcSHui Xie 
1201d83750fSNikolas Klauser   { // check that ranges::dangling is returned
1211d83750fSNikolas Klauser     std::array<int, 4> out;
1221d83750fSNikolas Klauser     std::same_as<std::ranges::in_out_result<std::ranges::dangling, int*>> auto ret =
1231d83750fSNikolas Klauser         std::ranges::copy(std::array{1, 2, 3, 4}, out.data());
1241d83750fSNikolas Klauser     assert(ret.out == out.data() + 4);
1251d83750fSNikolas Klauser     assert((out == std::array{1, 2, 3, 4}));
1261d83750fSNikolas Klauser   }
1271d83750fSNikolas Klauser 
1281d83750fSNikolas Klauser   { // check that an iterator is returned with a borrowing range
1291d83750fSNikolas Klauser     std::array in{1, 2, 3, 4};
1301d83750fSNikolas Klauser     std::array<int, 4> out;
131*d05bada5SDuo Wang     std::same_as<std::ranges::in_out_result<std::array<int, 4>::iterator, int*>> auto ret =
132*d05bada5SDuo Wang         std::ranges::copy(std::views::all(in), out.data());
133*d05bada5SDuo Wang     assert(ret.in == in.end());
1341d83750fSNikolas Klauser     assert(ret.out == out.data() + 4);
1351d83750fSNikolas Klauser     assert(in == out);
1361d83750fSNikolas Klauser   }
1371d83750fSNikolas Klauser 
1381d83750fSNikolas Klauser   { // check that every element is copied exactly once
1391d83750fSNikolas Klauser     struct CopyOnce {
1401d83750fSNikolas Klauser       bool copied                               = false;
1411d83750fSNikolas Klauser       constexpr CopyOnce()                      = default;
1421d83750fSNikolas Klauser       constexpr CopyOnce(const CopyOnce& other) = delete;
1431d83750fSNikolas Klauser       constexpr CopyOnce& operator=(const CopyOnce& other) {
1441d83750fSNikolas Klauser         assert(!other.copied);
1451d83750fSNikolas Klauser         copied = true;
1461d83750fSNikolas Klauser         return *this;
1471d83750fSNikolas Klauser       }
1481d83750fSNikolas Klauser     };
1491d83750fSNikolas Klauser     {
1501d83750fSNikolas Klauser       std::array<CopyOnce, 4> in{};
1511d83750fSNikolas Klauser       std::array<CopyOnce, 4> out{};
1521d83750fSNikolas Klauser       auto ret = std::ranges::copy(in.begin(), in.end(), out.begin());
1531d83750fSNikolas Klauser       assert(ret.in == in.end());
1541d83750fSNikolas Klauser       assert(ret.out == out.end());
1551d83750fSNikolas Klauser       assert(std::all_of(out.begin(), out.end(), [](const auto& e) { return e.copied; }));
1561d83750fSNikolas Klauser     }
1571d83750fSNikolas Klauser     {
1581d83750fSNikolas Klauser       std::array<CopyOnce, 4> in{};
1591d83750fSNikolas Klauser       std::array<CopyOnce, 4> out{};
1601d83750fSNikolas Klauser       auto ret = std::ranges::copy(in, out.begin());
1611d83750fSNikolas Klauser       assert(ret.in == in.end());
1621d83750fSNikolas Klauser       assert(ret.out == out.end());
1631d83750fSNikolas Klauser       assert(std::all_of(out.begin(), out.end(), [](const auto& e) { return e.copied; }));
1641d83750fSNikolas Klauser     }
1651d83750fSNikolas Klauser   }
1661d83750fSNikolas Klauser 
1671d83750fSNikolas Klauser   { // check that the range is copied forwards
1681d83750fSNikolas Klauser     struct OnlyForwardsCopyable {
1691d83750fSNikolas Klauser       OnlyForwardsCopyable* next = nullptr;
1701d83750fSNikolas Klauser       bool canCopy               = false;
1711d83750fSNikolas Klauser       OnlyForwardsCopyable()     = default;
1721d83750fSNikolas Klauser       constexpr OnlyForwardsCopyable& operator=(const OnlyForwardsCopyable&) {
1731d83750fSNikolas Klauser         assert(canCopy);
1741d83750fSNikolas Klauser         if (next != nullptr)
1751d83750fSNikolas Klauser           next->canCopy = true;
1761d83750fSNikolas Klauser         return *this;
1771d83750fSNikolas Klauser       }
1781d83750fSNikolas Klauser     };
1791d83750fSNikolas Klauser     {
1801d83750fSNikolas Klauser       std::array<OnlyForwardsCopyable, 3> in{};
1811d83750fSNikolas Klauser       std::array<OnlyForwardsCopyable, 3> out{};
1821d83750fSNikolas Klauser       out[0].next    = &out[1];
1831d83750fSNikolas Klauser       out[1].next    = &out[2];
1841d83750fSNikolas Klauser       out[0].canCopy = true;
1851d83750fSNikolas Klauser       auto ret       = std::ranges::copy(in.begin(), in.end(), out.begin());
1861d83750fSNikolas Klauser       assert(ret.in == in.end());
1871d83750fSNikolas Klauser       assert(ret.out == out.end());
1881d83750fSNikolas Klauser       assert(out[0].canCopy);
1891d83750fSNikolas Klauser       assert(out[1].canCopy);
1901d83750fSNikolas Klauser       assert(out[2].canCopy);
1911d83750fSNikolas Klauser     }
1921d83750fSNikolas Klauser     {
1931d83750fSNikolas Klauser       std::array<OnlyForwardsCopyable, 3> in{};
1941d83750fSNikolas Klauser       std::array<OnlyForwardsCopyable, 3> out{};
1951d83750fSNikolas Klauser       out[0].next    = &out[1];
1961d83750fSNikolas Klauser       out[1].next    = &out[2];
1971d83750fSNikolas Klauser       out[0].canCopy = true;
1981d83750fSNikolas Klauser       auto ret       = std::ranges::copy(in, out.begin());
1991d83750fSNikolas Klauser       assert(ret.in == in.end());
2001d83750fSNikolas Klauser       assert(ret.out == out.end());
2011d83750fSNikolas Klauser       assert(out[0].canCopy);
2021d83750fSNikolas Klauser       assert(out[1].canCopy);
2031d83750fSNikolas Klauser       assert(out[2].canCopy);
2041d83750fSNikolas Klauser     }
2051d83750fSNikolas Klauser   }
2061d83750fSNikolas Klauser 
2071d83750fSNikolas Klauser   return true;
2081d83750fSNikolas Klauser }
2091d83750fSNikolas Klauser 
main(int,char **)2101d83750fSNikolas Klauser int main(int, char**) {
2111d83750fSNikolas Klauser   test();
2121d83750fSNikolas Klauser   static_assert(test());
2131d83750fSNikolas Klauser 
2141d83750fSNikolas Klauser   return 0;
2151d83750fSNikolas Klauser }
216