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 InputIterator, nothrow-forward-iterator OutputIterator, nothrow-sentinel-for<OutputIterator> Sentinel>
14// requires constructible_from<iter_value_t<OutputIterator>, iter_rvalue_reference_t<InputIterator>>
15// ranges::uninitialized_move_n_result<InputIterator, OutputIterator>
16// ranges::uninitialized_move_n(InputIterator ifirst, iter_difference_t<InputIterator> n, OutputIterator ofirst, Sentinel olast); // since C++20
17
18
19#include <algorithm>
20#include <array>
21#include <cassert>
22#include <iterator>
23#include <memory>
24#include <ranges>
25#include <type_traits>
26#include <utility>
27
28#include "../buffer.h"
29#include "../counted.h"
30#include "../overload_compare_iterator.h"
31#include "MoveOnly.h"
32#include "test_macros.h"
33#include "test_iterators.h"
34
35// TODO(varconst): consolidate the ADL checks into a single file.
36// Because this is a variable and not a function, it's guaranteed that ADL won't be used. However,
37// implementations are allowed to use a different mechanism to achieve this effect, so this check is
38// libc++-specific.
39LIBCPP_STATIC_ASSERT(std::is_class_v<decltype(std::ranges::uninitialized_move)>);
40
41static_assert(std::is_invocable_v<decltype(std::ranges::uninitialized_move), int*, int*, long*, long*>);
42struct NotConvertibleFromInt {};
43static_assert(!std::is_invocable_v<decltype(std::ranges::uninitialized_move), int*, int*, NotConvertibleFromInt*,
44 NotConvertibleFromInt*>);
45
46int main(int, char**) {
47 // An empty range -- no default constructors should be invoked.
48 {
49 Counted in[] = {Counted()};
50 Buffer<Counted, 1> out;
51 Counted::reset();
52
53 {
54 auto result = std::ranges::uninitialized_move(in, in, out.begin(), out.end());
55 assert(Counted::current_objects == 0);
56 assert(Counted::total_objects == 0);
57 assert(Counted::total_copies == 0);
58 assert(result.in == in);
59 assert(result.out == out.begin());
60 }
61
62 {
63 std::ranges::empty_view<Counted> view;
64 auto result = std::ranges::uninitialized_move(view, out);
65 assert(Counted::current_objects == 0);
66 assert(Counted::total_objects == 0);
67 assert(Counted::total_copies == 0);
68 assert(result.in == view.begin());
69 assert(result.out == out.begin());
70 }
71
72 {
73 forward_iterator<Counted*> it(in);
74 std::ranges::subrange range(it, sentinel_wrapper<forward_iterator<Counted*>>(it));
75
76 auto result = std::ranges::uninitialized_move(range.begin(), range.end(), out.begin(), out.end());
77 assert(Counted::current_objects == 0);
78 assert(Counted::total_objects == 0);
79 assert(Counted::total_copies == 0);
80 assert(result.in == it);
81 assert(result.out == out.begin());
82 }
83
84 {
85 forward_iterator<Counted*> it(in);
86 std::ranges::subrange range(it, sentinel_wrapper<forward_iterator<Counted*>>(it));
87
88 auto result = std::ranges::uninitialized_move(range, out);
89 assert(Counted::current_objects == 0);
90 assert(Counted::total_objects == 0);
91 assert(Counted::total_copies == 0);
92 assert(result.in == it);
93 assert(result.out == out.begin());
94 }
95 Counted::reset();
96 }
97
98 // A range containing several objects, (iter, sentinel) overload.
99 {
100 constexpr int N = 5;
101 Counted in[N] = {Counted(1), Counted(2), Counted(3), Counted(4), Counted(5)};
102 Buffer<Counted, N> out;
103 Counted::reset();
104
105 auto result = std::ranges::uninitialized_move(in, in + N, out.begin(), out.end());
106 ASSERT_SAME_TYPE(decltype(result), std::ranges::uninitialized_move_result<Counted*, Counted*>);
107 assert(Counted::current_objects == N);
108 assert(Counted::total_objects == N);
109 assert(Counted::total_moves == N);
110 assert(Counted::total_copies == 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_move(range, out);
129 ASSERT_SAME_TYPE(decltype(result), std::ranges::uninitialized_move_result<Counted*, Counted*>);
130
131 assert(Counted::current_objects == N);
132 assert(Counted::total_objects == N);
133 assert(Counted::total_moves == N);
134 assert(Counted::total_copies == 0);
135 assert(std::equal(in, in + N, out.begin(), out.end()));
136
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_move(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_moves == N);
157 assert(Counted::total_copies == 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_move(view, out);
176
177 assert(Counted::current_objects == N);
178 assert(Counted::total_objects == N);
179 assert(Counted::total_moves == N);
180 assert(Counted::total_copies == 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_move(view, out);
200
201 assert(Counted::current_objects == N);
202 assert(Counted::total_objects == N);
203 assert(Counted::total_moves == N);
204 assert(Counted::total_copies == 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 move 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_move(in, in + 1, out, out + N);
224 assert(out[0] == 1);
225 assert(out[1] == 7);
226
227 std::ranges::uninitialized_move(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 -- check that the objects in the source
232 // range have been moved from. (iterator, sentinel) overload.
233#ifndef TEST_HAS_NO_EXCEPTIONS
234 {
235 constexpr int N = 3;
236 Counted in[] = {Counted(1), Counted(2), Counted(3), Counted(4), Counted(5)};
237 Buffer<Counted, 5> out;
238 Counted::reset();
239
240 Counted::throw_on = N; // When constructing out[3].
241 try {
242 std::ranges::uninitialized_move(in, in + 5, out.begin(), out.end());
243 assert(false);
244 } catch (...) {
245 }
246 assert(Counted::current_objects == 0);
247 assert(Counted::total_objects == N);
248 assert(Counted::total_moves == N);
249 assert(Counted::total_copies == 0);
250
251 assert(std::all_of(in, in + 1, [](const auto& e) { return e.moved_from; }));
252 assert(std::none_of(in + N, in + 5, [](const auto& e) { return e.moved_from; }));
253
254 std::destroy(first: out.begin(), last: out.begin() + N);
255 }
256 Counted::reset();
257
258 // An exception is thrown while objects are being created -- check that the objects in the source
259 // range have been moved from. (range) overload.
260 {
261 constexpr int N = 3;
262 Counted in[] = {Counted(1), Counted(2), Counted(3), Counted(4), Counted(5)};
263 Buffer<Counted, 5> out;
264 Counted::reset();
265
266 Counted::throw_on = N; // When constructing out[3].
267 try {
268 std::ranges::uninitialized_move(in, out);
269 assert(false);
270 } catch (...) {
271 }
272 assert(Counted::current_objects == 0);
273 assert(Counted::total_objects == N);
274 assert(Counted::total_moves == N);
275 assert(Counted::total_copies == 0);
276
277 assert(std::all_of(in, in + 1, [](const auto& e) { return e.moved_from; }));
278 assert(std::none_of(in + N, in + 5, [](const auto& e) { return e.moved_from; }));
279
280 std::destroy(first: out.begin(), last: out.begin() + N);
281 }
282 Counted::reset();
283#endif // TEST_HAS_NO_EXCEPTIONS
284
285 // Works with const iterators, (iter, sentinel) overload.
286 {
287 constexpr int N = 5;
288 Counted in[N] = {Counted(1), Counted(2), Counted(3), Counted(4), Counted(5)};
289 Buffer<Counted, N> out;
290 Counted::reset();
291
292 std::ranges::uninitialized_move(in, in + N, out.cbegin(), out.cend());
293 assert(Counted::current_objects == N);
294 assert(Counted::total_objects == N);
295 assert(std::equal(in, in + N, out.begin(), out.end()));
296
297 std::destroy(first: out.begin(), last: out.end());
298 }
299 Counted::reset();
300
301 // Works with const iterators, (range) overload.
302 {
303 constexpr int N = 5;
304 Counted in[N] = {Counted(1), Counted(2), Counted(3), Counted(4), Counted(5)};
305 Buffer<Counted, N> out;
306 Counted::reset();
307
308 std::ranges::subrange out_range (out.cbegin(), out.cend());
309 std::ranges::uninitialized_move(in, out_range);
310 assert(Counted::current_objects == N);
311 assert(Counted::total_objects == N);
312 assert(std::equal(in, in + N, out.begin(), out.end()));
313
314 std::destroy(first: out.begin(), last: out.end());
315 }
316 Counted::reset();
317
318 // Conversions, (iter, sentinel) overload.
319 {
320 constexpr int N = 3;
321 int in[N] = {1, 2, 3};
322 Buffer<double, N> out;
323
324 std::ranges::uninitialized_move(in, in + N, out.begin(), out.end());
325 assert(std::equal(in, in + N, out.begin(), out.end()));
326 }
327
328 // Conversions, (range) overload.
329 {
330 constexpr int N = 3;
331 int in[N] = {1, 2, 3};
332 Buffer<double, N> out;
333
334 std::ranges::uninitialized_move(in, out);
335 assert(std::equal(in, in + N, out.begin(), out.end()));
336 }
337
338 // Destination range is shorter than the source range, (iter, sentinel) overload.
339 {
340 constexpr int M = 3;
341 constexpr int N = 5;
342 Counted in[N] = {Counted(1), Counted(2), Counted(3), Counted(4), Counted(5)};
343 Buffer<Counted, M> out;
344 Counted::reset();
345
346 auto result = std::ranges::uninitialized_move(in, in + N, out.begin(), out.end());
347 assert(Counted::current_objects == M);
348 assert(Counted::total_objects == M);
349 assert(Counted::total_moves == M);
350 assert(Counted::total_copies == 0);
351
352 assert(std::equal(in, in + M, out.begin(), out.end()));
353 assert(result.in == in + M);
354 assert(result.out == out.end());
355 }
356
357 // Destination range is shorter than the source range, (range) overload.
358 {
359 constexpr int M = 3;
360 constexpr int N = 5;
361 Counted in[N] = {Counted(1), Counted(2), Counted(3), Counted(4), Counted(5)};
362 Buffer<Counted, M> out;
363 Counted::reset();
364
365 std::ranges::subrange range(in, in + N);
366 auto result = std::ranges::uninitialized_move(range, out);
367 assert(Counted::current_objects == M);
368 assert(Counted::total_objects == M);
369 assert(Counted::total_moves == M);
370 assert(Counted::total_copies == 0);
371
372 assert(std::equal(in, in + M, out.begin(), out.end()));
373 assert(result.in == in + M);
374 assert(result.out == out.end());
375 }
376
377 // Ensure the `iter_move` customization point is being used.
378 {
379 constexpr int N = 3;
380 int in[N] = {1, 2, 3};
381 Buffer<int, N> out;
382 int iter_moves = 0;
383 adl::Iterator begin = adl::Iterator::TrackMoves(in, iter_moves);
384 adl::Iterator end = adl::Iterator::TrackMoves(in + N, iter_moves);
385
386 std::ranges::uninitialized_move(begin, end, out.begin(), out.end());
387 assert(iter_moves == 3);
388 iter_moves = 0;
389
390 std::ranges::subrange range(begin, end);
391 std::ranges::uninitialized_move(range, out);
392 assert(iter_moves == 3);
393 iter_moves = 0;
394 }
395
396 // Move-only iterators are supported.
397 {
398 using MoveOnlyIter = cpp20_input_iterator<const int*>;
399 static_assert(!std::is_copy_constructible_v<MoveOnlyIter>);
400
401 constexpr int N = 3;
402 struct MoveOnlyRange {
403 int buffer[N] = {1, 2, 3};
404 auto begin() const { return MoveOnlyIter(buffer); }
405 auto end() const { return sentinel_wrapper<MoveOnlyIter>(MoveOnlyIter(buffer)); }
406 };
407 static_assert(std::ranges::input_range<MoveOnlyRange>);
408 MoveOnlyRange in;
409
410 // (iter, sentinel) overload.
411 {
412 Buffer<int, N> out;
413 std::ranges::uninitialized_move(in.begin(), in.end(), out.begin(), out.end());
414 }
415
416 // (range) overload.
417 {
418 Buffer<int, N> out;
419 std::ranges::uninitialized_move(in, out);
420 }
421 }
422
423 // MoveOnly types are supported
424 {
425 {
426 MoveOnly a[] = {1, 2, 3, 4};
427 Buffer<MoveOnly, 4> out;
428 std::ranges::uninitialized_move(std::begin(a), std::end(a), std::begin(out), std::end(out));
429 assert(std::ranges::equal(out, std::array<MoveOnly, 4>{1, 2, 3, 4}));
430 }
431 {
432 MoveOnly a[] = {1, 2, 3, 4};
433 Buffer<MoveOnly, 4> out;
434 std::ranges::uninitialized_move(a, out);
435 assert(std::ranges::equal(out, std::array<MoveOnly, 4>{1, 2, 3, 4}));
436 }
437 }
438
439 // Test with an iterator that overloads operator== and operator!= as the input and output iterators
440 {
441 using T = int;
442 using Iterator = overload_compare_iterator<T*>;
443 const int N = 5;
444
445 // input
446 {
447 char pool[sizeof(T) * N] = {0};
448 T* p = reinterpret_cast<T*>(pool);
449 T* p_end = reinterpret_cast<T*>(pool) + N;
450 T array[N] = {1, 2, 3, 4, 5};
451 std::ranges::uninitialized_move(Iterator(array), Iterator(array + N), p, p_end);
452 for (int i = 0; i != N; ++i) {
453 assert(array[i] == p[i]);
454 }
455 }
456
457 // output
458 {
459 char pool[sizeof(T) * N] = {0};
460 T* p = reinterpret_cast<T*>(pool);
461 T* p_end = reinterpret_cast<T*>(pool) + N;
462 T array[N] = {1, 2, 3, 4, 5};
463 std::ranges::uninitialized_move(array, array + N, Iterator(p), Iterator(p_end));
464 for (int i = 0; i != N; ++i) {
465 assert(array[i] == p[i]);
466 }
467 }
468 }
469
470 return 0;
471}
472

source code of libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move.pass.cpp