|
20 | 20 | #include <__memory/addressof.h> |
21 | 21 | #include <__memory/allocator_traits.h> |
22 | 22 | #include <__memory/construct_at.h> |
| 23 | +#include <__memory/is_trivially_allocator_relocatable.h> |
23 | 24 | #include <__memory/pointer_traits.h> |
24 | 25 | #include <__type_traits/enable_if.h> |
25 | 26 | #include <__type_traits/extent.h> |
@@ -591,60 +592,38 @@ __uninitialized_allocator_copy(_Alloc& __alloc, _Iter1 __first1, _Sent1 __last1, |
591 | 592 | return std::__rewrap_iter(__first2, __result); |
592 | 593 | } |
593 | 594 |
|
594 | | -template <class _Alloc, class _Type> |
595 | | -struct __allocator_has_trivial_move_construct : _Not<__has_construct<_Alloc, _Type*, _Type&&> > {}; |
596 | | - |
597 | | -template <class _Type> |
598 | | -struct __allocator_has_trivial_move_construct<allocator<_Type>, _Type> : true_type {}; |
599 | | - |
600 | | -template <class _Alloc, class _Tp> |
601 | | -struct __allocator_has_trivial_destroy : _Not<__has_destroy<_Alloc, _Tp*> > {}; |
602 | | - |
603 | | -template <class _Tp, class _Up> |
604 | | -struct __allocator_has_trivial_destroy<allocator<_Tp>, _Up> : true_type {}; |
605 | | - |
606 | 595 | // __uninitialized_allocator_relocate relocates the objects in [__first, __last) into __result. |
| 596 | +// |
607 | 597 | // Relocation means that the objects in [__first, __last) are placed into __result as-if by move-construct and destroy, |
608 | 598 | // except that the move constructor and destructor may never be called if they are known to be equivalent to a memcpy. |
609 | 599 | // |
610 | | -// Preconditions: __result doesn't contain any objects and [__first, __last) contains objects |
| 600 | +// This algorithm works even if part of the resulting range overlaps with [__first, __last), as long as __result itself |
| 601 | +// is not in [__first, last). |
| 602 | +// |
| 603 | +// Preconditions: |
| 604 | +// - __result doesn't contain any objects and [__first, __last) contains objects |
| 605 | +// - __result is not in [__first, __last) sd |
611 | 606 | // Postconditions: __result contains the objects from [__first, __last) and |
612 | 607 | // [__first, __last) doesn't contain any objects |
613 | | -// |
614 | | -// The strong exception guarantee is provided if any of the following are true: |
615 | | -// - is_nothrow_move_constructible<_ValueType> |
616 | | -// - is_copy_constructible<_ValueType> |
617 | | -// - __libcpp_is_trivially_relocatable<_ValueType> |
618 | 608 | template <class _Alloc, class _ContiguousIterator> |
619 | 609 | _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void __uninitialized_allocator_relocate( |
620 | 610 | _Alloc& __alloc, _ContiguousIterator __first, _ContiguousIterator __last, _ContiguousIterator __result) { |
621 | 611 | static_assert(__libcpp_is_contiguous_iterator<_ContiguousIterator>::value, ""); |
622 | 612 | using _ValueType = typename iterator_traits<_ContiguousIterator>::value_type; |
623 | 613 | static_assert(__is_cpp17_move_insertable<_Alloc>::value, |
624 | 614 | "The specified type does not meet the requirements of Cpp17MoveInsertable"); |
625 | | - if (__libcpp_is_constant_evaluated() || !__libcpp_is_trivially_relocatable<_ValueType>::value || |
626 | | - !__allocator_has_trivial_move_construct<_Alloc, _ValueType>::value || |
627 | | - !__allocator_has_trivial_destroy<_Alloc, _ValueType>::value) { |
628 | | - auto __destruct_first = __result; |
629 | | - auto __guard = std::__make_exception_guard( |
630 | | - _AllocatorDestroyRangeReverse<_Alloc, _ContiguousIterator>(__alloc, __destruct_first, __result)); |
631 | | - auto __iter = __first; |
632 | | - while (__iter != __last) { |
633 | | -#if _LIBCPP_HAS_EXCEPTIONS |
634 | | - allocator_traits<_Alloc>::construct(__alloc, std::__to_address(__result), std::move_if_noexcept(*__iter)); |
635 | | -#else |
636 | | - allocator_traits<_Alloc>::construct(__alloc, std::__to_address(__result), std::move(*__iter)); |
637 | | -#endif |
638 | | - ++__iter; |
| 615 | + if (__libcpp_is_constant_evaluated() || !__is_trivially_allocator_relocatable<_Alloc, _ValueType>::value) { |
| 616 | + while (__first != __last) { |
| 617 | + allocator_traits<_Alloc>::construct(__alloc, std::__to_address(__result), std::move(*__first)); |
| 618 | + allocator_traits<_Alloc>::destroy(__alloc, std::__to_address(__first)); |
| 619 | + ++__first; |
639 | 620 | ++__result; |
640 | 621 | } |
641 | | - __guard.__complete(); |
642 | | - std::__allocator_destroy(__alloc, __first, __last); |
643 | 622 | } else { |
644 | 623 | // Casting to void* to suppress clang complaining that this is technically UB. |
645 | | - __builtin_memcpy(static_cast<void*>(std::__to_address(__result)), |
646 | | - std::__to_address(__first), |
647 | | - sizeof(_ValueType) * (__last - __first)); |
| 624 | + __builtin_memmove(static_cast<void*>(std::__to_address(__result)), |
| 625 | + std::__to_address(__first), |
| 626 | + sizeof(_ValueType) * (__last - __first)); |
648 | 627 | } |
649 | 628 | } |
650 | 629 |
|
|
0 commit comments