|
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