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// UNSUPPORTED: c++03, c++11, c++14, c++17
10
11// <memory>
12//
13// template<input_iterator I, sentinel-for<I> S1, nothrow-forward-iterator O, nothrow-sentinel-for<O> S2>
14// requires constructible_from<iter_value_t<O>, iter_reference_t<I>>
15// uninitialized_copy_result<I, O> ranges::uninitialized_copy(I ifirst, S1 ilast, O ofirst, S2 olast); // since C++20
16//
17// template<input_range IR, nothrow-forward-range OR>
18// requires constructible_from<range_value_t<OR>, range_reference_t<IR>>
19// uninitialized_copy_result<borrowed_iterator_t<IR>, borrowed_iterator_t<OR>> ranges::uninitialized_copy(IR&& in_range, OR&& out_range); // since C++20
20
21#include <algorithm>
22#include <cassert>
23#include <iterator>
24#include <memory>
25#include <ranges>
26#include <type_traits>
27
28#include "../buffer.h"
29#include "../counted.h"
30#include "../overload_compare_iterator.h"
31#include "test_macros.h"
32#include "test_iterators.h"
33
34// TODO(varconst): consolidate the ADL checks into a single file.
35// Because this is a variable and not a function, it's guaranteed that ADL won't be used. However,
36// implementations are allowed to use a different mechanism to achieve this effect, so this check is
37// libc++-specific.
38LIBCPP_STATIC_ASSERT(std::is_class_v<decltype(std::ranges::uninitialized_copy)>);
39
40static_assert(std::is_invocable_v<decltype(std::ranges::uninitialized_copy), int*, int*, long*, long*>);
41struct NotConvertibleFromInt {};
42static_assert(!std::is_invocable_v<decltype(std::ranges::uninitialized_copy), int*, int*, NotConvertibleFromInt*,
43 NotConvertibleFromInt*>);
44
45int main(int, char**) {
46 // An empty range -- no default constructors should be invoked.
47 {
48 Counted in[] = {Counted()};
49 Buffer<Counted, 1> out;
50 Counted::reset();
51
52 {
53 auto result = std::ranges::uninitialized_copy(in, in, out.begin(), out.end());
54 assert(Counted::current_objects == 0);
55 assert(Counted::total_objects == 0);
56 assert(Counted::total_copies == 0);
57 assert(result.in == in);
58 assert(result.out == out.begin());
59 }
60
61 {
62 std::ranges::empty_view<Counted> view;
63 auto result = std::ranges::uninitialized_copy(view, out);
64 assert(Counted::current_objects == 0);
65 assert(Counted::total_objects == 0);
66 assert(Counted::total_copies == 0);
67 assert(result.in == view.begin());
68 assert(result.out == out.begin());
69 }
70
71 {
72 forward_iterator<Counted*> it(in);
73 std::ranges::subrange range(it, sentinel_wrapper<forward_iterator<Counted*>>(it));
74
75 auto result = std::ranges::uninitialized_copy(range.begin(), range.end(), out.begin(), out.end());
76 assert(Counted::current_objects == 0);
77 assert(Counted::total_objects == 0);
78 assert(Counted::total_copies == 0);
79 assert(result.in == it);
80 assert(result.out == out.begin());
81 }
82
83 {
84 forward_iterator<Counted*> it(in);
85 std::ranges::subrange range(it, sentinel_wrapper<forward_iterator<Counted*>>(it));
86
87 auto result = std::ranges::uninitialized_copy(range, out);
88 assert(Counted::current_objects == 0);
89 assert(Counted::total_objects == 0);
90 assert(Counted::total_copies == 0);
91 assert(result.in == it);
92 assert(result.out == out.begin());
93 }
94 Counted::reset();
95 }
96
97 // A range containing several objects, (iter, sentinel) overload.
98 {
99 constexpr int N = 5;
100 Counted in[N] = {Counted(1), Counted(2), Counted(3), Counted(4), Counted(5)};
101 Buffer<Counted, N> out;
102 Counted::reset();
103
104 auto result = std::ranges::uninitialized_copy(in, in + N, out.begin(), out.end());
105 ASSERT_SAME_TYPE(decltype(result), std::ranges::uninitialized_copy_result<Counted*, Counted*>);
106
107 assert(Counted::current_objects == N);
108 assert(Counted::total_objects == N);
109 assert(Counted::total_copies == N);
110 assert(Counted::total_moves == 0);
111
112 assert(std::equal(in, in + N, out.begin(), out.end()));
113 assert(result.in == in + N);
114 assert(result.out == out.end());
115
116 std::destroy(first: out.begin(), last: out.end());
117 }
118 Counted::reset();
119
120 // A range containing several objects, (range) overload.
121 {
122 constexpr int N = 5;
123 Counted in[N] = {Counted(1), Counted(2), Counted(3), Counted(4), Counted(5)};
124 Buffer<Counted, N> out;
125 Counted::reset();
126
127 std::ranges::subrange range(in, in + N);
128 auto result = std::ranges::uninitialized_copy(range, out);
129 ASSERT_SAME_TYPE(decltype(result), std::ranges::uninitialized_copy_result<Counted*, Counted*>);
130
131 assert(Counted::current_objects == N);
132 assert(Counted::total_objects == N);
133 assert(Counted::total_copies == N);
134 assert(Counted::total_moves == 0);
135
136 assert(std::equal(in, in + N, out.begin(), out.end()));
137 assert(result.in == in + N);
138 assert(result.out == out.end());
139
140 std::destroy(first: out.begin(), last: out.end());
141 }
142 Counted::reset();
143
144 // Using `counted_iterator`.
145 {
146 constexpr int N = 3;
147 Counted in[] = {Counted(1), Counted(2), Counted(3), Counted(4), Counted(5)};
148 Buffer<Counted, 5> out;
149 Counted::reset();
150
151 std::counted_iterator iter(in, N);
152 auto result = std::ranges::uninitialized_copy(iter, std::default_sentinel, out.begin(), out.end());
153
154 assert(Counted::current_objects == N);
155 assert(Counted::total_objects == N);
156 assert(Counted::total_copies == N);
157 assert(Counted::total_moves == 0);
158 assert(std::equal(in, in + N, out.begin(), out.begin() + N));
159
160 assert(result.in == iter + N);
161 assert(result.out == out.begin() + N);
162
163 std::destroy(first: out.begin(), last: out.begin() + N);
164 }
165 Counted::reset();
166
167 // Using `views::counted`.
168 {
169 constexpr int N = 3;
170 Counted in[] = {Counted(1), Counted(2), Counted(3), Counted(4), Counted(5)};
171 Buffer<Counted, 5> out;
172 Counted::reset();
173
174 auto view = std::views::counted(in, N);
175 auto result = std::ranges::uninitialized_copy(view, out);
176
177 assert(Counted::current_objects == N);
178 assert(Counted::total_objects == N);
179 assert(Counted::total_copies == N);
180 assert(Counted::total_moves == 0);
181 assert(std::equal(in, in + N, out.begin(), out.begin() + N));
182
183 assert(result.in == view.begin() + N);
184 assert(result.out == out.begin() + N);
185
186 std::destroy(first: out.begin(), last: out.begin() + N);
187 }
188 Counted::reset();
189
190 // Using `reverse_view`.
191 {
192 constexpr int N = 3;
193 Counted in[] = {Counted(1), Counted(2), Counted(3), Counted(4), Counted(5)};
194 Buffer<Counted, 5> out;
195 Counted::reset();
196
197 std::ranges::subrange range(in, in + N);
198 auto view = std::ranges::views::reverse(range);
199 auto result = std::ranges::uninitialized_copy(view, out);
200
201 assert(Counted::current_objects == N);
202 assert(Counted::total_objects == N);
203 assert(Counted::total_copies == N);
204 assert(Counted::total_moves == 0);
205
206 Counted expected[N] = {Counted(3), Counted(2), Counted(1)};
207 assert(std::equal(out.begin(), out.begin() + N, expected, expected + N));
208
209 assert(result.in == view.begin() + N);
210 assert(result.out == out.begin() + N);
211
212 std::destroy(first: out.begin(), last: out.begin() + N);
213 }
214 Counted::reset();
215
216 // Any existing values should be overwritten by copy constructors.
217 {
218 constexpr int N = 5;
219 int in[N] = {1, 2, 3, 4, 5};
220 int out[N] = {6, 7, 8, 9, 10};
221 assert(!std::equal(in, in + N, out, out + N));
222
223 std::ranges::uninitialized_copy(in, in + 1, out, out + N);
224 assert(out[0] == 1);
225 assert(out[1] == 7);
226
227 std::ranges::uninitialized_copy(in, in + N, out, out + N);
228 assert(std::equal(in, in + N, out, out + N));
229 }
230
231 // An exception is thrown while objects are being created -- objects not yet overwritten should
232 // stay valid. (iterator, sentinel) overload.
233#ifndef TEST_HAS_NO_EXCEPTIONS
234 {
235 constexpr int M = 3;
236 constexpr int N = 5;
237 Counted in[N] = {Counted(1), Counted(2), Counted(3), Counted(4), Counted(5)};
238 Counted out[N] = {Counted(6), Counted(7), Counted(8), Counted(9), Counted(10)};
239 Counted::reset();
240
241 Counted::throw_on = M; // When constructing out[3].
242 try {
243 std::ranges::uninitialized_copy(in, in + N, out, out + N);
244 assert(false);
245 } catch (...) {
246 }
247 assert(Counted::current_objects == 0);
248 assert(Counted::total_objects == M);
249 assert(Counted::total_copies == M);
250 assert(Counted::total_moves == 0);
251
252 assert(out[4].value == 10);
253 }
254 Counted::reset();
255
256 // An exception is thrown while objects are being created -- objects not yet overwritten should
257 // stay valid. (range) overload.
258 {
259 constexpr int M = 3;
260 constexpr int N = 5;
261 Counted in[N] = {Counted(1), Counted(2), Counted(3), Counted(4), Counted(5)};
262 Counted out[N] = {Counted(6), Counted(7), Counted(8), Counted(9), Counted(10)};
263 Counted::reset();
264
265 Counted::throw_on = M; // When constructing out[3].
266 try {
267 std::ranges::uninitialized_copy(in, out);
268 assert(false);
269 } catch (...) {
270 }
271 assert(Counted::current_objects == 0);
272 assert(Counted::total_objects == M);
273 assert(Counted::total_copies == M);
274 assert(Counted::total_moves == 0);
275
276 assert(out[4].value == 10);
277 }
278 Counted::reset();
279#endif // TEST_HAS_NO_EXCEPTIONS
280
281 // Works with const iterators, (iter, sentinel) overload.
282 {
283 constexpr int N = 5;
284 Counted in[N] = {Counted(1), Counted(2), Counted(3), Counted(4), Counted(5)};
285 Buffer<Counted, N> out;
286 Counted::reset();
287
288 std::ranges::uninitialized_copy(in, in + N, out.cbegin(), out.cend());
289 assert(Counted::current_objects == N);
290 assert(Counted::total_objects == N);
291 assert(std::equal(in, in + N, out.begin(), out.end()));
292
293 std::destroy(first: out.begin(), last: out.end());
294 }
295 Counted::reset();
296
297 // Works with const iterators, (range) overload.
298 {
299 constexpr int N = 5;
300 Counted in[N] = {Counted(1), Counted(2), Counted(3), Counted(4), Counted(5)};
301 Buffer<Counted, N> out;
302 Counted::reset();
303
304 std::ranges::subrange out_range(out.cbegin(), out.cend());
305 std::ranges::uninitialized_copy(in, out_range);
306 assert(Counted::current_objects == N);
307 assert(Counted::total_objects == N);
308 assert(std::equal(in, in + N, out.begin(), out.end()));
309
310 std::destroy(first: out.begin(), last: out.end());
311 }
312 Counted::reset();
313
314 // Conversions, (iter, sentinel) overload.
315 {
316 constexpr int N = 3;
317 int in[N] = {1, 2, 3};
318 Buffer<double, N> out;
319
320 std::ranges::uninitialized_copy(in, in + N, out.begin(), out.end());
321 assert(std::equal(in, in + N, out.begin(), out.end()));
322 }
323
324 // Conversions, (range) overload.
325 {
326 constexpr int N = 3;
327 int in[N] = {1, 2, 3};
328 Buffer<double, N> out;
329
330 std::ranges::uninitialized_copy(in, out);
331 assert(std::equal(in, in + N, out.begin(), out.end()));
332 }
333
334 // Destination range is shorter than the source range, (iter, sentinel) overload.
335 {
336 constexpr int M = 3;
337 constexpr int N = 5;
338 Counted in[N] = {Counted(1), Counted(2), Counted(3), Counted(4), Counted(5)};
339 Buffer<Counted, M> out;
340 Counted::reset();
341
342 auto result = std::ranges::uninitialized_copy(in, in + N, out.begin(), out.end());
343 assert(Counted::current_objects == M);
344 assert(Counted::total_objects == M);
345 assert(Counted::total_copies == M);
346 assert(Counted::total_moves == 0);
347
348 assert(std::equal(in, in + M, out.begin(), out.end()));
349 assert(result.in == in + M);
350 assert(result.out == out.end());
351 }
352
353 // Destination range is shorter than the source range, (range) overload.
354 {
355 constexpr int M = 3;
356 constexpr int N = 5;
357 Counted in[N] = {Counted(1), Counted(2), Counted(3), Counted(4), Counted(5)};
358 Buffer<Counted, M> out;
359 Counted::reset();
360
361 std::ranges::subrange range(in, in + N);
362 auto result = std::ranges::uninitialized_copy(range, out);
363 assert(Counted::current_objects == M);
364 assert(Counted::total_objects == M);
365 assert(Counted::total_copies == M);
366 assert(Counted::total_moves == 0);
367
368 assert(std::equal(in, in + M, out.begin(), out.end()));
369 assert(result.in == in + M);
370 assert(result.out == out.end());
371 }
372
373 // Move-only iterators are supported.
374 {
375 using MoveOnlyIter = cpp20_input_iterator<const int*>;
376 static_assert(!std::is_copy_constructible_v<MoveOnlyIter>);
377
378 constexpr int N = 3;
379 struct MoveOnlyRange {
380 int buffer[N] = {1, 2, 3};
381 auto begin() const { return MoveOnlyIter(buffer); }
382 auto end() const { return sentinel_wrapper<MoveOnlyIter>(MoveOnlyIter(buffer)); }
383 };
384 static_assert(std::ranges::input_range<MoveOnlyRange>);
385 MoveOnlyRange in;
386
387 // (iter, sentinel) overload.
388 {
389 Buffer<int, N> out;
390 std::ranges::uninitialized_copy(in.begin(), in.end(), out.begin(), out.end());
391 }
392
393 // (range) overload.
394 {
395 Buffer<int, N> out;
396 std::ranges::uninitialized_copy(in, out);
397 }
398 }
399
400 // Test with an iterator that overloads operator== and operator!= as the input and output iterators
401 {
402 using T = int;
403 using Iterator = overload_compare_iterator<T*>;
404 const int N = 5;
405
406 // input
407 {
408 char pool[sizeof(T) * N] = {0};
409 T* p = reinterpret_cast<T*>(pool);
410 T* p_end = reinterpret_cast<T*>(pool) + N;
411 T array[N] = {1, 2, 3, 4, 5};
412 std::ranges::uninitialized_copy(Iterator(array), Iterator(array + N), p, p_end);
413 for (int i = 0; i != N; ++i) {
414 assert(array[i] == p[i]);
415 }
416 }
417
418 // output
419 {
420 char pool[sizeof(T) * N] = {0};
421 T* p = reinterpret_cast<T*>(pool);
422 T* p_end = reinterpret_cast<T*>(pool) + N;
423 T array[N] = {1, 2, 3, 4, 5};
424 std::ranges::uninitialized_copy(array, array + N, Iterator(p), Iterator(p_end));
425 for (int i = 0; i != N; ++i) {
426 assert(array[i] == p[i]);
427 }
428 }
429 }
430
431 return 0;
432}
433

source code of libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.copy/ranges_uninitialized_copy.pass.cpp