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

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