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 // UNSUPPORTED: libcpp-has-no-incomplete-ranges
11 
12 // <memory>
13 //
14 // template<input_iterator I, sentinel-for<I> S1, nothrow-forward-iterator O, nothrow-sentinel-for<O> S2>
15 //   requires constructible_from<iter_value_t<O>, iter_reference_t<I>>
16 // uninitialized_copy_result<I, O> ranges::uninitialized_copy(I ifirst, S1 ilast, O ofirst, S2 olast); // since C++20
17 //
18 // template<input_range IR, nothrow-forward-range OR>
19 //   requires constructible_from<range_value_t<OR>, range_reference_t<IR>>
20 // uninitialized_copy_result<borrowed_iterator_t<IR>, borrowed_iterator_t<OR>> ranges::uninitialized_copy(IR&& in_range, OR&& out_range); // since C++20
21 
22 #include <algorithm>
23 #include <cassert>
24 #include <iterator>
25 #include <memory>
26 #include <ranges>
27 #include <type_traits>
28 
29 #include "../buffer.h"
30 #include "../counted.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.
38 LIBCPP_STATIC_ASSERT(std::is_class_v<decltype(std::ranges::uninitialized_copy)>);
39 
40 static_assert(std::is_invocable_v<decltype(std::ranges::uninitialized_copy), int*, int*, long*, long*>);
41 struct NotConvertibleFromInt {};
42 static_assert(!std::is_invocable_v<decltype(std::ranges::uninitialized_copy), int*, int*, NotConvertibleFromInt*,
43                                    NotConvertibleFromInt*>);
44 
main(int,char **)45 int 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(out.begin(), 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(out.begin(), 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(out.begin(), 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(out.begin(), 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(out.begin(), 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(out.begin(), 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(out.begin(), 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   return 0;
401 }
402