1 // -*- C++ -*- 2 //===----------------------------------------------------------------------===// 3 // 4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5 // See https://llvm.org/LICENSE.txt for license information. 6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7 // 8 //===----------------------------------------------------------------------===// 9 10 #ifndef _LIBCPP___MEMORY_UNINITIALIZED_ALGORITHMS_H 11 #define _LIBCPP___MEMORY_UNINITIALIZED_ALGORITHMS_H 12 13 #include <__algorithm/copy.h> 14 #include <__algorithm/move.h> 15 #include <__algorithm/unwrap_iter.h> 16 #include <__algorithm/unwrap_range.h> 17 #include <__config> 18 #include <__iterator/iterator_traits.h> 19 #include <__iterator/reverse_iterator.h> 20 #include <__memory/addressof.h> 21 #include <__memory/allocator_traits.h> 22 #include <__memory/construct_at.h> 23 #include <__memory/pointer_traits.h> 24 #include <__memory/voidify.h> 25 #include <__type_traits/extent.h> 26 #include <__type_traits/is_array.h> 27 #include <__type_traits/is_constant_evaluated.h> 28 #include <__type_traits/is_trivially_copy_assignable.h> 29 #include <__type_traits/is_trivially_copy_constructible.h> 30 #include <__type_traits/is_trivially_move_assignable.h> 31 #include <__type_traits/is_trivially_move_constructible.h> 32 #include <__type_traits/is_unbounded_array.h> 33 #include <__type_traits/negation.h> 34 #include <__type_traits/remove_const.h> 35 #include <__type_traits/remove_extent.h> 36 #include <__utility/exception_guard.h> 37 #include <__utility/move.h> 38 #include <__utility/pair.h> 39 #include <new> 40 41 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 42 # pragma GCC system_header 43 #endif 44 45 _LIBCPP_BEGIN_NAMESPACE_STD 46 47 struct __always_false { 48 template <class... _Args> 49 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator()(_Args&&...) const _NOEXCEPT { 50 return false; 51 } 52 }; 53 54 // uninitialized_copy 55 56 template <class _ValueType, class _InputIterator, class _Sentinel1, class _ForwardIterator, class _EndPredicate> 57 inline _LIBCPP_HIDE_FROM_ABI pair<_InputIterator, _ForwardIterator> __uninitialized_copy( 58 _InputIterator __ifirst, _Sentinel1 __ilast, _ForwardIterator __ofirst, _EndPredicate __stop_copying) { 59 _ForwardIterator __idx = __ofirst; 60 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS 61 try { 62 #endif 63 for (; __ifirst != __ilast && !__stop_copying(__idx); ++__ifirst, (void)++__idx) 64 ::new (std::__voidify(*__idx)) _ValueType(*__ifirst); 65 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS 66 } catch (...) { 67 std::__destroy(__ofirst, __idx); 68 throw; 69 } 70 #endif 71 72 return pair<_InputIterator, _ForwardIterator>(std::move(__ifirst), std::move(__idx)); 73 } 74 75 template <class _InputIterator, class _ForwardIterator> 76 _LIBCPP_HIDE_FROM_ABI _ForwardIterator 77 uninitialized_copy(_InputIterator __ifirst, _InputIterator __ilast, _ForwardIterator __ofirst) { 78 typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType; 79 auto __result = std::__uninitialized_copy<_ValueType>( 80 std::move(__ifirst), std::move(__ilast), std::move(__ofirst), __always_false()); 81 return std::move(__result.second); 82 } 83 84 // uninitialized_copy_n 85 86 template <class _ValueType, class _InputIterator, class _Size, class _ForwardIterator, class _EndPredicate> 87 inline _LIBCPP_HIDE_FROM_ABI pair<_InputIterator, _ForwardIterator> 88 __uninitialized_copy_n(_InputIterator __ifirst, _Size __n, _ForwardIterator __ofirst, _EndPredicate __stop_copying) { 89 _ForwardIterator __idx = __ofirst; 90 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS 91 try { 92 #endif 93 for (; __n > 0 && !__stop_copying(__idx); ++__ifirst, (void)++__idx, (void)--__n) 94 ::new (std::__voidify(*__idx)) _ValueType(*__ifirst); 95 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS 96 } catch (...) { 97 std::__destroy(__ofirst, __idx); 98 throw; 99 } 100 #endif 101 102 return pair<_InputIterator, _ForwardIterator>(std::move(__ifirst), std::move(__idx)); 103 } 104 105 template <class _InputIterator, class _Size, class _ForwardIterator> 106 inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator 107 uninitialized_copy_n(_InputIterator __ifirst, _Size __n, _ForwardIterator __ofirst) { 108 typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType; 109 auto __result = 110 std::__uninitialized_copy_n<_ValueType>(std::move(__ifirst), __n, std::move(__ofirst), __always_false()); 111 return std::move(__result.second); 112 } 113 114 // uninitialized_fill 115 116 template <class _ValueType, class _ForwardIterator, class _Sentinel, class _Tp> 117 inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator 118 __uninitialized_fill(_ForwardIterator __first, _Sentinel __last, const _Tp& __x) { 119 _ForwardIterator __idx = __first; 120 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS 121 try { 122 #endif 123 for (; __idx != __last; ++__idx) 124 ::new (std::__voidify(*__idx)) _ValueType(__x); 125 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS 126 } catch (...) { 127 std::__destroy(__first, __idx); 128 throw; 129 } 130 #endif 131 132 return __idx; 133 } 134 135 template <class _ForwardIterator, class _Tp> 136 inline _LIBCPP_HIDE_FROM_ABI void 137 uninitialized_fill(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __x) { 138 typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType; 139 (void)std::__uninitialized_fill<_ValueType>(__first, __last, __x); 140 } 141 142 // uninitialized_fill_n 143 144 template <class _ValueType, class _ForwardIterator, class _Size, class _Tp> 145 inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator 146 __uninitialized_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x) { 147 _ForwardIterator __idx = __first; 148 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS 149 try { 150 #endif 151 for (; __n > 0; ++__idx, (void)--__n) 152 ::new (std::__voidify(*__idx)) _ValueType(__x); 153 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS 154 } catch (...) { 155 std::__destroy(__first, __idx); 156 throw; 157 } 158 #endif 159 160 return __idx; 161 } 162 163 template <class _ForwardIterator, class _Size, class _Tp> 164 inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator 165 uninitialized_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x) { 166 typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType; 167 return std::__uninitialized_fill_n<_ValueType>(__first, __n, __x); 168 } 169 170 #if _LIBCPP_STD_VER >= 17 171 172 // uninitialized_default_construct 173 174 template <class _ValueType, class _ForwardIterator, class _Sentinel> 175 inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator 176 __uninitialized_default_construct(_ForwardIterator __first, _Sentinel __last) { 177 auto __idx = __first; 178 # ifndef _LIBCPP_HAS_NO_EXCEPTIONS 179 try { 180 # endif 181 for (; __idx != __last; ++__idx) 182 ::new (std::__voidify(*__idx)) _ValueType; 183 # ifndef _LIBCPP_HAS_NO_EXCEPTIONS 184 } catch (...) { 185 std::__destroy(__first, __idx); 186 throw; 187 } 188 # endif 189 190 return __idx; 191 } 192 193 template <class _ForwardIterator> 194 inline _LIBCPP_HIDE_FROM_ABI void uninitialized_default_construct(_ForwardIterator __first, _ForwardIterator __last) { 195 using _ValueType = typename iterator_traits<_ForwardIterator>::value_type; 196 (void)std::__uninitialized_default_construct<_ValueType>(std::move(__first), std::move(__last)); 197 } 198 199 // uninitialized_default_construct_n 200 201 template <class _ValueType, class _ForwardIterator, class _Size> 202 inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator __uninitialized_default_construct_n(_ForwardIterator __first, _Size __n) { 203 auto __idx = __first; 204 # ifndef _LIBCPP_HAS_NO_EXCEPTIONS 205 try { 206 # endif 207 for (; __n > 0; ++__idx, (void)--__n) 208 ::new (std::__voidify(*__idx)) _ValueType; 209 # ifndef _LIBCPP_HAS_NO_EXCEPTIONS 210 } catch (...) { 211 std::__destroy(__first, __idx); 212 throw; 213 } 214 # endif 215 216 return __idx; 217 } 218 219 template <class _ForwardIterator, class _Size> 220 inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator uninitialized_default_construct_n(_ForwardIterator __first, _Size __n) { 221 using _ValueType = typename iterator_traits<_ForwardIterator>::value_type; 222 return std::__uninitialized_default_construct_n<_ValueType>(std::move(__first), __n); 223 } 224 225 // uninitialized_value_construct 226 227 template <class _ValueType, class _ForwardIterator, class _Sentinel> 228 inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator 229 __uninitialized_value_construct(_ForwardIterator __first, _Sentinel __last) { 230 auto __idx = __first; 231 # ifndef _LIBCPP_HAS_NO_EXCEPTIONS 232 try { 233 # endif 234 for (; __idx != __last; ++__idx) 235 ::new (std::__voidify(*__idx)) _ValueType(); 236 # ifndef _LIBCPP_HAS_NO_EXCEPTIONS 237 } catch (...) { 238 std::__destroy(__first, __idx); 239 throw; 240 } 241 # endif 242 243 return __idx; 244 } 245 246 template <class _ForwardIterator> 247 inline _LIBCPP_HIDE_FROM_ABI void uninitialized_value_construct(_ForwardIterator __first, _ForwardIterator __last) { 248 using _ValueType = typename iterator_traits<_ForwardIterator>::value_type; 249 (void)std::__uninitialized_value_construct<_ValueType>(std::move(__first), std::move(__last)); 250 } 251 252 // uninitialized_value_construct_n 253 254 template <class _ValueType, class _ForwardIterator, class _Size> 255 inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator __uninitialized_value_construct_n(_ForwardIterator __first, _Size __n) { 256 auto __idx = __first; 257 # ifndef _LIBCPP_HAS_NO_EXCEPTIONS 258 try { 259 # endif 260 for (; __n > 0; ++__idx, (void)--__n) 261 ::new (std::__voidify(*__idx)) _ValueType(); 262 # ifndef _LIBCPP_HAS_NO_EXCEPTIONS 263 } catch (...) { 264 std::__destroy(__first, __idx); 265 throw; 266 } 267 # endif 268 269 return __idx; 270 } 271 272 template <class _ForwardIterator, class _Size> 273 inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator uninitialized_value_construct_n(_ForwardIterator __first, _Size __n) { 274 using _ValueType = typename iterator_traits<_ForwardIterator>::value_type; 275 return std::__uninitialized_value_construct_n<_ValueType>(std::move(__first), __n); 276 } 277 278 // uninitialized_move 279 280 template <class _ValueType, 281 class _InputIterator, 282 class _Sentinel1, 283 class _ForwardIterator, 284 class _EndPredicate, 285 class _IterMove> 286 inline _LIBCPP_HIDE_FROM_ABI pair<_InputIterator, _ForwardIterator> __uninitialized_move( 287 _InputIterator __ifirst, 288 _Sentinel1 __ilast, 289 _ForwardIterator __ofirst, 290 _EndPredicate __stop_moving, 291 _IterMove __iter_move) { 292 auto __idx = __ofirst; 293 # ifndef _LIBCPP_HAS_NO_EXCEPTIONS 294 try { 295 # endif 296 for (; __ifirst != __ilast && !__stop_moving(__idx); ++__idx, (void)++__ifirst) { 297 ::new (std::__voidify(*__idx)) _ValueType(__iter_move(__ifirst)); 298 } 299 # ifndef _LIBCPP_HAS_NO_EXCEPTIONS 300 } catch (...) { 301 std::__destroy(__ofirst, __idx); 302 throw; 303 } 304 # endif 305 306 return {std::move(__ifirst), std::move(__idx)}; 307 } 308 309 template <class _InputIterator, class _ForwardIterator> 310 inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator 311 uninitialized_move(_InputIterator __ifirst, _InputIterator __ilast, _ForwardIterator __ofirst) { 312 using _ValueType = typename iterator_traits<_ForwardIterator>::value_type; 313 auto __iter_move = [](auto&& __iter) -> decltype(auto) { return std::move(*__iter); }; 314 315 auto __result = std::__uninitialized_move<_ValueType>( 316 std::move(__ifirst), std::move(__ilast), std::move(__ofirst), __always_false(), __iter_move); 317 return std::move(__result.second); 318 } 319 320 // uninitialized_move_n 321 322 template <class _ValueType, 323 class _InputIterator, 324 class _Size, 325 class _ForwardIterator, 326 class _EndPredicate, 327 class _IterMove> 328 inline _LIBCPP_HIDE_FROM_ABI pair<_InputIterator, _ForwardIterator> __uninitialized_move_n( 329 _InputIterator __ifirst, _Size __n, _ForwardIterator __ofirst, _EndPredicate __stop_moving, _IterMove __iter_move) { 330 auto __idx = __ofirst; 331 # ifndef _LIBCPP_HAS_NO_EXCEPTIONS 332 try { 333 # endif 334 for (; __n > 0 && !__stop_moving(__idx); ++__idx, (void)++__ifirst, --__n) 335 ::new (std::__voidify(*__idx)) _ValueType(__iter_move(__ifirst)); 336 # ifndef _LIBCPP_HAS_NO_EXCEPTIONS 337 } catch (...) { 338 std::__destroy(__ofirst, __idx); 339 throw; 340 } 341 # endif 342 343 return {std::move(__ifirst), std::move(__idx)}; 344 } 345 346 template <class _InputIterator, class _Size, class _ForwardIterator> 347 inline _LIBCPP_HIDE_FROM_ABI pair<_InputIterator, _ForwardIterator> 348 uninitialized_move_n(_InputIterator __ifirst, _Size __n, _ForwardIterator __ofirst) { 349 using _ValueType = typename iterator_traits<_ForwardIterator>::value_type; 350 auto __iter_move = [](auto&& __iter) -> decltype(auto) { return std::move(*__iter); }; 351 352 return std::__uninitialized_move_n<_ValueType>( 353 std::move(__ifirst), __n, std::move(__ofirst), __always_false(), __iter_move); 354 } 355 356 // TODO: Rewrite this to iterate left to right and use reverse_iterators when calling 357 // Destroys every element in the range [first, last) FROM RIGHT TO LEFT using allocator 358 // destruction. If elements are themselves C-style arrays, they are recursively destroyed 359 // in the same manner. 360 // 361 // This function assumes that destructors do not throw, and that the allocator is bound to 362 // the correct type. 363 template <class _Alloc, 364 class _BidirIter, 365 class = __enable_if_t< __has_bidirectional_iterator_category<_BidirIter>::value >> 366 _LIBCPP_HIDE_FROM_ABI constexpr void 367 __allocator_destroy_multidimensional(_Alloc& __alloc, _BidirIter __first, _BidirIter __last) noexcept { 368 using _ValueType = typename iterator_traits<_BidirIter>::value_type; 369 static_assert(is_same_v<typename allocator_traits<_Alloc>::value_type, _ValueType>, 370 "The allocator should already be rebound to the correct type"); 371 372 if (__first == __last) 373 return; 374 375 if constexpr (is_array_v<_ValueType>) { 376 static_assert(!__libcpp_is_unbounded_array<_ValueType>::value, 377 "arrays of unbounded arrays don't exist, but if they did we would mess up here"); 378 379 using _Element = remove_extent_t<_ValueType>; 380 __allocator_traits_rebind_t<_Alloc, _Element> __elem_alloc(__alloc); 381 do { 382 --__last; 383 decltype(auto) __array = *__last; 384 std::__allocator_destroy_multidimensional(__elem_alloc, __array, __array + extent_v<_ValueType>); 385 } while (__last != __first); 386 } else { 387 do { 388 --__last; 389 allocator_traits<_Alloc>::destroy(__alloc, std::addressof(*__last)); 390 } while (__last != __first); 391 } 392 } 393 394 // Constructs the object at the given location using the allocator's construct method. 395 // 396 // If the object being constructed is an array, each element of the array is allocator-constructed, 397 // recursively. If an exception is thrown during the construction of an array, the initialized 398 // elements are destroyed in reverse order of initialization using allocator destruction. 399 // 400 // This function assumes that the allocator is bound to the correct type. 401 template <class _Alloc, class _Tp> 402 _LIBCPP_HIDE_FROM_ABI constexpr void __allocator_construct_at_multidimensional(_Alloc& __alloc, _Tp* __loc) { 403 static_assert(is_same_v<typename allocator_traits<_Alloc>::value_type, _Tp>, 404 "The allocator should already be rebound to the correct type"); 405 406 if constexpr (is_array_v<_Tp>) { 407 using _Element = remove_extent_t<_Tp>; 408 __allocator_traits_rebind_t<_Alloc, _Element> __elem_alloc(__alloc); 409 size_t __i = 0; 410 _Tp& __array = *__loc; 411 412 // If an exception is thrown, destroy what we have constructed so far in reverse order. 413 auto __guard = std::__make_exception_guard([&]() { 414 std::__allocator_destroy_multidimensional(__elem_alloc, __array, __array + __i); 415 }); 416 417 for (; __i != extent_v<_Tp>; ++__i) { 418 std::__allocator_construct_at_multidimensional(__elem_alloc, std::addressof(__array[__i])); 419 } 420 __guard.__complete(); 421 } else { 422 allocator_traits<_Alloc>::construct(__alloc, __loc); 423 } 424 } 425 426 // Constructs the object at the given location using the allocator's construct method, passing along 427 // the provided argument. 428 // 429 // If the object being constructed is an array, the argument is also assumed to be an array. Each 430 // each element of the array being constructed is allocator-constructed from the corresponding 431 // element of the argument array. If an exception is thrown during the construction of an array, 432 // the initialized elements are destroyed in reverse order of initialization using allocator 433 // destruction. 434 // 435 // This function assumes that the allocator is bound to the correct type. 436 template <class _Alloc, class _Tp, class _Arg> 437 _LIBCPP_HIDE_FROM_ABI constexpr void 438 __allocator_construct_at_multidimensional(_Alloc& __alloc, _Tp* __loc, _Arg const& __arg) { 439 static_assert(is_same_v<typename allocator_traits<_Alloc>::value_type, _Tp>, 440 "The allocator should already be rebound to the correct type"); 441 442 if constexpr (is_array_v<_Tp>) { 443 static_assert(is_array_v<_Arg>, 444 "Provided non-array initialization argument to __allocator_construct_at_multidimensional when " 445 "trying to construct an array."); 446 447 using _Element = remove_extent_t<_Tp>; 448 __allocator_traits_rebind_t<_Alloc, _Element> __elem_alloc(__alloc); 449 size_t __i = 0; 450 _Tp& __array = *__loc; 451 452 // If an exception is thrown, destroy what we have constructed so far in reverse order. 453 auto __guard = std::__make_exception_guard([&]() { 454 std::__allocator_destroy_multidimensional(__elem_alloc, __array, __array + __i); 455 }); 456 for (; __i != extent_v<_Tp>; ++__i) { 457 std::__allocator_construct_at_multidimensional(__elem_alloc, std::addressof(__array[__i]), __arg[__i]); 458 } 459 __guard.__complete(); 460 } else { 461 allocator_traits<_Alloc>::construct(__alloc, __loc, __arg); 462 } 463 } 464 465 // Given a range starting at it and containing n elements, initializes each element in the 466 // range from left to right using the construct method of the allocator (rebound to the 467 // correct type). 468 // 469 // If an exception is thrown, the initialized elements are destroyed in reverse order of 470 // initialization using allocator_traits destruction. If the elements in the range are C-style 471 // arrays, they are initialized element-wise using allocator construction, and recursively so. 472 template <class _Alloc, 473 class _BidirIter, 474 class _Tp, 475 class _Size = typename iterator_traits<_BidirIter>::difference_type> 476 _LIBCPP_HIDE_FROM_ABI constexpr void 477 __uninitialized_allocator_fill_n_multidimensional(_Alloc& __alloc, _BidirIter __it, _Size __n, _Tp const& __value) { 478 using _ValueType = typename iterator_traits<_BidirIter>::value_type; 479 __allocator_traits_rebind_t<_Alloc, _ValueType> __value_alloc(__alloc); 480 _BidirIter __begin = __it; 481 482 // If an exception is thrown, destroy what we have constructed so far in reverse order. 483 auto __guard = 484 std::__make_exception_guard([&]() { std::__allocator_destroy_multidimensional(__value_alloc, __begin, __it); }); 485 for (; __n != 0; --__n, ++__it) { 486 std::__allocator_construct_at_multidimensional(__value_alloc, std::addressof(*__it), __value); 487 } 488 __guard.__complete(); 489 } 490 491 // Same as __uninitialized_allocator_fill_n_multidimensional, but doesn't pass any initialization argument 492 // to the allocator's construct method, which results in value initialization. 493 template <class _Alloc, class _BidirIter, class _Size = typename iterator_traits<_BidirIter>::difference_type> 494 _LIBCPP_HIDE_FROM_ABI constexpr void 495 __uninitialized_allocator_value_construct_n_multidimensional(_Alloc& __alloc, _BidirIter __it, _Size __n) { 496 using _ValueType = typename iterator_traits<_BidirIter>::value_type; 497 __allocator_traits_rebind_t<_Alloc, _ValueType> __value_alloc(__alloc); 498 _BidirIter __begin = __it; 499 500 // If an exception is thrown, destroy what we have constructed so far in reverse order. 501 auto __guard = 502 std::__make_exception_guard([&]() { std::__allocator_destroy_multidimensional(__value_alloc, __begin, __it); }); 503 for (; __n != 0; --__n, ++__it) { 504 std::__allocator_construct_at_multidimensional(__value_alloc, std::addressof(*__it)); 505 } 506 __guard.__complete(); 507 } 508 509 #endif // _LIBCPP_STD_VER >= 17 510 511 // Destroy all elements in [__first, __last) from left to right using allocator destruction. 512 template <class _Alloc, class _Iter, class _Sent> 513 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void 514 __allocator_destroy(_Alloc& __alloc, _Iter __first, _Sent __last) { 515 for (; __first != __last; ++__first) 516 allocator_traits<_Alloc>::destroy(__alloc, std::__to_address(__first)); 517 } 518 519 template <class _Alloc, class _Iter> 520 class _AllocatorDestroyRangeReverse { 521 public: 522 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 523 _AllocatorDestroyRangeReverse(_Alloc& __alloc, _Iter& __first, _Iter& __last) 524 : __alloc_(__alloc), __first_(__first), __last_(__last) {} 525 526 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void operator()() const { 527 std::__allocator_destroy(__alloc_, std::reverse_iterator<_Iter>(__last_), std::reverse_iterator<_Iter>(__first_)); 528 } 529 530 private: 531 _Alloc& __alloc_; 532 _Iter& __first_; 533 _Iter& __last_; 534 }; 535 536 // Copy-construct [__first1, __last1) in [__first2, __first2 + N), where N is distance(__first1, __last1). 537 // 538 // The caller has to ensure that __first2 can hold at least N uninitialized elements. If an exception is thrown the 539 // already copied elements are destroyed in reverse order of their construction. 540 template <class _Alloc, class _Iter1, class _Sent1, class _Iter2> 541 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Iter2 542 __uninitialized_allocator_copy_impl(_Alloc& __alloc, _Iter1 __first1, _Sent1 __last1, _Iter2 __first2) { 543 auto __destruct_first = __first2; 544 auto __guard = 545 std::__make_exception_guard(_AllocatorDestroyRangeReverse<_Alloc, _Iter2>(__alloc, __destruct_first, __first2)); 546 while (__first1 != __last1) { 547 allocator_traits<_Alloc>::construct(__alloc, std::__to_address(__first2), *__first1); 548 ++__first1; 549 ++__first2; 550 } 551 __guard.__complete(); 552 return __first2; 553 } 554 555 template <class _Alloc, class _Type> 556 struct __allocator_has_trivial_copy_construct : _Not<__has_construct<_Alloc, _Type*, const _Type&> > {}; 557 558 template <class _Type> 559 struct __allocator_has_trivial_copy_construct<allocator<_Type>, _Type> : true_type {}; 560 561 template <class _Alloc, 562 class _In, 563 class _RawTypeIn = __remove_const_t<_In>, 564 class _Out, 565 __enable_if_t< 566 // using _RawTypeIn because of the allocator<T const> extension 567 is_trivially_copy_constructible<_RawTypeIn>::value && is_trivially_copy_assignable<_RawTypeIn>::value && 568 is_same<__remove_const_t<_In>, __remove_const_t<_Out> >::value && 569 __allocator_has_trivial_copy_construct<_Alloc, _RawTypeIn>::value>* = nullptr> 570 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Out* 571 __uninitialized_allocator_copy_impl(_Alloc&, _In* __first1, _In* __last1, _Out* __first2) { 572 // TODO: Remove the const_cast once we drop support for std::allocator<T const> 573 if (__libcpp_is_constant_evaluated()) { 574 while (__first1 != __last1) { 575 std::__construct_at(std::__to_address(__first2), *__first1); 576 ++__first1; 577 ++__first2; 578 } 579 return __first2; 580 } else { 581 return std::copy(__first1, __last1, const_cast<_RawTypeIn*>(__first2)); 582 } 583 } 584 585 template <class _Alloc, class _Iter1, class _Sent1, class _Iter2> 586 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Iter2 587 __uninitialized_allocator_copy(_Alloc& __alloc, _Iter1 __first1, _Sent1 __last1, _Iter2 __first2) { 588 auto __unwrapped_range = std::__unwrap_range(__first1, __last1); 589 auto __result = std::__uninitialized_allocator_copy_impl( 590 __alloc, __unwrapped_range.first, __unwrapped_range.second, std::__unwrap_iter(__first2)); 591 return std::__rewrap_iter(__first2, __result); 592 } 593 594 // Move-construct the elements [__first1, __last1) into [__first2, __first2 + N) 595 // if the move constructor is noexcept, where N is distance(__first1, __last1). 596 // 597 // Otherwise try to copy all elements. If an exception is thrown the already copied 598 // elements are destroyed in reverse order of their construction. 599 template <class _Alloc, class _Iter1, class _Sent1, class _Iter2> 600 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Iter2 601 __uninitialized_allocator_move_if_noexcept(_Alloc& __alloc, _Iter1 __first1, _Sent1 __last1, _Iter2 __first2) { 602 static_assert(__is_cpp17_move_insertable<_Alloc>::value, 603 "The specified type does not meet the requirements of Cpp17MoveInsertable"); 604 auto __destruct_first = __first2; 605 auto __guard = 606 std::__make_exception_guard(_AllocatorDestroyRangeReverse<_Alloc, _Iter2>(__alloc, __destruct_first, __first2)); 607 while (__first1 != __last1) { 608 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS 609 allocator_traits<_Alloc>::construct(__alloc, std::__to_address(__first2), std::move_if_noexcept(*__first1)); 610 #else 611 allocator_traits<_Alloc>::construct(__alloc, std::__to_address(__first2), std::move(*__first1)); 612 #endif 613 ++__first1; 614 ++__first2; 615 } 616 __guard.__complete(); 617 return __first2; 618 } 619 620 template <class _Alloc, class _Type> 621 struct __allocator_has_trivial_move_construct : _Not<__has_construct<_Alloc, _Type*, _Type&&> > {}; 622 623 template <class _Type> 624 struct __allocator_has_trivial_move_construct<allocator<_Type>, _Type> : true_type {}; 625 626 #ifndef _LIBCPP_COMPILER_GCC 627 template < 628 class _Alloc, 629 class _Iter1, 630 class _Iter2, 631 class _Type = typename iterator_traits<_Iter1>::value_type, 632 class = __enable_if_t<is_trivially_move_constructible<_Type>::value && is_trivially_move_assignable<_Type>::value && 633 __allocator_has_trivial_move_construct<_Alloc, _Type>::value> > 634 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Iter2 635 __uninitialized_allocator_move_if_noexcept(_Alloc&, _Iter1 __first1, _Iter1 __last1, _Iter2 __first2) { 636 if (__libcpp_is_constant_evaluated()) { 637 while (__first1 != __last1) { 638 std::__construct_at(std::__to_address(__first2), std::move(*__first1)); 639 ++__first1; 640 ++__first2; 641 } 642 return __first2; 643 } else { 644 return std::move(__first1, __last1, __first2); 645 } 646 } 647 #endif // _LIBCPP_COMPILER_GCC 648 649 _LIBCPP_END_NAMESPACE_STD 650 651 #endif // _LIBCPP___MEMORY_UNINITIALIZED_ALGORITHMS_H 652