Index: libcxx/include/__memory/uninitialized_algorithms.h =================================================================== --- libcxx/include/__memory/uninitialized_algorithms.h +++ libcxx/include/__memory/uninitialized_algorithms.h @@ -12,6 +12,7 @@ #include <__algorithm/copy.h> #include <__algorithm/move.h> +#include <__algorithm/unwrap_iter.h> #include <__config> #include <__iterator/iterator_traits.h> #include <__iterator/reverse_iterator.h> @@ -539,13 +540,15 @@ _Iter& __last_; }; -// 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 -// already copied elements are destroyed in reverse order of their construction. +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 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Iter2 -__uninitialized_allocator_copy(_Alloc& __alloc, _Iter1 __first1, _Sent1 __last1, _Iter2 __first2) { +__uninitialized_allocator_copy_impl(_Alloc& __alloc, _Iter1 __first1, _Sent1 __last1, _Iter2 __first2) { auto __destruct_first = __first2; auto __guard = std::__make_exception_guard(_AllocatorDestroyRangeReverse<_Alloc, _Iter2>(__alloc, __destruct_first, __first2)); @@ -558,21 +561,19 @@ 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 , + class _Type1, + class _TypeLast1, + class _Type2, + class _RawType = __remove_const_t<_Type2>, __enable_if_t< // using _RawType because of the allocator extension + is_same<__remove_cv_t<_Type1>, __remove_cv_t<_Type2>>::value && + is_same<__remove_cv_t<_Type1>, __remove_cv_t<_TypeLast1>>::value && 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(_Alloc&, const _Type* __first1, const _Type* __last1, _Type* __first2) { +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Type2* +__uninitialized_allocator_copy_impl(_Alloc&, const _Type1* __first1, const _TypeLast1* __last1, _Type2* __first2) { // TODO: Remove the const_cast once we drop support for std::allocator if (__libcpp_is_constant_evaluated()) { while (__first1 != __last1) { @@ -586,6 +587,16 @@ } } +// 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 +// already copied elements are destroyed in reverse order of their construction. +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Iter2 +__uninitialized_allocator_copy(_Alloc& __alloc, _Iter1 __first1, _Sent1 __last1, _Iter2 __first2) { + return std::__uninitialized_allocator_copy_impl(__alloc, std::__unwrap_iter(__first1), std::__unwrap_iter(__last1), std::__unwrap_iter(__first2)); +} + // Move-construct the elements [__first1, __last1) into [__first2, __first2 + N) // if the move constructor is noexcept, where N is distance(__first1, __last1). //