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, nothrow-forward-iterator O, nothrow-sentinel-for<O> S>
14// requires constructible_from<iter_value_t<O>, iter_reference_t<I>>
15// uninitialized_copy_n_result<I, O> uninitialized_copy_n(I ifirst, iter_difference_t<I> n, O ofirst, S olast); // since C++20
16
17#include <algorithm>
18#include <array>
19#include <cassert>
20#include <iterator>
21#include <memory>
22#include <ranges>
23#include <type_traits>
24
25#include "../buffer.h"
26#include "../counted.h"
27#include "../overload_compare_iterator.h"
28#include "MoveOnly.h"
29#include "test_iterators.h"
30#include "test_macros.h"
31
32// TODO(varconst): consolidate the ADL checks into a single file.
33// Because this is a variable and not a function, it's guaranteed that ADL won't be used. However,
34// implementations are allowed to use a different mechanism to achieve this effect, so this check is
35// libc++-specific.
36LIBCPP_STATIC_ASSERT(std::is_class_v<decltype(std::ranges::uninitialized_move_n)>);
37
38static_assert(std::is_invocable_v<decltype(std::ranges::uninitialized_move_n), int*, std::size_t, long*, long*>);
39struct NotConvertibleFromInt {};
40static_assert(!std::is_invocable_v<decltype(std::ranges::uninitialized_move_n), int*, std::size_t, NotConvertibleFromInt*,
41 NotConvertibleFromInt*>);
42
43int main(int, char**) {
44 // An empty range -- no default constructors should be invoked.
45 {
46 Counted in[] = {Counted()};
47 Buffer<Counted, 1> out;
48 Counted::reset();
49
50 auto result = std::ranges::uninitialized_move_n(in, 0, out.begin(), out.end());
51 assert(Counted::current_objects == 0);
52 assert(Counted::total_objects == 0);
53 assert(Counted::total_copies == 0);
54 assert(result.in == in);
55 assert(result.out == out.begin());
56 }
57 Counted::reset();
58
59 // A range containing several objects.
60 {
61 constexpr int N = 5;
62 Counted in[N] = {Counted(1), Counted(2), Counted(3), Counted(4), Counted(5)};
63 Buffer<Counted, N> out;
64 Counted::reset();
65
66 auto result = std::ranges::uninitialized_move_n(in, N, out.begin(), out.end());
67 ASSERT_SAME_TYPE(decltype(result), std::ranges::uninitialized_move_n_result<Counted*, Counted*>);
68
69 assert(Counted::current_objects == N);
70 assert(Counted::total_objects == N);
71 assert(Counted::total_moves == N);
72 assert(Counted::total_copies == 0);
73
74 assert(std::equal(in, in + N, out.begin(), out.end()));
75 assert(result.in == in + N);
76 assert(result.out == out.end());
77
78 std::destroy(first: out.begin(), last: out.end());
79 }
80 Counted::reset();
81
82 // An exception is thrown while objects are being created -- the existing objects should stay
83 // valid. (iterator, sentinel) overload.
84#ifndef TEST_HAS_NO_EXCEPTIONS
85 {
86 constexpr int N = 3;
87 Counted in[] = {Counted(1), Counted(2), Counted(3), Counted(4), Counted(5)};
88 Buffer<Counted, 5> out;
89 Counted::reset();
90
91 Counted::throw_on = N; // When constructing out[3].
92 try {
93 std::ranges::uninitialized_move_n(in, 5, out.begin(), out.end());
94 assert(false);
95 } catch (...) {
96 }
97 assert(Counted::current_objects == 0);
98 assert(Counted::total_objects == N);
99 assert(Counted::total_moves == N);
100 assert(Counted::total_copies == 0);
101
102 std::destroy(first: out.begin(), last: out.begin() + N);
103 }
104 Counted::reset();
105
106#endif // TEST_HAS_NO_EXCEPTIONS
107
108 // Works with const iterators.
109 {
110 constexpr int N = 5;
111 Counted in[N] = {Counted(1), Counted(2), Counted(3), Counted(4), Counted(5)};
112 Buffer<Counted, N> out;
113 Counted::reset();
114
115 std::ranges::uninitialized_move_n(in, N, out.cbegin(), out.cend());
116 assert(Counted::current_objects == N);
117 assert(Counted::total_objects == N);
118 assert(std::equal(in, in + N, out.begin(), out.end()));
119
120 std::destroy(first: out.begin(), last: out.end());
121 }
122 Counted::reset();
123
124 // Conversions.
125 {
126 constexpr int N = 3;
127 int in[N] = {1, 2, 3};
128 Buffer<double, N> out;
129
130 std::ranges::uninitialized_move_n(in, N, out.begin(), out.end());
131 assert(std::equal(in, in + N, out.begin(), out.end()));
132 }
133
134 // Destination range is shorter than the source range.
135 {
136 constexpr int M = 3;
137 constexpr int N = 5;
138 Counted in[N] = {Counted(1), Counted(2), Counted(3), Counted(4), Counted(5)};
139 Buffer<Counted, M> out;
140 Counted::reset();
141
142 auto result = std::ranges::uninitialized_move_n(in, N, out.begin(), out.end());
143 assert(Counted::current_objects == M);
144 assert(Counted::total_objects == M);
145 assert(Counted::total_moves == M);
146 assert(Counted::total_copies == 0);
147
148 assert(std::equal(in, in + M, out.begin(), out.end()));
149 assert(result.in == in + M);
150 assert(result.out == out.end());
151 }
152
153 // Ensure the `iter_move` customization point is being used.
154 {
155 constexpr int N = 3;
156 int in[N] = {1, 2, 3};
157 Buffer<int, N> out;
158 int iter_moves = 0;
159 adl::Iterator begin = adl::Iterator::TrackMoves(in, iter_moves);
160 adl::Iterator end = adl::Iterator::TrackMoves(in + N, iter_moves);
161
162 std::ranges::uninitialized_move(begin, end, out.begin(), out.end());
163 assert(iter_moves == 3);
164 iter_moves = 0;
165
166 std::ranges::subrange range(begin, end);
167 std::ranges::uninitialized_move(range, out);
168 assert(iter_moves == 3);
169 iter_moves = 0;
170 }
171
172 // Move-only iterators are supported.
173 {
174 using MoveOnlyIter = cpp20_input_iterator<const int*>;
175 static_assert(!std::is_copy_constructible_v<MoveOnlyIter>);
176
177 constexpr int N = 3;
178 int buffer[N] = {1, 2, 3};
179
180 MoveOnlyIter in(buffer);
181 Buffer<int, N> out;
182 std::ranges::uninitialized_move_n(std::move(in), N, out.begin(), out.end());
183 }
184
185 // MoveOnly types are supported
186 {
187 {
188 MoveOnly a[] = {1, 2, 3, 4};
189 Buffer<MoveOnly, 4> out;
190 std::ranges::uninitialized_move_n(std::begin(a), std::size(a), std::begin(out), std::end(out));
191 assert(std::ranges::equal(out, std::array<MoveOnly, 4>{1, 2, 3, 4}));
192 }
193 }
194
195 // Test with an iterator that overloads operator== and operator!= as the input and output iterators
196 {
197 using T = int;
198 using Iterator = overload_compare_iterator<T*>;
199 const int N = 5;
200
201 // input
202 {
203 char pool[sizeof(T) * N] = {0};
204 T* p = reinterpret_cast<T*>(pool);
205 T* p_end = reinterpret_cast<T*>(pool) + N;
206 T array[N] = {1, 2, 3, 4, 5};
207 std::ranges::uninitialized_move_n(Iterator(array), N, p, p_end);
208 for (int i = 0; i != N; ++i) {
209 assert(array[i] == p[i]);
210 }
211 }
212
213 // output
214 {
215 char pool[sizeof(T) * N] = {0};
216 T* p = reinterpret_cast<T*>(pool);
217 T* p_end = reinterpret_cast<T*>(pool) + N;
218 T array[N] = {1, 2, 3, 4, 5};
219 std::ranges::uninitialized_move_n(array, N, Iterator(p), Iterator(p_end));
220 for (int i = 0; i != N; ++i) {
221 assert(array[i] == p[i]);
222 }
223 }
224 }
225
226 return 0;
227}
228

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