Index: libcxx/include/__memory/uninitialized_algorithms.h =================================================================== --- libcxx/include/__memory/uninitialized_algorithms.h +++ libcxx/include/__memory/uninitialized_algorithms.h @@ -539,6 +539,56 @@ _Iter& __last_; }; +template +struct __allocator_has_trivial_copy_construct : _Not<__has_construct<_Alloc, _Type*, const _Type&> > {}; + +template +struct __allocator_has_trivial_copy_construct, _Type> : true_type {}; + +template , + __enable_if_t< + // using _RawType because of the allocator extension + is_trivially_copy_constructible<_RawType>::value && is_trivially_copy_assignable<_RawType>::value && + __allocator_has_trivial_copy_construct<_Alloc, _RawType>::value>* = nullptr> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Type* +__uninitialized_allocator_copy_opt(_Alloc&, const _Type* __first1, const _Type* __last1, _Type* __first2) { + // TODO: Remove the const_cast once we drop support for std::allocator + if (__libcpp_is_constant_evaluated()) { + while (__first1 != __last1) { + std::__construct_at(std::__to_address(__first2), *__first1); + ++__first1; + ++__first2; + } + return __first2; + } else { + return std::copy(__first1, __last1, const_cast<_RawType*>(__first2)); + } +} + +template , + __enable_if_t< + // using _RawType because of the allocator extension + is_trivially_copy_constructible<_RawType>::value && is_trivially_copy_assignable<_RawType>::value && + __allocator_has_trivial_copy_construct<_Alloc, _RawType>::value>* = nullptr> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Type* +__uninitialized_allocator_copy_opt(_Alloc&, _Type* __first1, _Type* __last1, _Type* __first2) { + // TODO: Remove the const_cast once we drop support for std::allocator + if (__libcpp_is_constant_evaluated()) { + while (__first1 != __last1) { + std::__construct_at(std::__to_address(__first2), *__first1); + ++__first1; + ++__first2; + } + return __first2; + } else { + return std::copy(__first1, __last1, const_cast<_RawType*>(__first2)); + } +} + // Copy-construct [__first1, __last1) in [__first2, __first2 + N), where N is distance(__first1, __last1). // // The caller has to ensure that __first2 can hold at least N uninitialized elements. If an exception is thrown the @@ -546,6 +596,19 @@ template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Iter2 __uninitialized_allocator_copy(_Alloc& __alloc, _Iter1 __first1, _Sent1 __last1, _Iter2 __first2) { + +#if _LIBCPP_STD_VER >= 17 + using _RawType = __remove_const_t<_Iter1>; + using _ValueType = typename allocator_traits<_Alloc>::value_type; + if constexpr(is_trivially_copy_constructible_v<_ValueType> && is_trivially_copy_assignable_v<_ValueType> && + __allocator_has_trivial_copy_construct<_Alloc, _RawType>::value && + is_same_v<_Iter1, _Sent1> && + is_same_v<_Iter1, _Iter2> && + is_same_v::pointer, _Iter1> && + is_same_v::value_type>, _Alloc>) + return std::__uninitialized_allocator_copy_opt(__alloc, __first1, __last1, __first2); + +#endif auto __destruct_first = __first2; auto __guard = std::__make_exception_guard(_AllocatorDestroyRangeReverse<_Alloc, _Iter2>(__alloc, __destruct_first, __first2)); @@ -558,12 +621,6 @@ return __first2; } -template -struct __allocator_has_trivial_copy_construct : _Not<__has_construct<_Alloc, _Type*, const _Type&> > {}; - -template -struct __allocator_has_trivial_copy_construct, _Type> : true_type {}; - template , Index: libcxx/include/vector =================================================================== --- libcxx/include/vector +++ libcxx/include/vector @@ -310,7 +310,10 @@ #include <__type_traits/is_allocator.h> #include <__type_traits/is_constructible.h> #include <__type_traits/is_nothrow_move_assignable.h> +#include <__type_traits/is_trivially_copy_assignable.h> +#include <__type_traits/is_trivially_copy_constructible.h> #include <__type_traits/noexcept_move_assign_container.h> +#include <__type_traits/remove_const.h> #include <__type_traits/type_identity.h> #include <__utility/exception_guard.h> #include <__utility/forward.h>