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 //===----------------------------------------------------------------------===//
8
9 // <algorithm>
10
11 // UNSUPPORTED: c++03, c++11, c++14, c++17
12
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);
19
20 #include <algorithm>
21 #include <array>
22 #include <cassert>
23 #include <deque>
24 #include <ranges>
25 #include <vector>
26
27 #include "almost_satisfies_types.h"
28 #include "test_iterators.h"
29 #include "type_algorithms.h"
30
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); };
33
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>);
43
44 template <class Range, class Out>
45 concept HasCopyR = requires(Range range, Out out) { std::ranges::copy(range, out); };
46
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*>);
55
56 static_assert(std::is_same_v<std::ranges::copy_result<int, long>, std::ranges::in_out_result<int, long>>);
57
58 // clang-format off
59 template <class In, class Out, class Sent = In>
test_iterators()60 constexpr void test_iterators() {
61 { // simple test
62 {
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());
70 }
71 {
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());
79 }
80 }
81
82 { // check that an empty range works
83 {
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());
89 }
90 {
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());
97 }
98 }
99 }
100 // clang-format on
101
test()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*>>>>();
108
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>>();
113
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>>>();
117 });
118 });
119
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}));
126 }
127
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<std::array<int, 4>::iterator, int*>> auto ret =
132 std::ranges::copy(std::views::all(in), out.data());
133 assert(ret.in == in.end());
134 assert(ret.out == out.data() + 4);
135 assert(in == out);
136 }
137
138 { // check that every element is copied exactly once
139 struct CopyOnce {
140 bool copied = false;
141 constexpr CopyOnce() = default;
142 constexpr CopyOnce(const CopyOnce& other) = delete;
143 constexpr CopyOnce& operator=(const CopyOnce& other) {
144 assert(!other.copied);
145 copied = true;
146 return *this;
147 }
148 };
149 {
150 std::array<CopyOnce, 4> in{};
151 std::array<CopyOnce, 4> out{};
152 auto ret = std::ranges::copy(in.begin(), in.end(), out.begin());
153 assert(ret.in == in.end());
154 assert(ret.out == out.end());
155 assert(std::all_of(out.begin(), out.end(), [](const auto& e) { return e.copied; }));
156 }
157 {
158 std::array<CopyOnce, 4> in{};
159 std::array<CopyOnce, 4> out{};
160 auto ret = std::ranges::copy(in, out.begin());
161 assert(ret.in == in.end());
162 assert(ret.out == out.end());
163 assert(std::all_of(out.begin(), out.end(), [](const auto& e) { return e.copied; }));
164 }
165 }
166
167 { // check that the range is copied forwards
168 struct OnlyForwardsCopyable {
169 OnlyForwardsCopyable* next = nullptr;
170 bool canCopy = false;
171 OnlyForwardsCopyable() = default;
172 constexpr OnlyForwardsCopyable& operator=(const OnlyForwardsCopyable&) {
173 assert(canCopy);
174 if (next != nullptr)
175 next->canCopy = true;
176 return *this;
177 }
178 };
179 {
180 std::array<OnlyForwardsCopyable, 3> in{};
181 std::array<OnlyForwardsCopyable, 3> out{};
182 out[0].next = &out[1];
183 out[1].next = &out[2];
184 out[0].canCopy = true;
185 auto ret = std::ranges::copy(in.begin(), in.end(), out.begin());
186 assert(ret.in == in.end());
187 assert(ret.out == out.end());
188 assert(out[0].canCopy);
189 assert(out[1].canCopy);
190 assert(out[2].canCopy);
191 }
192 {
193 std::array<OnlyForwardsCopyable, 3> in{};
194 std::array<OnlyForwardsCopyable, 3> out{};
195 out[0].next = &out[1];
196 out[1].next = &out[2];
197 out[0].canCopy = true;
198 auto ret = std::ranges::copy(in, out.begin());
199 assert(ret.in == in.end());
200 assert(ret.out == out.end());
201 assert(out[0].canCopy);
202 assert(out[1].canCopy);
203 assert(out[2].canCopy);
204 }
205 }
206
207 return true;
208 }
209
main(int,char **)210 int main(int, char**) {
211 test();
212 static_assert(test());
213
214 return 0;
215 }
216