diff --git a/libcxx/include/__iterator/iterator_traits.h b/libcxx/include/__iterator/iterator_traits.h --- a/libcxx/include/__iterator/iterator_traits.h +++ b/libcxx/include/__iterator/iterator_traits.h @@ -474,10 +474,10 @@ __has_iterator_category_convertible_to<_Tp, input_iterator_tag>::value && !__has_iterator_category_convertible_to<_Tp, forward_iterator_tag>::value> {}; -#if _LIBCPP_STD_VER >= 17 template using __iter_value_type = typename iterator_traits<_InputIterator>::value_type; +#if _LIBCPP_STD_VER >= 17 template using __iter_key_type = remove_const_t::value_type::first_type>; diff --git a/libcxx/include/__memory/construct_at.h b/libcxx/include/__memory/construct_at.h --- a/libcxx/include/__memory/construct_at.h +++ b/libcxx/include/__memory/construct_at.h @@ -13,6 +13,7 @@ #include <__config> #include <__debug> #include <__iterator/access.h> +#include <__iterator/iterator_traits.h> #include <__memory/addressof.h> #include <__memory/voidify.h> #include <__utility/forward.h> @@ -25,6 +26,19 @@ _LIBCPP_BEGIN_NAMESPACE_STD +namespace __construct_at { + +template +_ForwardIterator __next_n(_ForwardIterator __iter, _Size __n) { + while (__n > 0) { + ++__iter; + --__n; + } + return __iter; +} + +} // namespace __construct_at + // construct_at #if _LIBCPP_STD_VER > 17 @@ -68,6 +82,10 @@ template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 _ForwardIterator __destroy(_ForwardIterator __first, _ForwardIterator __last) { + if constexpr (is_trivially_destructible_v<__iter_value_type<_ForwardIterator>>) { + return __last; + } + for (; __first != __last; ++__first) _VSTD::__destroy_at(_VSTD::addressof(*__first)); return __first; @@ -78,6 +96,10 @@ template , int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 void destroy_at(_Tp* __loc) { + if constexpr (is_trivially_destructible_v<_Tp>) { + return; + } + _VSTD::__destroy_at(__loc); } @@ -98,6 +120,10 @@ template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 _ForwardIterator destroy_n(_ForwardIterator __first, _Size __n) { + if constexpr (is_trivially_destructible_v<__iter_value_type<_ForwardIterator>>) { + return __construct_at::__next_n(__first, __n); + } + for (; __n > 0; (void)++__first, --__n) _VSTD::__destroy_at(_VSTD::addressof(*__first)); return __first; diff --git a/libcxx/include/__memory/uninitialized_algorithms.h b/libcxx/include/__memory/uninitialized_algorithms.h --- a/libcxx/include/__memory/uninitialized_algorithms.h +++ b/libcxx/include/__memory/uninitialized_algorithms.h @@ -32,12 +32,116 @@ } }; +namespace __uninitialized_algorithms { + +template +_ForwardIterator __next(_ForwardIterator __iter, _Sentinel __sentinel) { + while (__iter != __sentinel) { + ++__iter; + } + return __iter; +} + +template +_ForwardIterator __next_n(_ForwardIterator __iter, _Size __n) { + while (__n > 0) { + ++__iter; + --__n; + } + return __iter; +} + +// TODO(varconst): support contiguous iterators. +template +struct __can_use_memset_fill { + static const bool __value = is_pointer<_OutputIterator>::value + && is_scalar<_From>::value + && is_scalar<_To>::value + && sizeof(_From) == 1 + && sizeof(_To) == 1 + && !is_volatile<_From>::value + && !is_volatile<_To>::value; +}; + +// TODO(varconst): support contiguous iterators. +template +struct __can_use_memset_zero { + static const bool __value = is_pointer<_OutputIterator>::value + && is_trivial<_ValueType>::value + && !is_volatile<_ValueType>::value; +}; + +template +struct __are_bitwise_compatible { + static const bool __value = sizeof(_From) == sizeof(_To) + && ((is_integral<_From>::value && is_integral<_To>::value) + || (is_floating_point<_From>::value && is_floating_point<_To>::value)); +}; + +template +struct __can_memcpy_between { + static const bool __value = (is_same<_From, _To>::value && is_trivial<_From>::value) + || __are_bitwise_compatible<_From, _To>::__value; +}; + +// TODO(varconst): support contiguous iterators. +template +struct __can_use_memcpy { + static const bool __value = is_pointer<_InputIterator>::value + && is_pointer<_OutputIterator>::value + && __can_memcpy_between<_From, _To>::__value + && !is_volatile<_From>::value + && !is_volatile<_To>::value; +}; + +#if _LIBCPP_STD_VER > 11 + +template +constexpr bool __can_use_memset_zero_v = __can_use_memset_zero<_ValueType, _OutputIterator>::__value; + +template +constexpr bool __can_use_memcpy_v = __can_use_memcpy<_From, _To, _InputIterator, _OutputIterator>::__value; + +#endif + +// TODO(varconst): use `std::to_address` to support contiguous iterators. +template +_Pointer __memset_fill(_Pointer __first, _Size __n, _ValueType __x) { + _VSTD::memset(__first, static_cast(__x), sizeof(_ValueType) * __n); + return __first + __n; +} + +// TODO(varconst): use `std::to_address` to support contiguous iterators. +template +_Pointer __memset_zero(_Pointer __first, _Size __n) { + _VSTD::memset(__first, 0, sizeof(_ValueType) * __n); + return __first + __n; +} + +// TODO(varconst): use `std::to_address` to support contiguous iterators. +template +pair<_InputPtr, _OutputPtr> __memcpy(_InputPtr __ifirst, _Size __isize, _OutputPtr __ofirst, _Size __osize) { + _Size __smaller_size = __isize < __osize ? __isize : __osize; + _VSTD::memcpy(__ofirst, __ifirst, __smaller_size * sizeof(_ValueType)); + + return _VSTD::make_pair(__ifirst + __smaller_size, __ofirst + __smaller_size); +} + +} // namespace __uninitialized_algorithms + // uninitialized_copy template inline _LIBCPP_HIDE_FROM_ABI pair<_InputIterator, _ForwardIterator> __uninitialized_copy(_InputIterator __ifirst, _Sentinel1 __ilast, _ForwardIterator __ofirst, _Sentinel2 __olast) { +#ifndef _LIBCPP_CXX03_LANG + if constexpr (__uninitialized_algorithms::__can_use_memcpy<__iter_value_type<_InputIterator>, _ValueType, + _InputIterator, _ForwardIterator>::__value) { + return __uninitialized_algorithms::__memcpy<_ValueType>(__ifirst, __ilast - __ifirst, __ofirst, __olast - __ofirst); + } +#endif + _ForwardIterator __idx = __ofirst; #ifndef _LIBCPP_NO_EXCEPTIONS try { @@ -51,7 +155,7 @@ } #endif - return pair<_InputIterator, _ForwardIterator>(_VSTD::move(__ifirst), _VSTD::move(__idx)); + return _VSTD::make_pair(_VSTD::move(__ifirst), _VSTD::move(__idx)); } template @@ -69,6 +173,13 @@ inline _LIBCPP_HIDE_FROM_ABI pair<_InputIterator, _ForwardIterator> __uninitialized_copy_n(_InputIterator __ifirst, _Size __n, _ForwardIterator __ofirst, _Sentinel __olast) { +#ifndef _LIBCPP_CXX03_LANG + if constexpr (__uninitialized_algorithms::__can_use_memcpy<__iter_value_type<_InputIterator>, _ValueType, + _InputIterator, _ForwardIterator>::__value) { + return __uninitialized_algorithms::__memcpy<_ValueType>(__ifirst, __n, __ofirst, __olast - __ofirst); + } +#endif + _ForwardIterator __idx = __ofirst; #ifndef _LIBCPP_NO_EXCEPTIONS try { @@ -82,7 +193,7 @@ } #endif - return pair<_InputIterator, _ForwardIterator>(_VSTD::move(__ifirst), _VSTD::move(__idx)); + return _VSTD::make_pair(_VSTD::move(__ifirst), _VSTD::move(__idx)); } template @@ -100,6 +211,12 @@ inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator __uninitialized_fill(_ForwardIterator __first, _Sentinel __last, const _Tp& __x) { +#ifndef _LIBCPP_CXX03_LANG + if constexpr (__uninitialized_algorithms::__can_use_memset_fill<_ValueType, _Tp, _ForwardIterator>::__value) { + return __uninitialized_algorithms::__memset_fill(__first, __last - __first, __x); + } +#endif + _ForwardIterator __idx = __first; #ifndef _LIBCPP_NO_EXCEPTIONS try @@ -133,6 +250,12 @@ inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator __uninitialized_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x) { +#ifndef _LIBCPP_CXX03_LANG + if constexpr (__uninitialized_algorithms::__can_use_memset_fill<_ValueType, _Tp, _ForwardIterator>::__value) { + return __uninitialized_algorithms::__memset_fill(__first, __n, __x); + } +#endif + _ForwardIterator __idx = __first; #ifndef _LIBCPP_NO_EXCEPTIONS try @@ -167,6 +290,10 @@ template inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator __uninitialized_default_construct(_ForwardIterator __first, _Sentinel __last) { + if constexpr (is_trivially_default_constructible_v<_ValueType>) { + return __uninitialized_algorithms::__next(__first, __last); + } + auto __idx = __first; #ifndef _LIBCPP_NO_EXCEPTIONS try { @@ -196,6 +323,10 @@ template inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator __uninitialized_default_construct_n(_ForwardIterator __first, _Size __n) { + if constexpr (is_trivially_default_constructible_v<_ValueType>) { + return __uninitialized_algorithms::__next_n(__first, __n); + } + auto __idx = __first; #ifndef _LIBCPP_NO_EXCEPTIONS try { @@ -224,6 +355,10 @@ template inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator __uninitialized_value_construct(_ForwardIterator __first, _Sentinel __last) { + if constexpr (__uninitialized_algorithms::__can_use_memset_zero_v<_ValueType, _ForwardIterator>) { + return __uninitialized_algorithms::__memset_zero<_ValueType>(__first, __last - __first); + } + auto __idx = __first; #ifndef _LIBCPP_NO_EXCEPTIONS try { @@ -253,6 +388,10 @@ template inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator __uninitialized_value_construct_n(_ForwardIterator __first, _Size __n) { + if constexpr (__uninitialized_algorithms::__can_use_memset_zero_v<_ValueType, _ForwardIterator>) { + return __uninitialized_algorithms::__memset_zero<_ValueType>(__first, __n); + } + auto __idx = __first; #ifndef _LIBCPP_NO_EXCEPTIONS try { @@ -283,6 +422,11 @@ inline _LIBCPP_HIDE_FROM_ABI pair<_InputIterator, _ForwardIterator> __uninitialized_move(_InputIterator __ifirst, _Sentinel1 __ilast, _ForwardIterator __ofirst, _Sentinel2 __olast, _IterMove __iter_move) { + if constexpr (__uninitialized_algorithms::__can_use_memcpy_v<__iter_value_type<_InputIterator>, _ValueType, + _InputIterator, _ForwardIterator>) { + return __uninitialized_algorithms::__memcpy<_ValueType>(__ifirst, __ilast - __ifirst, __ofirst, __olast - __ofirst); + } + auto __idx = __ofirst; #ifndef _LIBCPP_NO_EXCEPTIONS try { @@ -316,7 +460,12 @@ template inline _LIBCPP_HIDE_FROM_ABI pair<_InputIterator, _ForwardIterator> __uninitialized_move_n(_InputIterator __ifirst, _Size __n, - _ForwardIterator __ofirst, _Sentinel __olast, _IterMove __iter_move) { + _ForwardIterator __ofirst, _Sentinel __olast, _IterMove __iter_move) { + if constexpr (__uninitialized_algorithms::__can_use_memcpy_v<__iter_value_type<_InputIterator>, _ValueType, + _InputIterator, _ForwardIterator>) { + return __uninitialized_algorithms::__memcpy<_ValueType>(__ifirst, __n, __ofirst, __olast - __ofirst); + } + auto __idx = __ofirst; #ifndef _LIBCPP_NO_EXCEPTIONS try { diff --git a/libcxx/include/type_traits b/libcxx/include/type_traits --- a/libcxx/include/type_traits +++ b/libcxx/include/type_traits @@ -1206,7 +1206,6 @@ // is_compound -// >= 11 because in C++03 nullptr isn't actually nullptr #if __has_keyword(__is_compound) && !defined(_LIBCPP_CXX03_LANG) template diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy.pass.cpp --- a/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy.pass.cpp +++ b/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy.pass.cpp @@ -51,6 +51,7 @@ std::allocator_traits::deallocate(alloc, pool, 5); } + { using Array = Counted[3][2]; using Alloc = std::allocator; @@ -75,6 +76,24 @@ std::allocator_traits::deallocate(alloc, pool, 5); } + // Trivial types. + { + constexpr int N = 5; + + int x[N] = {}; + std::destroy(x, x + N); + + int* y[N] = {}; + std::destroy(y, y + N); + + struct Trivial { + int a = 0; + float b = 0; + }; + Trivial z[N] = {}; + std::destroy(z, z + N); + } + return true; } #endif diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_at.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_at.pass.cpp --- a/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_at.pass.cpp +++ b/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_at.pass.cpp @@ -103,6 +103,7 @@ std::allocator_traits::deallocate(alloc, ptr1, 1); std::allocator_traits::deallocate(alloc, ptr2, 1); } + { using Alloc = std::allocator; Alloc alloc; @@ -125,6 +126,22 @@ std::allocator_traits::deallocate(alloc, ptr2, 1); } + // Trivial types. + { + int x = 0; + std::destroy_at(&x); + + int* y = nullptr; + std::destroy_at(&y); + + struct Trivial { + int a = 0; + float b = 0; + }; + Trivial z; + std::destroy_at(&z); + } + return true; } diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_n.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_n.pass.cpp --- a/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_n.pass.cpp +++ b/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_n.pass.cpp @@ -52,6 +52,7 @@ std::allocator_traits::deallocate(alloc, pool, 5); } + { using Array = Counted[3][2]; using Alloc = std::allocator; @@ -77,6 +78,24 @@ std::allocator_traits::deallocate(alloc, pool, 5); } + // Trivial types. + { + constexpr int N = 5; + + int x[N] = {}; + std::destroy_n(x, N); + + int* y[N] = {}; + std::destroy_n(y, N); + + struct Trivial { + int a = 0; + float b = 0; + }; + Trivial z[N] = {}; + std::destroy_n(z, N); + } + return true; } #endif diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/ranges_destroy.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/ranges_destroy.pass.cpp --- a/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/ranges_destroy.pass.cpp +++ b/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/ranges_destroy.pass.cpp @@ -206,6 +206,24 @@ Traits::deallocate(alloc, buffer, N); } + // Trivial types. + { + constexpr int N = 5; + + int x[N] = {}; + std::ranges::destroy(x, x + N); + + int* y[N] = {}; + std::ranges::destroy(y, y + N); + + struct Trivial { + int a = 0; + float b = 0; + }; + Trivial z[N] = {}; + std::ranges::destroy(z, z + N); + } + return true; } diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/ranges_destroy_at.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/ranges_destroy_at.pass.cpp --- a/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/ranges_destroy_at.pass.cpp +++ b/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/ranges_destroy_at.pass.cpp @@ -144,6 +144,22 @@ Traits::deallocate(alloc, array, 1); } + // Trivial types. + { + int x = 0; + std::ranges::destroy_at(&x); + + int* y = nullptr; + std::ranges::destroy_at(&y); + + struct Trivial { + int a = 0; + float b = 0; + }; + Trivial z; + std::ranges::destroy_at(&z); + } + return true; } diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/ranges_destroy_n.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/ranges_destroy_n.pass.cpp --- a/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/ranges_destroy_n.pass.cpp +++ b/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/ranges_destroy_n.pass.cpp @@ -128,6 +128,24 @@ Traits::deallocate(alloc, buffer, N); } + // Trivial types. + { + constexpr int N = 5; + + int x[N] = {}; + std::ranges::destroy_n(x, N); + + int* y[N] = {}; + std::ranges::destroy_n(y, N); + + struct Trivial { + int a = 0; + float b = 0; + }; + Trivial z[N] = {}; + std::ranges::destroy_n(z, N); + } + return true; } diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct.pass.cpp --- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct.pass.cpp +++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct.pass.cpp @@ -54,7 +54,7 @@ assert(Counted::total_objects == 0); forward_iterator it(buf.begin()); - auto range = std::ranges::subrange(it, sentinel_wrapper>(it)); + std::ranges::subrange range(it, sentinel_wrapper>(it)); std::ranges::uninitialized_default_construct(range.begin(), range.end()); assert(Counted::current_objects == 0); assert(Counted::total_objects == 0); @@ -82,7 +82,7 @@ constexpr int N = 5; Buffer buf; - auto range = std::ranges::subrange(buf.begin(), buf.end()); + std::ranges::subrange range(buf.begin(), buf.end()); std::ranges::uninitialized_default_construct(range); assert(Counted::current_objects == N); assert(Counted::total_objects == N); @@ -123,7 +123,7 @@ constexpr int N = 3; Buffer buf; - auto range = std::ranges::subrange(buf.begin(), buf.begin() + N); + std::ranges::subrange range(buf.begin(), buf.begin() + N); std::ranges::uninitialized_default_construct(std::ranges::reverse_view(range)); assert(Counted::current_objects == N); assert(Counted::total_objects == N); @@ -180,7 +180,7 @@ { constexpr int N = 5; Buffer buf; - auto range = std::ranges::subrange(buf.cbegin(), buf.cend()); + std::ranges::subrange range(buf.cbegin(), buf.cend()); std::ranges::uninitialized_default_construct(range); assert(Counted::current_objects == N); @@ -189,5 +189,65 @@ Counted::reset(); } + // Works with trivial types, (iter, sentinel) overload. + { + constexpr int N = 5; + + { + Buffer buf; + auto result = std::ranges::uninitialized_default_construct(buf.begin(), buf.end()); + assert(result == buf.end()); + } + + { + Buffer buf; + auto result = std::ranges::uninitialized_default_construct(buf.begin(), buf.end()); + assert(result == buf.end()); + } + + { + struct Trivial { + int a = 0; + float b = 0; + }; + Buffer buf; + auto result = std::ranges::uninitialized_default_construct(buf.begin(), buf.end()); + assert(result == buf.end()); + } + } + + // Works with trivial types, (range) overload. + { + constexpr int N = 5; + + { + Buffer buf; + std::ranges::subrange range(buf.begin(), buf.end()); + + auto result = std::ranges::uninitialized_default_construct(range); + assert(result == buf.end()); + } + + { + Buffer buf; + std::ranges::subrange range(buf.begin(), buf.end()); + + auto result = std::ranges::uninitialized_default_construct(range); + assert(result == buf.end()); + } + + { + struct Trivial { + int a = 0; + float b = 0; + }; + Buffer buf; + std::ranges::subrange range(buf.begin(), buf.end()); + + auto result = std::ranges::uninitialized_default_construct(range); + assert(result == buf.end()); + } + } + return 0; } diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/uninitialized_default_construct.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/uninitialized_default_construct.pass.cpp --- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/uninitialized_default_construct.pass.cpp +++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/uninitialized_default_construct.pass.cpp @@ -17,6 +17,7 @@ #include #include +#include "../buffer.h" #include "test_macros.h" #include "test_iterators.h" @@ -85,10 +86,28 @@ assert(Counted::count == 0); } +void test_trivial() { + constexpr int N = 5; + + Buffer x; + std::uninitialized_default_construct(x.begin(), x.end()); + + Buffer y; + std::uninitialized_default_construct(y.begin(), y.end()); + + struct Trivial { + int a = 0; + float b = 0; + }; + Buffer z; + std::uninitialized_default_construct(z.begin(), z.end()); +} + int main(int, char**) { test_counted(); test_ctor_throws(); + test_trivial(); - return 0; + return 0; } diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/ranges_uninitialized_value_construct.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/ranges_uninitialized_value_construct.pass.cpp --- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/ranges_uninitialized_value_construct.pass.cpp +++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/ranges_uninitialized_value_construct.pass.cpp @@ -56,7 +56,7 @@ assert(Counted::total_objects == 0); forward_iterator it(buf.begin()); - auto range = std::ranges::subrange(it, sentinel_wrapper>(it)); + std::ranges::subrange range(it, sentinel_wrapper>(it)); std::ranges::uninitialized_value_construct(range.begin(), range.end()); assert(Counted::current_objects == 0); assert(Counted::total_objects == 0); @@ -84,7 +84,7 @@ constexpr int N = 5; Buffer buf; - auto range = std::ranges::subrange(buf.begin(), buf.end()); + std::ranges::subrange range(buf.begin(), buf.end()); std::ranges::uninitialized_value_construct(range); assert(Counted::current_objects == N); assert(Counted::total_objects == N); @@ -124,7 +124,7 @@ constexpr int N = 3; Buffer buf; - auto range = std::ranges::subrange(buf.begin(), buf.begin() + N); + std::ranges::subrange range(buf.begin(), buf.begin() + N); std::ranges::uninitialized_value_construct(std::ranges::reverse_view(range)); assert(Counted::current_objects == N); assert(Counted::total_objects == N); @@ -201,7 +201,7 @@ constexpr int N = 5; Buffer buf; - auto range = std::ranges::subrange(buf.cbegin(), buf.cend()); + std::ranges::subrange range(buf.cbegin(), buf.cend()); std::ranges::uninitialized_value_construct(range); assert(Counted::current_objects == N); assert(Counted::total_objects == N); @@ -209,5 +209,76 @@ Counted::reset(); } + // Works with trivial types, (iter, sentinel) overload. + { + constexpr int N = 5; + + { + Buffer x; + + auto result = std::ranges::uninitialized_value_construct(x.begin(), x.end()); + assert(result == x.end()); + assert(std::all_of(x.begin(), x.end(), [](auto e) { return e == 0; })); + } + + { + Buffer y; + + auto result = std::ranges::uninitialized_value_construct(y.begin(), y.end()); + assert(result == y.end()); + assert(std::all_of(y.begin(), y.end(), [](auto e) { return e == nullptr; })); + } + + { + struct Trivial { + int a = 0; + float b = 0; + bool operator==(const Trivial& rhs) const { return a == rhs.a && b == rhs.b; } + }; + Buffer z; + + auto result = std::ranges::uninitialized_value_construct(z.begin(), z.end()); + assert(result == z.end()); + assert(std::all_of(z.begin(), z.end(), [](auto e) { return e == Trivial(); })); + } + } + + // Works with trivial types, (range) overload. + { + constexpr int N = 5; + + { + Buffer buf; + std::ranges::subrange range(buf.begin(), buf.end()); + + auto result = std::ranges::uninitialized_value_construct(range); + assert(result == buf.end()); + assert(std::all_of(buf.begin(), buf.end(), [](auto e) { return e == 0; })); + } + + { + Buffer buf; + std::ranges::subrange range(buf.begin(), buf.end()); + + auto result = std::ranges::uninitialized_value_construct(range); + assert(result == buf.end()); + assert(std::all_of(buf.begin(), buf.end(), [](auto e) { return e == nullptr; })); + } + + { + struct Trivial { + int a = 0; + float b = 0; + bool operator==(const Trivial& rhs) const { return a == rhs.a && b == rhs.b; } + }; + Buffer buf; + std::ranges::subrange range(buf.begin(), buf.end()); + + auto result = std::ranges::uninitialized_value_construct(range); + assert(result == buf.end()); + assert(std::all_of(buf.begin(), buf.end(), [](auto e) { return e == Trivial(); })); + } + } + return 0; } diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/uninitialized_value_construct.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/uninitialized_value_construct.pass.cpp --- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/uninitialized_value_construct.pass.cpp +++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/uninitialized_value_construct.pass.cpp @@ -14,11 +14,13 @@ // void uninitialized_value_construct(ForwardIt, ForwardIt); #include -#include +#include #include +#include -#include "test_macros.h" +#include "../buffer.h" #include "test_iterators.h" +#include "test_macros.h" struct Counted { static int count; @@ -102,11 +104,34 @@ assert(pool[4] == 0); } +void test_trivial() { + constexpr int N = 5; + + Buffer x; + std::uninitialized_value_construct(x.begin(), x.end()); + assert(std::all_of(x.begin(), x.end(), [](auto e) { return e == 0; })); + + Buffer y; + std::uninitialized_value_construct(y.begin(), y.end()); + assert(std::all_of(y.begin(), y.end(), [](auto e) { return e == nullptr; })); + + struct Trivial { + int a = 0; + float b = 0; + bool operator==(const Trivial& rhs) const { return a == rhs.a && b == rhs.b; } + }; + Buffer z; + + std::uninitialized_value_construct(z.begin(), z.end()); + assert(std::all_of(z.begin(), z.end(), [](auto e) { return e == Trivial(); })); +} + int main(int, char**) { test_counted(); test_value_initialized(); test_ctor_throws(); + test_trivial(); - return 0; + return 0; } diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill.n/ranges_uninitialized_fill_n.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill.n/ranges_uninitialized_fill_n.pass.cpp --- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill.n/ranges_uninitialized_fill_n.pass.cpp +++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill.n/ranges_uninitialized_fill_n.pass.cpp @@ -36,6 +36,13 @@ struct NotConvertibleFromInt {}; static_assert(!std::is_invocable_v); +template +void test_trivial(From x) { + Buffer buf; + std::ranges::uninitialized_fill_n(buf.begin(), buf.size(), x); + assert(std::all_of(buf.begin(), buf.end(), [=](auto e) { return e == x; })); +} + int main(int, char**) { constexpr int value = 42; Counted x(value); @@ -116,5 +123,23 @@ Counted::reset(); } + // Works with trivial types, . + { + test_trivial('a'); + test_trivial('a'); + test_trivial(std::byte(4)); + test_trivial(4); + test_trivial('a'); + test_trivial(4); // ! + + struct Trivial { + int a = 0; + float b = 0; + bool operator==(const Trivial& rhs) const { return a == rhs.a && b == rhs.b; } + }; + Trivial foo = {3, 4.f}; + test_trivial(foo); + } + return 0; } diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill.n/uninitialized_fill_n.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill.n/uninitialized_fill_n.pass.cpp --- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill.n/uninitialized_fill_n.pass.cpp +++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill.n/uninitialized_fill_n.pass.cpp @@ -13,8 +13,10 @@ // uninitialized_fill_n(ForwardIterator first, Size n, const T& x); #include +#include #include +#include "../buffer.h" #include "test_macros.h" struct B @@ -46,6 +48,14 @@ int Nasty::counter_ = 0; +template +void test_trivial(From x) { + Buffer buf; + + std::uninitialized_fill_n(buf.begin(), buf.size(), x); + assert(std::all_of(buf.begin(), buf.end(), [=](auto e) { return e == x; })); +} + int main(int, char**) { { @@ -53,6 +63,7 @@ char pool[sizeof(B)*N] = {0}; B* bp = (B*)pool; assert(B::population_ == 0); + #ifndef TEST_HAS_NO_EXCEPTIONS try { @@ -64,6 +75,7 @@ assert(B::population_ == 0); } #endif + B::count_ = 0; B* r = std::uninitialized_fill_n(bp, 2, B()); assert(r == bp + 2); @@ -71,7 +83,7 @@ assert(bp[i].data_ == 1); assert(B::population_ == 2); } - { + { const int N = 5; char pool[N*sizeof(Nasty)] = {0}; @@ -83,7 +95,25 @@ assert(bp[i].i_ == 23); } + // Works with trivial types. + { + test_trivial('a'); + test_trivial('a'); +#if TEST_STD_VER > 14 + test_trivial(std::byte(4)); +#endif + test_trivial(4); + test_trivial('a'); + test_trivial(4); // ! + + struct Trivial { + int a = 0; + float b = 0; + bool operator==(const Trivial& rhs) const { return a == rhs.a && b == rhs.b; } + }; + Trivial x = {3, 4.f}; + test_trivial(x); } - return 0; + return 0; } diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill/ranges_uninitialized_fill.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill/ranges_uninitialized_fill.pass.cpp --- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill/ranges_uninitialized_fill.pass.cpp +++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill/ranges_uninitialized_fill.pass.cpp @@ -41,6 +41,24 @@ static_assert(!std::is_invocable_v); +template +void test_trivial(From x) { + constexpr int N = 5; + + { + Buffer buf; + std::ranges::uninitialized_fill(buf.begin(), buf.end(), x); + assert(std::all_of(buf.begin(), buf.end(), [=](auto e) { return e == x; })); + } + + { + Buffer buf; + std::ranges::subrange range(buf.begin(), buf.end()); + std::ranges::uninitialized_fill(range, x); + assert(std::all_of(buf.begin(), buf.end(), [=](auto e) { return e == x; })); + } +} + int main(int, char**) { constexpr int value = 42; Counted x(value); @@ -228,5 +246,23 @@ Counted::reset(); } + // Works with trivial types, . + { + test_trivial('a'); + test_trivial('a'); + test_trivial(std::byte(4)); + test_trivial(4); + test_trivial('a'); + test_trivial(4); // ! + + struct Trivial { + int a = 0; + float b = 0; + bool operator==(const Trivial& rhs) const { return a == rhs.a && b == rhs.b; } + }; + Trivial foo = {3, 4.f}; + test_trivial(foo); + } + return 0; } diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill/uninitialized_fill.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill/uninitialized_fill.pass.cpp --- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill/uninitialized_fill.pass.cpp +++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill/uninitialized_fill.pass.cpp @@ -14,8 +14,10 @@ // const T& x); #include +#include #include +#include "../buffer.h" #include "test_macros.h" struct B @@ -47,6 +49,14 @@ int Nasty::counter_ = 0; +template +void test_trivial(From x) { + Buffer buf; + + std::uninitialized_fill(buf.begin(), buf.end(), x); + assert(std::all_of(buf.begin(), buf.end(), [=](auto e) { return e == x; })); +} + int main(int, char**) { { @@ -54,6 +64,7 @@ char pool[sizeof(B)*N] = {0}; B* bp = (B*)pool; assert(B::population_ == 0); + #ifndef TEST_HAS_NO_EXCEPTIONS try { @@ -65,12 +76,14 @@ assert(B::population_ == 0); } #endif + B::count_ = 0; std::uninitialized_fill(bp, bp+2, B()); for (int i = 0; i < 2; ++i) assert(bp[i].data_ == 1); assert(B::population_ == 2); } + { const int N = 5; char pool[N*sizeof(Nasty)] = {0}; @@ -82,5 +95,25 @@ assert(bp[i].i_ == 23); } - return 0; + // Works with trivial types. + { + test_trivial('a'); + test_trivial('a'); +#if TEST_STD_VER > 14 + test_trivial(std::byte(4)); +#endif + test_trivial(4); + test_trivial('a'); + test_trivial(4); + + struct Trivial { + int a = 0; + float b = 0; + bool operator==(const Trivial& rhs) const { return a == rhs.a && b == rhs.b; } + }; + Trivial x = {3, 4.f}; + test_trivial(x); + } + + return 0; }