Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / libcxx / test / std / algorithms / alg.modifying.operations / alg.copy / ranges.copy.pass.cpp
blobbc9c2788293cd48e34f8c664fdad1d3da0f4fdc3
1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 // <algorithm>
11 // UNSUPPORTED: c++03, c++11, c++14, c++17
13 // template<input_iterator I, sentinel_for<I> S, weakly_incrementable O>
14 // requires indirectly_copyable<I, O>
15 // constexpr ranges::copy_result<I, O> ranges::copy(I first, S last, O result);
16 // template<input_range R, weakly_incrementable O>
17 // requires indirectly_copyable<iterator_t<R>, O>
18 // constexpr ranges::copy_result<borrowed_iterator_t<R>, O> ranges::copy(R&& r, O result);
20 #include <algorithm>
21 #include <array>
22 #include <cassert>
23 #include <deque>
24 #include <ranges>
25 #include <vector>
27 #include "almost_satisfies_types.h"
28 #include "test_iterators.h"
29 #include "type_algorithms.h"
31 template <class In, class Out = In, class Sent = sentinel_wrapper<In>>
32 concept HasCopyIt = requires(In in, Sent sent, Out out) { std::ranges::copy(in, sent, out); };
34 static_assert(HasCopyIt<int*>);
35 static_assert(!HasCopyIt<InputIteratorNotDerivedFrom>);
36 static_assert(!HasCopyIt<InputIteratorNotIndirectlyReadable>);
37 static_assert(!HasCopyIt<InputIteratorNotInputOrOutputIterator>);
38 static_assert(!HasCopyIt<int*, WeaklyIncrementableNotMovable>);
39 struct NotIndirectlyCopyable {};
40 static_assert(!HasCopyIt<int*, NotIndirectlyCopyable*>);
41 static_assert(!HasCopyIt<int*, int*, SentinelForNotSemiregular>);
42 static_assert(!HasCopyIt<int*, int*, SentinelForNotWeaklyEqualityComparableWith>);
44 template <class Range, class Out>
45 concept HasCopyR = requires(Range range, Out out) { std::ranges::copy(range, out); };
47 static_assert(HasCopyR<std::array<int, 10>, int*>);
48 static_assert(!HasCopyR<InputRangeNotDerivedFrom, int*>);
49 static_assert(!HasCopyR<InputRangeNotIndirectlyReadable, int*>);
50 static_assert(!HasCopyR<InputRangeNotInputOrOutputIterator, int*>);
51 static_assert(!HasCopyR<WeaklyIncrementableNotMovable, int*>);
52 static_assert(!HasCopyR<UncheckedRange<NotIndirectlyCopyable*>, int*>);
53 static_assert(!HasCopyR<InputRangeNotSentinelSemiregular, int*>);
54 static_assert(!HasCopyR<InputRangeNotSentinelEqualityComparableWith, int*>);
56 static_assert(std::is_same_v<std::ranges::copy_result<int, long>, std::ranges::in_out_result<int, long>>);
58 // clang-format off
59 template <class In, class Out, class Sent = In>
60 constexpr void test_iterators() {
61 { // simple test
63 std::array in{1, 2, 3, 4};
64 std::array<int, 4> out;
65 std::same_as<std::ranges::in_out_result<In, Out>> auto ret =
66 std::ranges::copy(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data()));
67 assert(in == out);
68 assert(base(ret.in) == in.data() + in.size());
69 assert(base(ret.out) == out.data() + out.size());
72 std::array in{1, 2, 3, 4};
73 std::array<int, 4> out;
74 auto range = std::ranges::subrange(In(in.data()), Sent(In(in.data() + in.size())));
75 std::same_as<std::ranges::in_out_result<In, Out>> auto ret = std::ranges::copy(range, Out(out.data()));
76 assert(in == out);
77 assert(base(ret.in) == in.data() + in.size());
78 assert(base(ret.out) == out.data() + out.size());
82 { // check that an empty range works
84 std::array<int, 0> in;
85 std::array<int, 0> out;
86 auto ret = std::ranges::copy(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data()));
87 assert(base(ret.in) == in.data());
88 assert(base(ret.out) == out.data());
91 std::array<int, 0> in;
92 std::array<int, 0> out;
93 auto range = std::ranges::subrange(In(in.data()), Sent(In(in.data() + in.size())));
94 auto ret = std::ranges::copy(range, Out(out.data()));
95 assert(base(ret.in) == in.data());
96 assert(base(ret.out) == out.data());
100 // clang-format on
102 constexpr bool test() {
103 types::for_each(types::forward_iterator_list<int*>{}, []<class Out>() {
104 test_iterators<cpp20_input_iterator<int*>, Out, sentinel_wrapper<cpp20_input_iterator<int*>>>();
105 test_iterators<ProxyIterator<cpp20_input_iterator<int*>>,
106 ProxyIterator<Out>,
107 sentinel_wrapper<ProxyIterator<cpp20_input_iterator<int*>>>>();
109 types::for_each(types::forward_iterator_list<int*>{}, []<class In>() {
110 test_iterators<In, Out>();
111 test_iterators<In, Out, sized_sentinel<In>>();
112 test_iterators<In, Out, sentinel_wrapper<In>>();
114 test_iterators<ProxyIterator<In>, ProxyIterator<Out>>();
115 test_iterators<ProxyIterator<In>, ProxyIterator<Out>, sized_sentinel<ProxyIterator<In>>>();
116 test_iterators<ProxyIterator<In>, ProxyIterator<Out>, sentinel_wrapper<ProxyIterator<In>>>();
120 { // check that ranges::dangling is returned
121 std::array<int, 4> out;
122 std::same_as<std::ranges::in_out_result<std::ranges::dangling, int*>> auto ret =
123 std::ranges::copy(std::array{1, 2, 3, 4}, out.data());
124 assert(ret.out == out.data() + 4);
125 assert((out == std::array{1, 2, 3, 4}));
128 { // check that an iterator is returned with a borrowing range
129 std::array in{1, 2, 3, 4};
130 std::array<int, 4> out;
131 std::same_as<std::ranges::in_out_result<int*, int*>> auto ret = std::ranges::copy(std::views::all(in), out.data());
132 assert(ret.in == in.data() + 4);
133 assert(ret.out == out.data() + 4);
134 assert(in == out);
137 { // check that every element is copied exactly once
138 struct CopyOnce {
139 bool copied = false;
140 constexpr CopyOnce() = default;
141 constexpr CopyOnce(const CopyOnce& other) = delete;
142 constexpr CopyOnce& operator=(const CopyOnce& other) {
143 assert(!other.copied);
144 copied = true;
145 return *this;
149 std::array<CopyOnce, 4> in{};
150 std::array<CopyOnce, 4> out{};
151 auto ret = std::ranges::copy(in.begin(), in.end(), out.begin());
152 assert(ret.in == in.end());
153 assert(ret.out == out.end());
154 assert(std::all_of(out.begin(), out.end(), [](const auto& e) { return e.copied; }));
157 std::array<CopyOnce, 4> in{};
158 std::array<CopyOnce, 4> out{};
159 auto ret = std::ranges::copy(in, out.begin());
160 assert(ret.in == in.end());
161 assert(ret.out == out.end());
162 assert(std::all_of(out.begin(), out.end(), [](const auto& e) { return e.copied; }));
166 { // check that the range is copied forwards
167 struct OnlyForwardsCopyable {
168 OnlyForwardsCopyable* next = nullptr;
169 bool canCopy = false;
170 OnlyForwardsCopyable() = default;
171 constexpr OnlyForwardsCopyable& operator=(const OnlyForwardsCopyable&) {
172 assert(canCopy);
173 if (next != nullptr)
174 next->canCopy = true;
175 return *this;
179 std::array<OnlyForwardsCopyable, 3> in{};
180 std::array<OnlyForwardsCopyable, 3> out{};
181 out[0].next = &out[1];
182 out[1].next = &out[2];
183 out[0].canCopy = true;
184 auto ret = std::ranges::copy(in.begin(), in.end(), out.begin());
185 assert(ret.in == in.end());
186 assert(ret.out == out.end());
187 assert(out[0].canCopy);
188 assert(out[1].canCopy);
189 assert(out[2].canCopy);
192 std::array<OnlyForwardsCopyable, 3> in{};
193 std::array<OnlyForwardsCopyable, 3> out{};
194 out[0].next = &out[1];
195 out[1].next = &out[2];
196 out[0].canCopy = true;
197 auto ret = std::ranges::copy(in, out.begin());
198 assert(ret.in == in.end());
199 assert(ret.out == out.end());
200 assert(out[0].canCopy);
201 assert(out[1].canCopy);
202 assert(out[2].canCopy);
206 return true;
209 int main(int, char**) {
210 test();
211 static_assert(test());
213 return 0;