2 //===----------------------------------------------------------------------===//
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
8 //===----------------------------------------------------------------------===//
10 #ifndef _LIBCPP___MEMORY_UNINITIALIZED_ALGORITHMS_H
11 #define _LIBCPP___MEMORY_UNINITIALIZED_ALGORITHMS_H
13 #include <__algorithm/copy.h>
14 #include <__algorithm/move.h>
15 #include <__algorithm/unwrap_iter.h>
16 #include <__algorithm/unwrap_range.h>
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>
41 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
42 # pragma GCC system_header
45 _LIBCPP_BEGIN_NAMESPACE_STD
47 struct __always_false
{
48 template <class... _Args
>
49 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR
bool operator()(_Args
&&...) const _NOEXCEPT
{
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
63 for (; __ifirst
!= __ilast
&& !__stop_copying(__idx
); ++__ifirst
, (void)++__idx
)
64 ::new (_VSTD::__voidify(*__idx
)) _ValueType(*__ifirst
);
65 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
67 _VSTD::__destroy(__ofirst
, __idx
);
72 return pair
<_InputIterator
, _ForwardIterator
>(_VSTD::move(__ifirst
), _VSTD::move(__idx
));
75 template <class _InputIterator
, class _ForwardIterator
>
77 _ForwardIterator
uninitialized_copy(_InputIterator __ifirst
, _InputIterator __ilast
,
78 _ForwardIterator __ofirst
) {
79 typedef typename iterator_traits
<_ForwardIterator
>::value_type _ValueType
;
80 auto __result
= std::__uninitialized_copy
<_ValueType
>(
81 std::move(__ifirst
), std::move(__ilast
), std::move(__ofirst
), __always_false());
82 return _VSTD::move(__result
.second
);
85 // uninitialized_copy_n
87 template <class _ValueType
, class _InputIterator
, class _Size
, class _ForwardIterator
, class _EndPredicate
>
88 inline _LIBCPP_HIDE_FROM_ABI pair
<_InputIterator
, _ForwardIterator
> __uninitialized_copy_n(
89 _InputIterator __ifirst
, _Size __n
, _ForwardIterator __ofirst
, _EndPredicate __stop_copying
) {
90 _ForwardIterator __idx
= __ofirst
;
91 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
94 for (; __n
> 0 && !__stop_copying(__idx
); ++__ifirst
, (void)++__idx
, (void)--__n
)
95 ::new (_VSTD::__voidify(*__idx
)) _ValueType(*__ifirst
);
96 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
98 _VSTD::__destroy(__ofirst
, __idx
);
103 return pair
<_InputIterator
, _ForwardIterator
>(_VSTD::move(__ifirst
), _VSTD::move(__idx
));
106 template <class _InputIterator
, class _Size
, class _ForwardIterator
>
107 inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator
uninitialized_copy_n(_InputIterator __ifirst
, _Size __n
,
108 _ForwardIterator __ofirst
) {
109 typedef typename iterator_traits
<_ForwardIterator
>::value_type _ValueType
;
111 std::__uninitialized_copy_n
<_ValueType
>(std::move(__ifirst
), __n
, std::move(__ofirst
), __always_false());
112 return _VSTD::move(__result
.second
);
115 // uninitialized_fill
117 template <class _ValueType
, class _ForwardIterator
, class _Sentinel
, class _Tp
>
118 inline _LIBCPP_HIDE_FROM_ABI
119 _ForwardIterator
__uninitialized_fill(_ForwardIterator __first
, _Sentinel __last
, const _Tp
& __x
)
121 _ForwardIterator __idx
= __first
;
122 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
126 for (; __idx
!= __last
; ++__idx
)
127 ::new (_VSTD::__voidify(*__idx
)) _ValueType(__x
);
128 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
132 _VSTD::__destroy(__first
, __idx
);
140 template <class _ForwardIterator
, class _Tp
>
141 inline _LIBCPP_HIDE_FROM_ABI
142 void uninitialized_fill(_ForwardIterator __first
, _ForwardIterator __last
, const _Tp
& __x
)
144 typedef typename iterator_traits
<_ForwardIterator
>::value_type _ValueType
;
145 (void)_VSTD::__uninitialized_fill
<_ValueType
>(__first
, __last
, __x
);
148 // uninitialized_fill_n
150 template <class _ValueType
, class _ForwardIterator
, class _Size
, class _Tp
>
151 inline _LIBCPP_HIDE_FROM_ABI
152 _ForwardIterator
__uninitialized_fill_n(_ForwardIterator __first
, _Size __n
, const _Tp
& __x
)
154 _ForwardIterator __idx
= __first
;
155 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
159 for (; __n
> 0; ++__idx
, (void) --__n
)
160 ::new (_VSTD::__voidify(*__idx
)) _ValueType(__x
);
161 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
165 _VSTD::__destroy(__first
, __idx
);
173 template <class _ForwardIterator
, class _Size
, class _Tp
>
174 inline _LIBCPP_HIDE_FROM_ABI
175 _ForwardIterator
uninitialized_fill_n(_ForwardIterator __first
, _Size __n
, const _Tp
& __x
)
177 typedef typename iterator_traits
<_ForwardIterator
>::value_type _ValueType
;
178 return _VSTD::__uninitialized_fill_n
<_ValueType
>(__first
, __n
, __x
);
181 #if _LIBCPP_STD_VER >= 17
183 // uninitialized_default_construct
185 template <class _ValueType
, class _ForwardIterator
, class _Sentinel
>
186 inline _LIBCPP_HIDE_FROM_ABI
187 _ForwardIterator
__uninitialized_default_construct(_ForwardIterator __first
, _Sentinel __last
) {
188 auto __idx
= __first
;
189 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
192 for (; __idx
!= __last
; ++__idx
)
193 ::new (_VSTD::__voidify(*__idx
)) _ValueType
;
194 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
196 _VSTD::__destroy(__first
, __idx
);
204 template <class _ForwardIterator
>
205 inline _LIBCPP_HIDE_FROM_ABI
206 void uninitialized_default_construct(_ForwardIterator __first
, _ForwardIterator __last
) {
207 using _ValueType
= typename iterator_traits
<_ForwardIterator
>::value_type
;
208 (void)_VSTD::__uninitialized_default_construct
<_ValueType
>(
209 _VSTD::move(__first
), _VSTD::move(__last
));
212 // uninitialized_default_construct_n
214 template <class _ValueType
, class _ForwardIterator
, class _Size
>
215 inline _LIBCPP_HIDE_FROM_ABI
216 _ForwardIterator
__uninitialized_default_construct_n(_ForwardIterator __first
, _Size __n
) {
217 auto __idx
= __first
;
218 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
221 for (; __n
> 0; ++__idx
, (void) --__n
)
222 ::new (_VSTD::__voidify(*__idx
)) _ValueType
;
223 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
225 _VSTD::__destroy(__first
, __idx
);
233 template <class _ForwardIterator
, class _Size
>
234 inline _LIBCPP_HIDE_FROM_ABI
235 _ForwardIterator
uninitialized_default_construct_n(_ForwardIterator __first
, _Size __n
) {
236 using _ValueType
= typename iterator_traits
<_ForwardIterator
>::value_type
;
237 return _VSTD::__uninitialized_default_construct_n
<_ValueType
>(_VSTD::move(__first
), __n
);
240 // uninitialized_value_construct
242 template <class _ValueType
, class _ForwardIterator
, class _Sentinel
>
243 inline _LIBCPP_HIDE_FROM_ABI
244 _ForwardIterator
__uninitialized_value_construct(_ForwardIterator __first
, _Sentinel __last
) {
245 auto __idx
= __first
;
246 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
249 for (; __idx
!= __last
; ++__idx
)
250 ::new (_VSTD::__voidify(*__idx
)) _ValueType();
251 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
253 _VSTD::__destroy(__first
, __idx
);
261 template <class _ForwardIterator
>
262 inline _LIBCPP_HIDE_FROM_ABI
263 void uninitialized_value_construct(_ForwardIterator __first
, _ForwardIterator __last
) {
264 using _ValueType
= typename iterator_traits
<_ForwardIterator
>::value_type
;
265 (void)_VSTD::__uninitialized_value_construct
<_ValueType
>(
266 _VSTD::move(__first
), _VSTD::move(__last
));
269 // uninitialized_value_construct_n
271 template <class _ValueType
, class _ForwardIterator
, class _Size
>
272 inline _LIBCPP_HIDE_FROM_ABI
273 _ForwardIterator
__uninitialized_value_construct_n(_ForwardIterator __first
, _Size __n
) {
274 auto __idx
= __first
;
275 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
278 for (; __n
> 0; ++__idx
, (void) --__n
)
279 ::new (_VSTD::__voidify(*__idx
)) _ValueType();
280 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
282 _VSTD::__destroy(__first
, __idx
);
290 template <class _ForwardIterator
, class _Size
>
291 inline _LIBCPP_HIDE_FROM_ABI
292 _ForwardIterator
uninitialized_value_construct_n(_ForwardIterator __first
, _Size __n
) {
293 using _ValueType
= typename iterator_traits
<_ForwardIterator
>::value_type
;
294 return std::__uninitialized_value_construct_n
<_ValueType
>(_VSTD::move(__first
), __n
);
297 // uninitialized_move
299 template <class _ValueType
,
300 class _InputIterator
,
302 class _ForwardIterator
,
305 inline _LIBCPP_HIDE_FROM_ABI pair
<_InputIterator
, _ForwardIterator
> __uninitialized_move(
306 _InputIterator __ifirst
,
308 _ForwardIterator __ofirst
,
309 _EndPredicate __stop_moving
,
310 _IterMove __iter_move
) {
311 auto __idx
= __ofirst
;
312 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
315 for (; __ifirst
!= __ilast
&& !__stop_moving(__idx
); ++__idx
, (void)++__ifirst
) {
316 ::new (_VSTD::__voidify(*__idx
)) _ValueType(__iter_move(__ifirst
));
318 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
320 _VSTD::__destroy(__ofirst
, __idx
);
325 return {_VSTD::move(__ifirst
), _VSTD::move(__idx
)};
328 template <class _InputIterator
, class _ForwardIterator
>
329 inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator
uninitialized_move(_InputIterator __ifirst
, _InputIterator __ilast
,
330 _ForwardIterator __ofirst
) {
331 using _ValueType
= typename iterator_traits
<_ForwardIterator
>::value_type
;
332 auto __iter_move
= [](auto&& __iter
) -> decltype(auto) { return _VSTD::move(*__iter
); };
334 auto __result
= std::__uninitialized_move
<_ValueType
>(
335 std::move(__ifirst
), std::move(__ilast
), std::move(__ofirst
), __always_false(), __iter_move
);
336 return _VSTD::move(__result
.second
);
339 // uninitialized_move_n
341 template <class _ValueType
,
342 class _InputIterator
,
344 class _ForwardIterator
,
347 inline _LIBCPP_HIDE_FROM_ABI pair
<_InputIterator
, _ForwardIterator
> __uninitialized_move_n(
348 _InputIterator __ifirst
, _Size __n
, _ForwardIterator __ofirst
, _EndPredicate __stop_moving
, _IterMove __iter_move
) {
349 auto __idx
= __ofirst
;
350 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
353 for (; __n
> 0 && !__stop_moving(__idx
); ++__idx
, (void)++__ifirst
, --__n
)
354 ::new (_VSTD::__voidify(*__idx
)) _ValueType(__iter_move(__ifirst
));
355 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
357 _VSTD::__destroy(__ofirst
, __idx
);
362 return {_VSTD::move(__ifirst
), _VSTD::move(__idx
)};
365 template <class _InputIterator
, class _Size
, class _ForwardIterator
>
366 inline _LIBCPP_HIDE_FROM_ABI pair
<_InputIterator
, _ForwardIterator
>
367 uninitialized_move_n(_InputIterator __ifirst
, _Size __n
, _ForwardIterator __ofirst
) {
368 using _ValueType
= typename iterator_traits
<_ForwardIterator
>::value_type
;
369 auto __iter_move
= [](auto&& __iter
) -> decltype(auto) { return _VSTD::move(*__iter
); };
371 return std::__uninitialized_move_n
<_ValueType
>(
372 std::move(__ifirst
), __n
, std::move(__ofirst
), __always_false(), __iter_move
);
375 // TODO: Rewrite this to iterate left to right and use reverse_iterators when calling
376 // Destroys every element in the range [first, last) FROM RIGHT TO LEFT using allocator
377 // destruction. If elements are themselves C-style arrays, they are recursively destroyed
378 // in the same manner.
380 // This function assumes that destructors do not throw, and that the allocator is bound to
382 template<class _Alloc
, class _BidirIter
, class = __enable_if_t
<
383 __has_bidirectional_iterator_category
<_BidirIter
>::value
385 _LIBCPP_HIDE_FROM_ABI
386 constexpr void __allocator_destroy_multidimensional(_Alloc
& __alloc
, _BidirIter __first
, _BidirIter __last
) noexcept
{
387 using _ValueType
= typename iterator_traits
<_BidirIter
>::value_type
;
388 static_assert(is_same_v
<typename allocator_traits
<_Alloc
>::value_type
, _ValueType
>,
389 "The allocator should already be rebound to the correct type");
391 if (__first
== __last
)
394 if constexpr (is_array_v
<_ValueType
>) {
395 static_assert(!__libcpp_is_unbounded_array
<_ValueType
>::value
,
396 "arrays of unbounded arrays don't exist, but if they did we would mess up here");
398 using _Element
= remove_extent_t
<_ValueType
>;
399 __allocator_traits_rebind_t
<_Alloc
, _Element
> __elem_alloc(__alloc
);
402 decltype(auto) __array
= *__last
;
403 std::__allocator_destroy_multidimensional(__elem_alloc
, __array
, __array
+ extent_v
<_ValueType
>);
404 } while (__last
!= __first
);
408 allocator_traits
<_Alloc
>::destroy(__alloc
, std::addressof(*__last
));
409 } while (__last
!= __first
);
413 // Constructs the object at the given location using the allocator's construct method.
415 // If the object being constructed is an array, each element of the array is allocator-constructed,
416 // recursively. If an exception is thrown during the construction of an array, the initialized
417 // elements are destroyed in reverse order of initialization using allocator destruction.
419 // This function assumes that the allocator is bound to the correct type.
420 template<class _Alloc
, class _Tp
>
421 _LIBCPP_HIDE_FROM_ABI
422 constexpr void __allocator_construct_at_multidimensional(_Alloc
& __alloc
, _Tp
* __loc
) {
423 static_assert(is_same_v
<typename allocator_traits
<_Alloc
>::value_type
, _Tp
>,
424 "The allocator should already be rebound to the correct type");
426 if constexpr (is_array_v
<_Tp
>) {
427 using _Element
= remove_extent_t
<_Tp
>;
428 __allocator_traits_rebind_t
<_Alloc
, _Element
> __elem_alloc(__alloc
);
430 _Tp
& __array
= *__loc
;
432 // If an exception is thrown, destroy what we have constructed so far in reverse order.
433 auto __guard
= std::__make_exception_guard([&]() {
434 std::__allocator_destroy_multidimensional(__elem_alloc
, __array
, __array
+ __i
);
437 for (; __i
!= extent_v
<_Tp
>; ++__i
) {
438 std::__allocator_construct_at_multidimensional(__elem_alloc
, std::addressof(__array
[__i
]));
440 __guard
.__complete();
442 allocator_traits
<_Alloc
>::construct(__alloc
, __loc
);
446 // Constructs the object at the given location using the allocator's construct method, passing along
447 // the provided argument.
449 // If the object being constructed is an array, the argument is also assumed to be an array. Each
450 // each element of the array being constructed is allocator-constructed from the corresponding
451 // element of the argument array. If an exception is thrown during the construction of an array,
452 // the initialized elements are destroyed in reverse order of initialization using allocator
455 // This function assumes that the allocator is bound to the correct type.
456 template<class _Alloc
, class _Tp
, class _Arg
>
457 _LIBCPP_HIDE_FROM_ABI
458 constexpr void __allocator_construct_at_multidimensional(_Alloc
& __alloc
, _Tp
* __loc
, _Arg
const& __arg
) {
459 static_assert(is_same_v
<typename allocator_traits
<_Alloc
>::value_type
, _Tp
>,
460 "The allocator should already be rebound to the correct type");
462 if constexpr (is_array_v
<_Tp
>) {
463 static_assert(is_array_v
<_Arg
>,
464 "Provided non-array initialization argument to __allocator_construct_at_multidimensional when "
465 "trying to construct an array.");
467 using _Element
= remove_extent_t
<_Tp
>;
468 __allocator_traits_rebind_t
<_Alloc
, _Element
> __elem_alloc(__alloc
);
470 _Tp
& __array
= *__loc
;
472 // If an exception is thrown, destroy what we have constructed so far in reverse order.
473 auto __guard
= std::__make_exception_guard([&]() {
474 std::__allocator_destroy_multidimensional(__elem_alloc
, __array
, __array
+ __i
);
476 for (; __i
!= extent_v
<_Tp
>; ++__i
) {
477 std::__allocator_construct_at_multidimensional(__elem_alloc
, std::addressof(__array
[__i
]), __arg
[__i
]);
479 __guard
.__complete();
481 allocator_traits
<_Alloc
>::construct(__alloc
, __loc
, __arg
);
485 // Given a range starting at it and containing n elements, initializes each element in the
486 // range from left to right using the construct method of the allocator (rebound to the
489 // If an exception is thrown, the initialized elements are destroyed in reverse order of
490 // initialization using allocator_traits destruction. If the elements in the range are C-style
491 // arrays, they are initialized element-wise using allocator construction, and recursively so.
492 template<class _Alloc
, class _BidirIter
, class _Tp
, class _Size
= typename iterator_traits
<_BidirIter
>::difference_type
>
493 _LIBCPP_HIDE_FROM_ABI
constexpr void
494 __uninitialized_allocator_fill_n_multidimensional(_Alloc
& __alloc
, _BidirIter __it
, _Size __n
, _Tp
const& __value
) {
495 using _ValueType
= typename iterator_traits
<_BidirIter
>::value_type
;
496 __allocator_traits_rebind_t
<_Alloc
, _ValueType
> __value_alloc(__alloc
);
497 _BidirIter __begin
= __it
;
499 // If an exception is thrown, destroy what we have constructed so far in reverse order.
500 auto __guard
= std::__make_exception_guard([&]() { std::__allocator_destroy_multidimensional(__value_alloc
, __begin
, __it
); });
501 for (; __n
!= 0; --__n
, ++__it
) {
502 std::__allocator_construct_at_multidimensional(__value_alloc
, std::addressof(*__it
), __value
);
504 __guard
.__complete();
507 // Same as __uninitialized_allocator_fill_n_multidimensional, but doesn't pass any initialization argument
508 // to the allocator's construct method, which results in value initialization.
509 template <class _Alloc
, class _BidirIter
, class _Size
= typename iterator_traits
<_BidirIter
>::difference_type
>
510 _LIBCPP_HIDE_FROM_ABI
constexpr void
511 __uninitialized_allocator_value_construct_n_multidimensional(_Alloc
& __alloc
, _BidirIter __it
, _Size __n
) {
512 using _ValueType
= typename iterator_traits
<_BidirIter
>::value_type
;
513 __allocator_traits_rebind_t
<_Alloc
, _ValueType
> __value_alloc(__alloc
);
514 _BidirIter __begin
= __it
;
516 // If an exception is thrown, destroy what we have constructed so far in reverse order.
517 auto __guard
= std::__make_exception_guard([&]() { std::__allocator_destroy_multidimensional(__value_alloc
, __begin
, __it
); });
518 for (; __n
!= 0; --__n
, ++__it
) {
519 std::__allocator_construct_at_multidimensional(__value_alloc
, std::addressof(*__it
));
521 __guard
.__complete();
524 #endif // _LIBCPP_STD_VER >= 17
526 // Destroy all elements in [__first, __last) from left to right using allocator destruction.
527 template <class _Alloc
, class _Iter
, class _Sent
>
528 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
void
529 __allocator_destroy(_Alloc
& __alloc
, _Iter __first
, _Sent __last
) {
530 for (; __first
!= __last
; ++__first
)
531 allocator_traits
<_Alloc
>::destroy(__alloc
, std::__to_address(__first
));
534 template <class _Alloc
, class _Iter
>
535 class _AllocatorDestroyRangeReverse
{
537 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
538 _AllocatorDestroyRangeReverse(_Alloc
& __alloc
, _Iter
& __first
, _Iter
& __last
)
539 : __alloc_(__alloc
), __first_(__first
), __last_(__last
) {}
541 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
void operator()() const {
542 std::__allocator_destroy(__alloc_
, std::reverse_iterator
<_Iter
>(__last_
), std::reverse_iterator
<_Iter
>(__first_
));
551 // Copy-construct [__first1, __last1) in [__first2, __first2 + N), where N is distance(__first1, __last1).
553 // The caller has to ensure that __first2 can hold at least N uninitialized elements. If an exception is thrown the
554 // already copied elements are destroyed in reverse order of their construction.
555 template <class _Alloc
, class _Iter1
, class _Sent1
, class _Iter2
>
556 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Iter2
557 __uninitialized_allocator_copy_impl(_Alloc
& __alloc
, _Iter1 __first1
, _Sent1 __last1
, _Iter2 __first2
) {
558 auto __destruct_first
= __first2
;
560 std::__make_exception_guard(_AllocatorDestroyRangeReverse
<_Alloc
, _Iter2
>(__alloc
, __destruct_first
, __first2
));
561 while (__first1
!= __last1
) {
562 allocator_traits
<_Alloc
>::construct(__alloc
, std::__to_address(__first2
), *__first1
);
566 __guard
.__complete();
570 template <class _Alloc
, class _Type
>
571 struct __allocator_has_trivial_copy_construct
: _Not
<__has_construct
<_Alloc
, _Type
*, const _Type
&> > {};
573 template <class _Type
>
574 struct __allocator_has_trivial_copy_construct
<allocator
<_Type
>, _Type
> : true_type
{};
576 template <class _Alloc
,
578 class _RawTypeIn
= __remove_const_t
<_In
>,
581 // using _RawTypeIn because of the allocator<T const> extension
582 is_trivially_copy_constructible
<_RawTypeIn
>::value
&& is_trivially_copy_assignable
<_RawTypeIn
>::value
&&
583 is_same
<__remove_const_t
<_In
>, __remove_const_t
<_Out
> >::value
&&
584 __allocator_has_trivial_copy_construct
<_Alloc
, _RawTypeIn
>::value
>* = nullptr>
585 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Out
*
586 __uninitialized_allocator_copy_impl(_Alloc
&, _In
* __first1
, _In
* __last1
, _Out
* __first2
) {
587 // TODO: Remove the const_cast once we drop support for std::allocator<T const>
588 if (__libcpp_is_constant_evaluated()) {
589 while (__first1
!= __last1
) {
590 std::__construct_at(std::__to_address(__first2
), *__first1
);
596 return std::copy(__first1
, __last1
, const_cast<_RawTypeIn
*>(__first2
));
600 template <class _Alloc
, class _Iter1
, class _Sent1
, class _Iter2
>
601 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Iter2
__uninitialized_allocator_copy(_Alloc
& __alloc
, _Iter1 __first1
, _Sent1 __last1
, _Iter2 __first2
) {
602 auto __unwrapped_range
= std::__unwrap_range(__first1
, __last1
);
603 auto __result
= std::__uninitialized_allocator_copy_impl(__alloc
, __unwrapped_range
.first
, __unwrapped_range
.second
, std::__unwrap_iter(__first2
));
604 return std::__rewrap_iter(__first2
, __result
);
607 // Move-construct the elements [__first1, __last1) into [__first2, __first2 + N)
608 // if the move constructor is noexcept, where N is distance(__first1, __last1).
610 // Otherwise try to copy all elements. If an exception is thrown the already copied
611 // elements are destroyed in reverse order of their construction.
612 template <class _Alloc
, class _Iter1
, class _Sent1
, class _Iter2
>
613 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Iter2
__uninitialized_allocator_move_if_noexcept(
614 _Alloc
& __alloc
, _Iter1 __first1
, _Sent1 __last1
, _Iter2 __first2
) {
615 static_assert(__is_cpp17_move_insertable
<_Alloc
>::value
,
616 "The specified type does not meet the requirements of Cpp17MoveInsertable");
617 auto __destruct_first
= __first2
;
619 std::__make_exception_guard(_AllocatorDestroyRangeReverse
<_Alloc
, _Iter2
>(__alloc
, __destruct_first
, __first2
));
620 while (__first1
!= __last1
) {
621 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
622 allocator_traits
<_Alloc
>::construct(__alloc
, std::__to_address(__first2
), std::move_if_noexcept(*__first1
));
624 allocator_traits
<_Alloc
>::construct(__alloc
, std::__to_address(__first2
), std::move(*__first1
));
629 __guard
.__complete();
633 template <class _Alloc
, class _Type
>
634 struct __allocator_has_trivial_move_construct
: _Not
<__has_construct
<_Alloc
, _Type
*, _Type
&&> > {};
636 template <class _Type
>
637 struct __allocator_has_trivial_move_construct
<allocator
<_Type
>, _Type
> : true_type
{};
639 #ifndef _LIBCPP_COMPILER_GCC
644 class _Type
= typename iterator_traits
<_Iter1
>::value_type
,
645 class = __enable_if_t
<is_trivially_move_constructible
<_Type
>::value
&& is_trivially_move_assignable
<_Type
>::value
&&
646 __allocator_has_trivial_move_construct
<_Alloc
, _Type
>::value
> >
647 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Iter2
648 __uninitialized_allocator_move_if_noexcept(_Alloc
&, _Iter1 __first1
, _Iter1 __last1
, _Iter2 __first2
) {
649 if (__libcpp_is_constant_evaluated()) {
650 while (__first1
!= __last1
) {
651 std::__construct_at(std::__to_address(__first2
), std::move(*__first1
));
657 return std::move(__first1
, __last1
, __first2
);
660 #endif // _LIBCPP_COMPILER_GCC
662 _LIBCPP_END_NAMESPACE_STD
664 #endif // _LIBCPP___MEMORY_UNINITIALIZED_ALGORITHMS_H