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, sentinel-for<I> S1, nothrow-forward-iterator O, nothrow-sentinel-for<O> S2> 14 // requires constructible_from<iter_value_t<O>, iter_reference_t<I>> 15 // uninitialized_copy_result<I, O> ranges::uninitialized_copy(I ifirst, S1 ilast, O ofirst, S2 olast); // since C++20 16 // 17 // template<input_range IR, nothrow-forward-range OR> 18 // requires constructible_from<range_value_t<OR>, range_reference_t<IR>> 19 // uninitialized_copy_result<borrowed_iterator_t<IR>, borrowed_iterator_t<OR>> ranges::uninitialized_copy(IR&& in_range, OR&& out_range); // since C++20 20 21 #include <algorithm> 22 #include <cassert> 23 #include <iterator> 24 #include <memory> 25 #include <ranges> 26 #include <type_traits> 27 28 #include "../buffer.h" 29 #include "../counted.h" 30 #include "../overload_compare_iterator.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 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 // Conversions, (iter, sentinel) overload. 282 { 283 constexpr int N = 3; 284 int in[N] = {1, 2, 3}; 285 Buffer<double, N> out; 286 287 std::ranges::uninitialized_copy(in, in + N, out.begin(), out.end()); 288 assert(std::equal(in, in + N, out.begin(), out.end())); 289 } 290 291 // Conversions, (range) overload. 292 { 293 constexpr int N = 3; 294 int in[N] = {1, 2, 3}; 295 Buffer<double, N> out; 296 297 std::ranges::uninitialized_copy(in, out); 298 assert(std::equal(in, in + N, out.begin(), out.end())); 299 } 300 301 // Destination range is shorter than the source range, (iter, sentinel) overload. 302 { 303 constexpr int M = 3; 304 constexpr int N = 5; 305 Counted in[N] = {Counted(1), Counted(2), Counted(3), Counted(4), Counted(5)}; 306 Buffer<Counted, M> out; 307 Counted::reset(); 308 309 auto result = std::ranges::uninitialized_copy(in, in + N, out.begin(), out.end()); 310 assert(Counted::current_objects == M); 311 assert(Counted::total_objects == M); 312 assert(Counted::total_copies == M); 313 assert(Counted::total_moves == 0); 314 315 assert(std::equal(in, in + M, out.begin(), out.end())); 316 assert(result.in == in + M); 317 assert(result.out == out.end()); 318 } 319 320 // Destination range is shorter than the source range, (range) overload. 321 { 322 constexpr int M = 3; 323 constexpr int N = 5; 324 Counted in[N] = {Counted(1), Counted(2), Counted(3), Counted(4), Counted(5)}; 325 Buffer<Counted, M> out; 326 Counted::reset(); 327 328 std::ranges::subrange range(in, in + N); 329 auto result = std::ranges::uninitialized_copy(range, out); 330 assert(Counted::current_objects == M); 331 assert(Counted::total_objects == M); 332 assert(Counted::total_copies == M); 333 assert(Counted::total_moves == 0); 334 335 assert(std::equal(in, in + M, out.begin(), out.end())); 336 assert(result.in == in + M); 337 assert(result.out == out.end()); 338 } 339 340 // Move-only iterators are supported. 341 { 342 using MoveOnlyIter = cpp20_input_iterator<const int*>; 343 static_assert(!std::is_copy_constructible_v<MoveOnlyIter>); 344 345 constexpr int N = 3; 346 struct MoveOnlyRange { 347 int buffer[N] = {1, 2, 3}; 348 auto begin() const { return MoveOnlyIter(buffer); } 349 auto end() const { return sentinel_wrapper<MoveOnlyIter>(MoveOnlyIter(buffer)); } 350 }; 351 static_assert(std::ranges::input_range<MoveOnlyRange>); 352 MoveOnlyRange in; 353 354 // (iter, sentinel) overload. 355 { 356 Buffer<int, N> out; 357 std::ranges::uninitialized_copy(in.begin(), in.end(), out.begin(), out.end()); 358 } 359 360 // (range) overload. 361 { 362 Buffer<int, N> out; 363 std::ranges::uninitialized_copy(in, out); 364 } 365 } 366 367 // Test with an iterator that overloads operator== and operator!= as the input and output iterators 368 { 369 using T = int; 370 using Iterator = overload_compare_iterator<T*>; 371 const int N = 5; 372 373 // input 374 { 375 char pool[sizeof(T) * N] = {0}; 376 T* p = reinterpret_cast<T*>(pool); 377 T* p_end = reinterpret_cast<T*>(pool) + N; 378 T array[N] = {1, 2, 3, 4, 5}; 379 std::ranges::uninitialized_copy(Iterator(array), Iterator(array + N), p, p_end); 380 for (int i = 0; i != N; ++i) { 381 assert(array[i] == p[i]); 382 } 383 } 384 385 // output 386 { 387 char pool[sizeof(T) * N] = {0}; 388 T* p = reinterpret_cast<T*>(pool); 389 T* p_end = reinterpret_cast<T*>(pool) + N; 390 T array[N] = {1, 2, 3, 4, 5}; 391 std::ranges::uninitialized_copy(array, array + N, Iterator(p), Iterator(p_end)); 392 for (int i = 0; i != N; ++i) { 393 assert(array[i] == p[i]); 394 } 395 } 396 } 397 398 return 0; 399 } 400