|
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> |
@@ -594,60 +595,57 @@ __uninitialized_allocator_copy(_Alloc& __alloc, _Iter1 __first1, _Sent1 __last1, |
594 | 595 | return std::__rewrap_iter(__first2, __result); |
595 | 596 | } |
596 | 597 |
|
597 | | -// Move-construct the elements [__first1, __last1) into [__first2, __first2 + N) |
598 | | -// if the move constructor is noexcept, where N is distance(__first1, __last1). |
599 | | -// |
600 | | -// Otherwise try to copy all elements. If an exception is thrown the already copied |
601 | | -// elements are destroyed in reverse order of their construction. |
602 | | -template <class _Alloc, class _Iter1, class _Sent1, class _Iter2> |
603 | | -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Iter2 |
604 | | -__uninitialized_allocator_move_if_noexcept(_Alloc& __alloc, _Iter1 __first1, _Sent1 __last1, _Iter2 __first2) { |
605 | | - static_assert(__is_cpp17_move_insertable<_Alloc>::value, |
606 | | - "The specified type does not meet the requirements of Cpp17MoveInsertable"); |
607 | | - auto __destruct_first = __first2; |
608 | | - auto __guard = |
609 | | - std::__make_exception_guard(_AllocatorDestroyRangeReverse<_Alloc, _Iter2>(__alloc, __destruct_first, __first2)); |
610 | | - while (__first1 != __last1) { |
611 | | -#ifndef _LIBCPP_HAS_NO_EXCEPTIONS |
612 | | - allocator_traits<_Alloc>::construct(__alloc, std::__to_address(__first2), std::move_if_noexcept(*__first1)); |
613 | | -#else |
614 | | - allocator_traits<_Alloc>::construct(__alloc, std::__to_address(__first2), std::move(*__first1)); |
615 | | -#endif |
616 | | - ++__first1; |
617 | | - ++__first2; |
618 | | - } |
619 | | - __guard.__complete(); |
620 | | - return __first2; |
621 | | -} |
622 | | - |
623 | 598 | template <class _Alloc, class _Type> |
624 | 599 | struct __allocator_has_trivial_move_construct : _Not<__has_construct<_Alloc, _Type*, _Type&&> > {}; |
625 | 600 |
|
626 | 601 | template <class _Type> |
627 | 602 | struct __allocator_has_trivial_move_construct<allocator<_Type>, _Type> : true_type {}; |
628 | 603 |
|
629 | | -#ifndef _LIBCPP_COMPILER_GCC |
630 | | -template < |
631 | | - class _Alloc, |
632 | | - class _Iter1, |
633 | | - class _Iter2, |
634 | | - class _Type = typename iterator_traits<_Iter1>::value_type, |
635 | | - class = __enable_if_t<is_trivially_move_constructible<_Type>::value && is_trivially_move_assignable<_Type>::value && |
636 | | - __allocator_has_trivial_move_construct<_Alloc, _Type>::value> > |
637 | | -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Iter2 |
638 | | -__uninitialized_allocator_move_if_noexcept(_Alloc&, _Iter1 __first1, _Iter1 __last1, _Iter2 __first2) { |
639 | | - if (__libcpp_is_constant_evaluated()) { |
640 | | - while (__first1 != __last1) { |
641 | | - std::__construct_at(std::__to_address(__first2), std::move(*__first1)); |
642 | | - ++__first1; |
643 | | - ++__first2; |
| 604 | +template <class _Alloc, class _Tp> |
| 605 | +struct __allocator_has_trivial_destroy : _Not<__has_destroy<_Alloc, _Tp*> > {}; |
| 606 | + |
| 607 | +template <class _Tp, class _Up> |
| 608 | +struct __allocator_has_trivial_destroy<allocator<_Tp>, _Up> : true_type {}; |
| 609 | + |
| 610 | +// __uninitialized_allocator_relocate relocates the objects in [__first, __last) into __result. |
| 611 | +// Relocation means that the objects in [__first, __last) are placed into __result as-if by move-construct and destroy, |
| 612 | +// except that the move constructor and destructor may never be called if they are known to be equivalent to a memcpy. |
| 613 | +// |
| 614 | +// Preconditions: __result doesn't contain any objects and [__first, __last) contains objects |
| 615 | +// Postconditions: __result contains the objects from [__first, __last) and |
| 616 | +// [__first, __last) doesn't contain any objects |
| 617 | +// |
| 618 | +// The strong exception guarantee is provided if any of the following are true: |
| 619 | +// - is_nothrow_move_constructible<_Tp> |
| 620 | +// - is_copy_constructible<_Tp> |
| 621 | +// - __libcpp_is_trivially_relocatable<_Tp> |
| 622 | +template <class _Alloc, class _Tp> |
| 623 | +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void |
| 624 | +__uninitialized_allocator_relocate(_Alloc& __alloc, _Tp* __first, _Tp* __last, _Tp* __result) { |
| 625 | + static_assert(__is_cpp17_move_insertable<_Alloc>::value, |
| 626 | + "The specified type does not meet the requirements of Cpp17MoveInsertable"); |
| 627 | + if (__libcpp_is_constant_evaluated() || !__libcpp_is_trivially_relocatable<_Tp>::value || |
| 628 | + !__allocator_has_trivial_move_construct<_Alloc, _Tp>::value || |
| 629 | + !__allocator_has_trivial_destroy<_Alloc, _Tp>::value) { |
| 630 | + auto __destruct_first = __result; |
| 631 | + auto __guard = |
| 632 | + std::__make_exception_guard(_AllocatorDestroyRangeReverse<_Alloc, _Tp*>(__alloc, __destruct_first, __result)); |
| 633 | + auto __iter = __first; |
| 634 | + while (__iter != __last) { |
| 635 | +#ifndef _LIBCPP_HAS_NO_EXCEPTIONS |
| 636 | + allocator_traits<_Alloc>::construct(__alloc, __result, std::move_if_noexcept(*__iter)); |
| 637 | +#else |
| 638 | + allocator_traits<_Alloc>::construct(__alloc, __result, std::move(*__iter)); |
| 639 | +#endif |
| 640 | + ++__iter; |
| 641 | + ++__result; |
644 | 642 | } |
645 | | - return __first2; |
| 643 | + __guard.__complete(); |
| 644 | + std::__allocator_destroy(__alloc, __first, __last); |
646 | 645 | } else { |
647 | | - return std::move(__first1, __last1, __first2); |
| 646 | + __builtin_memcpy(__result, __first, sizeof(_Tp) * (__last - __first)); |
648 | 647 | } |
649 | 648 | } |
650 | | -#endif // _LIBCPP_COMPILER_GCC |
651 | 649 |
|
652 | 650 | _LIBCPP_END_NAMESPACE_STD |
653 | 651 |
|
|
0 commit comments