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 InputIterator, nothrow-forward-iterator OutputIterator, nothrow-sentinel-for<OutputIterator> Sentinel> 14 // requires constructible_from<iter_value_t<OutputIterator>, iter_rvalue_reference_t<InputIterator>> 15 // ranges::uninitialized_move_n_result<InputIterator, OutputIterator> 16 // ranges::uninitialized_move_n(InputIterator ifirst, iter_difference_t<InputIterator> n, OutputIterator ofirst, Sentinel olast); // since C++20 17 18 19 #include <algorithm> 20 #include <array> 21 #include <cassert> 22 #include <iterator> 23 #include <memory> 24 #include <ranges> 25 #include <type_traits> 26 #include <utility> 27 28 #include "../buffer.h" 29 #include "../counted.h" 30 #include "../overload_compare_iterator.h" 31 #include "MoveOnly.h" 32 #include "test_macros.h" 33 #include "test_iterators.h" 34 35 // TODO(varconst): consolidate the ADL checks into a single file. 36 // Because this is a variable and not a function, it's guaranteed that ADL won't be used. However, 37 // implementations are allowed to use a different mechanism to achieve this effect, so this check is 38 // libc++-specific. 39 LIBCPP_STATIC_ASSERT(std::is_class_v<decltype(std::ranges::uninitialized_move)>); 40 41 static_assert(std::is_invocable_v<decltype(std::ranges::uninitialized_move), int*, int*, long*, long*>); 42 struct NotConvertibleFromInt {}; 43 static_assert(!std::is_invocable_v<decltype(std::ranges::uninitialized_move), int*, int*, NotConvertibleFromInt*, 44 NotConvertibleFromInt*>); 45 46 int main(int, char**) { 47 // An empty range -- no default constructors should be invoked. 48 { 49 Counted in[] = {Counted()}; 50 Buffer<Counted, 1> out; 51 Counted::reset(); 52 53 { 54 auto result = std::ranges::uninitialized_move(in, in, out.begin(), out.end()); 55 assert(Counted::current_objects == 0); 56 assert(Counted::total_objects == 0); 57 assert(Counted::total_copies == 0); 58 assert(result.in == in); 59 assert(result.out == out.begin()); 60 } 61 62 { 63 std::ranges::empty_view<Counted> view; 64 auto result = std::ranges::uninitialized_move(view, out); 65 assert(Counted::current_objects == 0); 66 assert(Counted::total_objects == 0); 67 assert(Counted::total_copies == 0); 68 assert(result.in == view.begin()); 69 assert(result.out == out.begin()); 70 } 71 72 { 73 forward_iterator<Counted*> it(in); 74 std::ranges::subrange range(it, sentinel_wrapper<forward_iterator<Counted*>>(it)); 75 76 auto result = std::ranges::uninitialized_move(range.begin(), range.end(), out.begin(), out.end()); 77 assert(Counted::current_objects == 0); 78 assert(Counted::total_objects == 0); 79 assert(Counted::total_copies == 0); 80 assert(result.in == it); 81 assert(result.out == out.begin()); 82 } 83 84 { 85 forward_iterator<Counted*> it(in); 86 std::ranges::subrange range(it, sentinel_wrapper<forward_iterator<Counted*>>(it)); 87 88 auto result = std::ranges::uninitialized_move(range, out); 89 assert(Counted::current_objects == 0); 90 assert(Counted::total_objects == 0); 91 assert(Counted::total_copies == 0); 92 assert(result.in == it); 93 assert(result.out == out.begin()); 94 } 95 Counted::reset(); 96 } 97 98 // A range containing several objects, (iter, sentinel) overload. 99 { 100 constexpr int N = 5; 101 Counted in[N] = {Counted(1), Counted(2), Counted(3), Counted(4), Counted(5)}; 102 Buffer<Counted, N> out; 103 Counted::reset(); 104 105 auto result = std::ranges::uninitialized_move(in, in + N, out.begin(), out.end()); 106 ASSERT_SAME_TYPE(decltype(result), std::ranges::uninitialized_move_result<Counted*, Counted*>); 107 assert(Counted::current_objects == N); 108 assert(Counted::total_objects == N); 109 assert(Counted::total_moves == N); 110 assert(Counted::total_copies == 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_move(range, out); 129 ASSERT_SAME_TYPE(decltype(result), std::ranges::uninitialized_move_result<Counted*, Counted*>); 130 131 assert(Counted::current_objects == N); 132 assert(Counted::total_objects == N); 133 assert(Counted::total_moves == N); 134 assert(Counted::total_copies == 0); 135 assert(std::equal(in, in + N, out.begin(), out.end())); 136 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_move(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_moves == N); 157 assert(Counted::total_copies == 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_move(view, out); 176 177 assert(Counted::current_objects == N); 178 assert(Counted::total_objects == N); 179 assert(Counted::total_moves == N); 180 assert(Counted::total_copies == 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_move(view, out); 200 201 assert(Counted::current_objects == N); 202 assert(Counted::total_objects == N); 203 assert(Counted::total_moves == N); 204 assert(Counted::total_copies == 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 move 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_move(in, in + 1, out, out + N); 224 assert(out[0] == 1); 225 assert(out[1] == 7); 226 227 std::ranges::uninitialized_move(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 -- check that the objects in the source 232 // range have been moved from. (iterator, sentinel) overload. 233 #ifndef TEST_HAS_NO_EXCEPTIONS 234 { 235 constexpr int N = 3; 236 Counted in[] = {Counted(1), Counted(2), Counted(3), Counted(4), Counted(5)}; 237 Buffer<Counted, 5> out; 238 Counted::reset(); 239 240 Counted::throw_on = N; // When constructing out[3]. 241 try { 242 std::ranges::uninitialized_move(in, in + 5, out.begin(), out.end()); 243 assert(false); 244 } catch (...) { 245 } 246 assert(Counted::current_objects == 0); 247 assert(Counted::total_objects == N); 248 assert(Counted::total_moves == N); 249 assert(Counted::total_copies == 0); 250 251 assert(std::all_of(in, in + 1, [](const auto& e) { return e.moved_from; })); 252 assert(std::none_of(in + N, in + 5, [](const auto& e) { return e.moved_from; })); 253 254 std::destroy(out.begin(), out.begin() + N); 255 } 256 Counted::reset(); 257 258 // An exception is thrown while objects are being created -- check that the objects in the source 259 // range have been moved from. (range) overload. 260 { 261 constexpr int N = 3; 262 Counted in[] = {Counted(1), Counted(2), Counted(3), Counted(4), Counted(5)}; 263 Buffer<Counted, 5> out; 264 Counted::reset(); 265 266 Counted::throw_on = N; // When constructing out[3]. 267 try { 268 std::ranges::uninitialized_move(in, out); 269 assert(false); 270 } catch (...) { 271 } 272 assert(Counted::current_objects == 0); 273 assert(Counted::total_objects == N); 274 assert(Counted::total_moves == N); 275 assert(Counted::total_copies == 0); 276 277 assert(std::all_of(in, in + 1, [](const auto& e) { return e.moved_from; })); 278 assert(std::none_of(in + N, in + 5, [](const auto& e) { return e.moved_from; })); 279 280 std::destroy(out.begin(), out.begin() + N); 281 } 282 Counted::reset(); 283 #endif // TEST_HAS_NO_EXCEPTIONS 284 285 // Conversions, (iter, sentinel) overload. 286 { 287 constexpr int N = 3; 288 int in[N] = {1, 2, 3}; 289 Buffer<double, N> out; 290 291 std::ranges::uninitialized_move(in, in + N, out.begin(), out.end()); 292 assert(std::equal(in, in + N, out.begin(), out.end())); 293 } 294 295 // Conversions, (range) overload. 296 { 297 constexpr int N = 3; 298 int in[N] = {1, 2, 3}; 299 Buffer<double, N> out; 300 301 std::ranges::uninitialized_move(in, out); 302 assert(std::equal(in, in + N, out.begin(), out.end())); 303 } 304 305 // Destination range is shorter than the source range, (iter, sentinel) overload. 306 { 307 constexpr int M = 3; 308 constexpr int N = 5; 309 Counted in[N] = {Counted(1), Counted(2), Counted(3), Counted(4), Counted(5)}; 310 Buffer<Counted, M> out; 311 Counted::reset(); 312 313 auto result = std::ranges::uninitialized_move(in, in + N, out.begin(), out.end()); 314 assert(Counted::current_objects == M); 315 assert(Counted::total_objects == M); 316 assert(Counted::total_moves == M); 317 assert(Counted::total_copies == 0); 318 319 assert(std::equal(in, in + M, out.begin(), out.end())); 320 assert(result.in == in + M); 321 assert(result.out == out.end()); 322 } 323 324 // Destination range is shorter than the source range, (range) overload. 325 { 326 constexpr int M = 3; 327 constexpr int N = 5; 328 Counted in[N] = {Counted(1), Counted(2), Counted(3), Counted(4), Counted(5)}; 329 Buffer<Counted, M> out; 330 Counted::reset(); 331 332 std::ranges::subrange range(in, in + N); 333 auto result = std::ranges::uninitialized_move(range, out); 334 assert(Counted::current_objects == M); 335 assert(Counted::total_objects == M); 336 assert(Counted::total_moves == M); 337 assert(Counted::total_copies == 0); 338 339 assert(std::equal(in, in + M, out.begin(), out.end())); 340 assert(result.in == in + M); 341 assert(result.out == out.end()); 342 } 343 344 // Ensure the `iter_move` customization point is being used. 345 { 346 constexpr int N = 3; 347 int in[N] = {1, 2, 3}; 348 Buffer<int, N> out; 349 int iter_moves = 0; 350 adl::Iterator begin = adl::Iterator::TrackMoves(in, iter_moves); 351 adl::Iterator end = adl::Iterator::TrackMoves(in + N, iter_moves); 352 353 std::ranges::uninitialized_move(begin, end, out.begin(), out.end()); 354 assert(iter_moves == 3); 355 iter_moves = 0; 356 357 std::ranges::subrange range(begin, end); 358 std::ranges::uninitialized_move(range, out); 359 assert(iter_moves == 3); 360 iter_moves = 0; 361 } 362 363 // Move-only iterators are supported. 364 { 365 using MoveOnlyIter = cpp20_input_iterator<const int*>; 366 static_assert(!std::is_copy_constructible_v<MoveOnlyIter>); 367 368 constexpr int N = 3; 369 struct MoveOnlyRange { 370 int buffer[N] = {1, 2, 3}; 371 auto begin() const { return MoveOnlyIter(buffer); } 372 auto end() const { return sentinel_wrapper<MoveOnlyIter>(MoveOnlyIter(buffer)); } 373 }; 374 static_assert(std::ranges::input_range<MoveOnlyRange>); 375 MoveOnlyRange in; 376 377 // (iter, sentinel) overload. 378 { 379 Buffer<int, N> out; 380 std::ranges::uninitialized_move(in.begin(), in.end(), out.begin(), out.end()); 381 } 382 383 // (range) overload. 384 { 385 Buffer<int, N> out; 386 std::ranges::uninitialized_move(in, out); 387 } 388 } 389 390 // MoveOnly types are supported 391 { 392 { 393 MoveOnly a[] = {1, 2, 3, 4}; 394 Buffer<MoveOnly, 4> out; 395 std::ranges::uninitialized_move(std::begin(a), std::end(a), std::begin(out), std::end(out)); 396 assert(std::ranges::equal(out, std::array<MoveOnly, 4>{1, 2, 3, 4})); 397 } 398 { 399 MoveOnly a[] = {1, 2, 3, 4}; 400 Buffer<MoveOnly, 4> out; 401 std::ranges::uninitialized_move(a, out); 402 assert(std::ranges::equal(out, std::array<MoveOnly, 4>{1, 2, 3, 4})); 403 } 404 } 405 406 // Test with an iterator that overloads operator== and operator!= as the input and output iterators 407 { 408 using T = int; 409 using Iterator = overload_compare_iterator<T*>; 410 const int N = 5; 411 412 // input 413 { 414 char pool[sizeof(T) * N] = {0}; 415 T* p = reinterpret_cast<T*>(pool); 416 T* p_end = reinterpret_cast<T*>(pool) + N; 417 T array[N] = {1, 2, 3, 4, 5}; 418 std::ranges::uninitialized_move(Iterator(array), Iterator(array + N), p, p_end); 419 for (int i = 0; i != N; ++i) { 420 assert(array[i] == p[i]); 421 } 422 } 423 424 // output 425 { 426 char pool[sizeof(T) * N] = {0}; 427 T* p = reinterpret_cast<T*>(pool); 428 T* p_end = reinterpret_cast<T*>(pool) + N; 429 T array[N] = {1, 2, 3, 4, 5}; 430 std::ranges::uninitialized_move(array, array + N, Iterator(p), Iterator(p_end)); 431 for (int i = 0; i != N; ++i) { 432 assert(array[i] == p[i]); 433 } 434 } 435 } 436 437 return 0; 438 } 439