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 // Conversions.
108 {
109 constexpr int N = 3;
110 int in[N] = {1, 2, 3};
111 Buffer<double, N> out;
112
113 std::ranges::uninitialized_copy_n(in, N, out.begin(), out.end());
114 assert(std::equal(in, in + N, out.begin(), out.end()));
115 }
116
117 // Destination range is shorter than the source range.
118 {
119 constexpr int M = 3;
120 constexpr int N = 5;
121 Counted in[N] = {Counted(1), Counted(2), Counted(3), Counted(4), Counted(5)};
122 Buffer<Counted, M> out;
123 Counted::reset();
124
125 auto result = std::ranges::uninitialized_copy_n(in, N, out.begin(), out.end());
126 assert(Counted::current_objects == M);
127 assert(Counted::total_objects == M);
128 assert(Counted::total_copies == M);
129 assert(Counted::total_moves == 0);
130
131 assert(std::equal(in, in + M, out.begin(), out.end()));
132 assert(result.in == in + M);
133 assert(result.out == out.end());
134 }
135
136 // Move-only iterators are supported.
137 {
138 using MoveOnlyIter = cpp20_input_iterator<const int*>;
139 static_assert(!std::is_copy_constructible_v<MoveOnlyIter>);
140
141 constexpr int N = 3;
142 int buffer[N] = {1, 2, 3};
143
144 MoveOnlyIter in(buffer);
145 Buffer<int, N> out;
146 std::ranges::uninitialized_copy_n(std::move(in), N, out.begin(), out.end());
147 }
148
149 // Test with an iterator that overloads operator== and operator!= as the input and output iterators
150 {
151 using T = int;
152 using Iterator = overload_compare_iterator<T*>;
153 const int N = 5;
154
155 // input
156 {
157 char pool[sizeof(T) * N] = {0};
158 T* p = reinterpret_cast<T*>(pool);
159 T* p_end = reinterpret_cast<T*>(pool) + N;
160 T array[N] = {1, 2, 3, 4, 5};
161 std::ranges::uninitialized_copy_n(Iterator(array), N, p, p_end);
162 for (int i = 0; i != N; ++i) {
163 assert(array[i] == p[i]);
164 }
165 }
166
167 // output
168 {
169 char pool[sizeof(T) * N] = {0};
170 T* p = reinterpret_cast<T*>(pool);
171 T* p_end = reinterpret_cast<T*>(pool) + N;
172 T array[N] = {1, 2, 3, 4, 5};
173 std::ranges::uninitialized_copy_n(array, N, Iterator(p), Iterator(p_end));
174 for (int i = 0; i != N; ++i) {
175 assert(array[i] == p[i]);
176 }
177 }
178 }
179
180 return 0;
181}
182

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