|
29 | 29 | #include <__type_traits/is_trivially_copy_constructible.h> |
30 | 30 | #include <__type_traits/is_trivially_move_assignable.h> |
31 | 31 | #include <__type_traits/is_trivially_move_constructible.h> |
| 32 | +#include <__type_traits/is_trivially_relocatable.h> |
32 | 33 | #include <__type_traits/is_unbounded_array.h> |
33 | 34 | #include <__type_traits/negation.h> |
34 | 35 | #include <__type_traits/remove_const.h> |
@@ -591,60 +592,48 @@ __uninitialized_allocator_copy(_Alloc& __alloc, _Iter1 __first1, _Sent1 __last1, |
591 | 592 | return std::__rewrap_iter(__first2, __result); |
592 | 593 | } |
593 | 594 |
|
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 | 595 | template <class _Alloc, class _Type> |
621 | 596 | struct __allocator_has_trivial_move_construct : _Not<__has_construct<_Alloc, _Type*, _Type&&> > {}; |
622 | 597 |
|
623 | 598 | template <class _Type> |
624 | 599 | struct __allocator_has_trivial_move_construct<allocator<_Type>, _Type> : true_type {}; |
625 | 600 |
|
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; |
| 601 | +template <class _Alloc, class _Tp> |
| 602 | +struct __allocator_has_trivial_destroy : _Not<__has_destroy<_Alloc, _Tp*>> {}; |
| 603 | + |
| 604 | +template <class _Tp, class _Up> |
| 605 | +struct __allocator_has_trivial_destroy<allocator<_Tp>, _Up> : true_type {}; |
| 606 | + |
| 607 | +// __uninitialized_allocator_relocate relocates the objects in [__first, __last) into __result. |
| 608 | +// relocation means that the objects in [__first, __last) are placed into __result as-if by move-construct and destroy, |
| 609 | +// except that the move constructor and destructor may never be called if they are known to be equivalent to a memcpy. |
| 610 | +// |
| 611 | +// Preconditions: __result doesn't contain any objects and [__first, __last) contains objects |
| 612 | +// Postconditions: __result contains the object from [__first, __last) and [__first, __last) doesn't contain any objects |
| 613 | +template <class _Alloc, class _Tp> |
| 614 | +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void |
| 615 | +__uninitialized_allocator_relocate(_Alloc& __alloc, _Tp* __first, _Tp* __last, _Tp* __result) { |
| 616 | + if (__libcpp_is_constant_evaluated() || !__libcpp_is_trivially_relocatable<_Tp>::value || |
| 617 | + !__allocator_has_trivial_move_construct<_Alloc, _Tp>::value || |
| 618 | + !__allocator_has_trivial_destroy<_Alloc, _Tp>::value) { |
| 619 | + auto __destruct_first = __result; |
| 620 | + auto __guard = |
| 621 | + std::__make_exception_guard(_AllocatorDestroyRangeReverse<_Alloc, _Tp*>(__alloc, __destruct_first, __result)); |
| 622 | + while (__first != __last) { |
| 623 | +#ifndef _LIBCPP_HAS_NO_EXCEPTIONS |
| 624 | + allocator_traits<_Alloc>::construct(__alloc, std::__to_address(__result), std::move_if_noexcept(*__first)); |
| 625 | +#else |
| 626 | + allocator_traits<_Alloc>::construct(__alloc, std::__to_address(__result), std::move(*__first)); |
| 627 | +#endif |
| 628 | + ++__first; |
| 629 | + ++__result; |
641 | 630 | } |
642 | | - return __first2; |
| 631 | + __guard.__complete(); |
| 632 | + std::__allocator_destroy(__alloc, __first, __last); |
643 | 633 | } else { |
644 | | - return std::move(__first1, __last1, __first2); |
| 634 | + __builtin_memcpy(__result, __first, sizeof(_Tp) * (__last - __first)); |
645 | 635 | } |
646 | 636 | } |
647 | | -#endif // _LIBCPP_COMPILER_GCC |
648 | 637 |
|
649 | 638 | _LIBCPP_END_NAMESPACE_STD |
650 | 639 |
|
|
0 commit comments