Index: libcxx/benchmarks/ContainerBenchmarks.h =================================================================== --- libcxx/benchmarks/ContainerBenchmarks.h +++ libcxx/benchmarks/ContainerBenchmarks.h @@ -26,6 +26,28 @@ } } +template +void BM_CopyConstruct(benchmark::State& st, Container) { + auto size = st.range(0); + Container c(size); + for (auto _ : st) { + auto v = c; + DoNotOptimizeData(v); + } +} + +template +void BM_Assignment(benchmark::State& st, Container) { + auto size = st.range(0); + Container c1(size); + Container c2; + for (auto _ : st) { + c1 = c2; + DoNotOptimizeData(c1); + DoNotOptimizeData(c2); + } +} + template void BM_ConstructSizeValue(benchmark::State& st, Container, typename Container::value_type const& val) { const auto size = st.range(0); Index: libcxx/benchmarks/vector_operations.bench.cpp =================================================================== --- libcxx/benchmarks/vector_operations.bench.cpp +++ libcxx/benchmarks/vector_operations.bench.cpp @@ -17,6 +17,14 @@ vector_byte, std::vector{})->Arg(5140480); +BENCHMARK_CAPTURE(BM_CopyConstruct, + vector_int, + std::vector{})->Arg(5140480); + +BENCHMARK_CAPTURE(BM_Assignment, + vector_int, + std::vector{})->Arg(5140480); + BENCHMARK_CAPTURE(BM_ConstructSizeValue, vector_byte, std::vector{}, 0)->Arg(5140480); Index: libcxx/include/__memory/uninitialized_algorithms.h =================================================================== --- libcxx/include/__memory/uninitialized_algorithms.h +++ libcxx/include/__memory/uninitialized_algorithms.h @@ -12,6 +12,8 @@ #include <__algorithm/copy.h> #include <__algorithm/move.h> +#include <__algorithm/unwrap_iter.h> +#include <__algorithm/unwrap_range.h> #include <__config> #include <__iterator/iterator_traits.h> #include <__iterator/reverse_iterator.h> @@ -545,7 +547,7 @@ // 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) { +__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)); @@ -565,14 +567,16 @@ struct __allocator_has_trivial_copy_construct, _Type> : true_type {}; template , + class _In, + class _RawTypeIn = __remove_const_t<_In>, + class _Out, __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(_Alloc&, const _Type* __first1, const _Type* __last1, _Type* __first2) { + // using _RawTypeIn because of the allocator extension + is_trivially_copy_constructible<_RawTypeIn>::value && is_trivially_copy_assignable<_RawTypeIn>::value && + is_same<__remove_cv_t<_In>, __remove_cv_t<_Out> >::value && + __allocator_has_trivial_copy_construct<_Alloc, _RawTypeIn>::value>* = nullptr> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Out* +__uninitialized_allocator_copy_impl(_Alloc&, _In* __first1, _In* __last1, _Out* __first2) { // TODO: Remove the const_cast once we drop support for std::allocator if (__libcpp_is_constant_evaluated()) { while (__first1 != __last1) { @@ -582,10 +586,17 @@ } return __first2; } else { - return std::copy(__first1, __last1, const_cast<_RawType*>(__first2)); + return std::copy(__first1, __last1, const_cast<_RawTypeIn*>(__first2)); } } +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Iter2 __uninitialized_allocator_copy(_Alloc& __alloc, _Iter1 __first1, _Sent1 __last1, _Iter2 __first2) { + auto __unwrapped_range = std::__unwrap_range(__first1, __last1); + auto __result = std::__uninitialized_allocator_copy_impl(__alloc, __unwrapped_range.first, __unwrapped_range.second, std::__unwrap_iter(__first2)); + return std::__rewrap_iter(__first2, __result); +} + // Move-construct the elements [__first1, __last1) into [__first2, __first2 + N) // if the move constructor is noexcept, where N is distance(__first1, __last1). //