diff --git a/libcxx/docs/Status/RangesAlgorithms.csv b/libcxx/docs/Status/RangesAlgorithms.csv --- a/libcxx/docs/Status/RangesAlgorithms.csv +++ b/libcxx/docs/Status/RangesAlgorithms.csv @@ -84,17 +84,17 @@ Permutation,sort_heap,Not assigned,n/a,Not started Permutation,prev_permutation,Not assigned,n/a,Not started Permutation,next_permutation,Not assigned,n/a,Not started -Uninitialised memory,uninitialized_copy,var-const,n/a,Not started -Uninitialised memory,uninitialized_copy_n,var-const,n/a,Not started -Uninitialised memory,uninitialized_fill,var-const,n/a,Not started -Uninitialised memory,uninitialized_fill_n,var-const,n/a,Not started -Uninitialised memory,uninitialized_move,var-const,n/a,Not started -Uninitialised memory,uninitialized_move_n,var-const,n/a,Not started -Uninitialised memory,uninitialized_default_construct,var-const,n/a,Not started -Uninitialised memory,uninitialized_default_construct_n,var-const,n/a,Not started -Uninitialised memory,uninitialized_value_construct,var-const,n/a,Not started -Uninitialised memory,uninitialized_value_construct_n,var-const,n/a,Not started -Uninitialised memory,destroy,var-const,n/a,Not started -Uninitialised memory,destroy_n,var-const,n/a,Not started -Uninitialised memory,destroy_at,var-const,n/a,Not started -Uninitialised memory,construct_at,var-const,n/a,Not started +Uninitialised memory,uninitialized_copy,Konstantin Varlamov,n/a,Not started +Uninitialised memory,uninitialized_copy_n,Konstantin Varlamov,n/a,Not started +Uninitialised memory,uninitialized_fill,Konstantin Varlamov,`D115626 `_,✅ +Uninitialised memory,uninitialized_fill_n,Konstantin Varlamov,`D115626 `_,✅ +Uninitialised memory,uninitialized_move,Konstantin Varlamov,n/a,Not started +Uninitialised memory,uninitialized_move_n,Konstantin Varlamov,n/a,Not started +Uninitialised memory,uninitialized_default_construct,Konstantin Varlamov,`D115315 `_,✅ +Uninitialised memory,uninitialized_default_construct_n,Konstantin Varlamov,`D115315 `_,✅ +Uninitialised memory,uninitialized_value_construct,Konstantin Varlamov,`D115626 `_,✅ +Uninitialised memory,uninitialized_value_construct_n,Konstantin Varlamov,`D115626 `_,✅ +Uninitialised memory,destroy,Konstantin Varlamov,n/a,Not started +Uninitialised memory,destroy_n,Konstantin Varlamov,n/a,Not started +Uninitialised memory,destroy_at,Konstantin Varlamov,n/a,Not started +Uninitialised memory,construct_at,Konstantin Varlamov,n/a,Not started diff --git a/libcxx/docs/Status/RangesPaper.csv b/libcxx/docs/Status/RangesPaper.csv --- a/libcxx/docs/Status/RangesPaper.csv +++ b/libcxx/docs/Status/RangesPaper.csv @@ -18,16 +18,16 @@ | *nothrow-forward-iterator* | *nothrow-forward-range*","| [iterator.concepts] | [range.refinements]",Konstantin Varlamov,✅ -`[specialized.algorithms] `_,"| `ranges::uninitialized_default_construct ` -| `ranges::uninitialized_default_construct_n ` -| ranges::uninitialized_value_construct -| ranges::uninitialized_value_construct_n +`[specialized.algorithms] `_,"| `ranges::uninitialized_default_construct `_ +| `ranges::uninitialized_default_construct_n `_ +| `ranges::uninitialized_value_construct `_ +| `ranges::uninitialized_value_construct_n `_ | ranges::uninitialized_copy | ranges::uninitialized_copy_n | ranges::uninitialized_move | ranges::uninitialized_move_n -| ranges::uninitialized_fill -| ranges::uninitialized_fill_n +| `ranges::uninitialized_fill `_ +| `ranges::uninitialized_fill_n `_ | ranges::construct_at | ranges::destroy | ranges::destroy_at diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -238,6 +238,7 @@ __memory/uninitialized_algorithms.h __memory/unique_ptr.h __memory/uses_allocator.h + __memory/voidify.h __mutex_base __numeric/accumulate.h __numeric/adjacent_difference.h 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 @@ -41,44 +41,67 @@ // destroy_at -#if _LIBCPP_STD_VER > 14 +// The internal functions are available regardless of the language version (with the exception of the `__destroy_at` +// taking an array). template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 -void destroy(_ForwardIterator, _ForwardIterator); +void __destroy(_ForwardIterator, _ForwardIterator); -template , int> = 0> +template ::value, int>::type = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 -void destroy_at(_Tp* __loc) { +void __destroy_at(_Tp* __loc) { _LIBCPP_ASSERT(__loc, "null pointer given to destroy_at"); __loc->~_Tp(); } +#if _LIBCPP_STD_VER > 17 +template ::value, int>::type = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 +void __destroy_at(_Tp* __loc) { + _LIBCPP_ASSERT(__loc, "null pointer given to destroy_at"); + _VSTD::__destroy(_VSTD::begin(*__loc), _VSTD::end(*__loc)); +} +#endif + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 +void __destroy(_ForwardIterator __first, _ForwardIterator __last) { + for (; __first != __last; ++__first) + _VSTD::__destroy_at(_VSTD::addressof(*__first)); +} + +#if _LIBCPP_STD_VER > 14 + +template , int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 +void destroy_at(_Tp* __loc) { + _VSTD::__destroy_at(__loc); +} + #if _LIBCPP_STD_VER > 17 template , int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 void destroy_at(_Tp* __loc) { - _LIBCPP_ASSERT(__loc, "null pointer given to destroy_at"); - _VSTD::destroy(_VSTD::begin(*__loc), _VSTD::end(*__loc)); + _VSTD::__destroy_at(__loc); } #endif template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 void destroy(_ForwardIterator __first, _ForwardIterator __last) { - for (; __first != __last; ++__first) - _VSTD::destroy_at(_VSTD::addressof(*__first)); + _VSTD::__destroy(_VSTD::move(__first), _VSTD::move(__last)); } template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 _ForwardIterator destroy_n(_ForwardIterator __first, _Size __n) { for (; __n > 0; (void)++__first, --__n) - _VSTD::destroy_at(_VSTD::addressof(*__first)); + _VSTD::__destroy_at(_VSTD::addressof(*__first)); return __first; } -#endif +#endif // _LIBCPP_STD_VER > 14 _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__memory/ranges_uninitialized_algorithms.h b/libcxx/include/__memory/ranges_uninitialized_algorithms.h --- a/libcxx/include/__memory/ranges_uninitialized_algorithms.h +++ b/libcxx/include/__memory/ranges_uninitialized_algorithms.h @@ -21,6 +21,7 @@ #include <__ranges/access.h> #include <__ranges/concepts.h> #include <__ranges/dangling.h> +#include <__utility/move.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -45,7 +46,8 @@ requires default_initializable> _ForwardIterator operator()(_ForwardIterator __first, _Sentinel __last) const { using _ValueType = remove_reference_t>; - return _VSTD::__uninitialized_default_construct<_ValueType>(__first, __last); + return _VSTD::__uninitialized_default_construct<_ValueType>( + _VSTD::move(__first), _VSTD::move(__last)); } template <__nothrow_forward_range _ForwardRange> @@ -56,7 +58,7 @@ }; -} // namespace __uninitialized_default_construct_ns +} // namespace __uninitialized_default_construct inline namespace __cpo { inline constexpr auto uninitialized_default_construct = @@ -77,18 +79,131 @@ _ForwardIterator operator()(_ForwardIterator __first, iter_difference_t<_ForwardIterator> __n) const { using _ValueType = remove_reference_t>; - return _VSTD::__uninitialized_default_construct_n<_ValueType>(__first, __n); + return _VSTD::__uninitialized_default_construct_n<_ValueType>(_VSTD::move(__first), __n); } }; -} // namespace __uninitialized_default_construct_n_ns +} // namespace __uninitialized_default_construct_n inline namespace __cpo { inline constexpr auto uninitialized_default_construct_n = __uninitialized_default_construct_n::__fn(__function_like::__tag()); } // namespace __cpo +// uninitialized_value_construct + +namespace __uninitialized_value_construct { + +struct __fn final : private __function_like { + + constexpr explicit __fn(__tag __x) noexcept : __function_like(__x) {} + + template <__nothrow_forward_iterator _ForwardIterator, + __nothrow_sentinel_for<_ForwardIterator> _Sentinel> + requires default_initializable> + _ForwardIterator operator()(_ForwardIterator __first, _Sentinel __last) const { + using _ValueType = remove_reference_t>; + return _VSTD::__uninitialized_value_construct<_ValueType>( + _VSTD::move(__first), _VSTD::move(__last)); + } + + template <__nothrow_forward_range _ForwardRange> + requires default_initializable> + borrowed_iterator_t<_ForwardRange> operator()(_ForwardRange&& __range) const { + return (*this)(ranges::begin(__range), ranges::end(__range)); + } + +}; + +} // namespace __uninitialized_value_construct + +inline namespace __cpo { +inline constexpr auto uninitialized_value_construct = + __uninitialized_value_construct::__fn(__function_like::__tag()); +} // namespace __cpo + +// uninitialized_value_construct_n + +namespace __uninitialized_value_construct_n { + +struct __fn final : private __function_like { + + constexpr explicit __fn(__tag __x) noexcept : __function_like(__x) {} + + template <__nothrow_forward_iterator _ForwardIterator> + requires default_initializable> + _ForwardIterator operator()(_ForwardIterator __first, + iter_difference_t<_ForwardIterator> __n) const { + using _ValueType = remove_reference_t>; + return _VSTD::__uninitialized_value_construct_n<_ValueType>(_VSTD::move(__first), __n); + } + +}; + +} // namespace __uninitialized_value_construct_n + +inline namespace __cpo { +inline constexpr auto uninitialized_value_construct_n = + __uninitialized_value_construct_n::__fn(__function_like::__tag()); +} // namespace __cpo + +// uninitialized_fill + +namespace __uninitialized_fill { + +struct __fn final : private __function_like { + + constexpr explicit __fn(__tag __x) noexcept : __function_like(__x) {} + + template <__nothrow_forward_iterator _ForwardIterator, + __nothrow_sentinel_for<_ForwardIterator> _Sentinel, + class _Tp> + requires constructible_from, const _Tp&> + _ForwardIterator operator()(_ForwardIterator __first, _Sentinel __last, const _Tp& __x) const { + using _ValueType = remove_reference_t>; + return _VSTD::__uninitialized_fill<_ValueType>(_VSTD::move(__first), _VSTD::move(__last), __x); + } + + template <__nothrow_forward_range _ForwardRange, class _Tp> + requires constructible_from, const _Tp&> + borrowed_iterator_t<_ForwardRange> operator()(_ForwardRange&& __range, const _Tp& __x) const { + return (*this)(ranges::begin(__range), ranges::end(__range), __x); + } + +}; + +} // namespace __uninitialized_fil + +inline namespace __cpo { +inline constexpr auto uninitialized_fill = __uninitialized_fill::__fn(__function_like::__tag()); +} // namespace __cpo + +// uninitialized_fill_n + +namespace __uninitialized_fill_n { + +struct __fn final : private __function_like { + + constexpr explicit __fn(__tag __x) noexcept : __function_like(__x) {} + + template <__nothrow_forward_iterator _ForwardIterator, class _Tp> + requires constructible_from, const _Tp&> + _ForwardIterator operator()(_ForwardIterator __first, + iter_difference_t<_ForwardIterator> __n, + const _Tp& __x) const { + using _ValueType = remove_reference_t>; + return _VSTD::__uninitialized_fill_n<_ValueType>(_VSTD::move(__first), __n, __x); + } + +}; + +} // namespace __uninitialized_fill_n + +inline namespace __cpo { +inline constexpr auto uninitialized_fill_n = __uninitialized_fill_n::__fn(__function_like::__tag()); +} // namespace __cpo + } // namespace ranges #endif // !defined(_LIBCPP_HAS_NO_RANGES) 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 @@ -13,6 +13,7 @@ #include <__config> #include <__memory/addressof.h> #include <__memory/construct_at.h> +#include <__memory/voidify.h> #include #include @@ -70,51 +71,70 @@ return __r; } -template -void -uninitialized_fill(_ForwardIterator __f, _ForwardIterator __l, const _Tp& __x) +// uninitialized_fill + +template +inline _LIBCPP_HIDE_FROM_ABI +_ForwardIterator __uninitialized_fill(_ForwardIterator __first, _Sentinel __last, const _Tp& __x) { - typedef typename iterator_traits<_ForwardIterator>::value_type value_type; + _ForwardIterator __idx = __first; #ifndef _LIBCPP_NO_EXCEPTIONS - _ForwardIterator __s = __f; try { #endif - for (; __f != __l; ++__f) - ::new ((void*)_VSTD::addressof(*__f)) value_type(__x); + for (; __idx != __last; ++__idx) + ::new (_VSTD::__voidify(*__idx)) _ValueType(__x); #ifndef _LIBCPP_NO_EXCEPTIONS } catch (...) { - for (; __s != __f; ++__s) - __s->~value_type(); + _VSTD::__destroy(__first, __idx); throw; } #endif + + return __idx; } -template -_ForwardIterator -uninitialized_fill_n(_ForwardIterator __f, _Size __n, const _Tp& __x) +template +inline _LIBCPP_HIDE_FROM_ABI +void uninitialized_fill(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __x) { - typedef typename iterator_traits<_ForwardIterator>::value_type value_type; + typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType; + (void)_VSTD::__uninitialized_fill<_ValueType>(__first, __last, __x); +} + +// uninitialized_fill_n + +template +inline _LIBCPP_HIDE_FROM_ABI +_ForwardIterator __uninitialized_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x) +{ + _ForwardIterator __idx = __first; #ifndef _LIBCPP_NO_EXCEPTIONS - _ForwardIterator __s = __f; try { #endif - for (; __n > 0; ++__f, (void) --__n) - ::new ((void*)_VSTD::addressof(*__f)) value_type(__x); + for (; __n > 0; ++__idx, (void) --__n) + ::new (_VSTD::__voidify(*__idx)) _ValueType(__x); #ifndef _LIBCPP_NO_EXCEPTIONS } catch (...) { - for (; __s != __f; ++__s) - __s->~value_type(); + _VSTD::__destroy(__first, __idx); throw; } #endif - return __f; + + return __idx; +} + +template +inline _LIBCPP_HIDE_FROM_ABI +_ForwardIterator uninitialized_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x) +{ + typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType; + return _VSTD::__uninitialized_fill_n<_ValueType>(__first, __n, __x); } #if _LIBCPP_STD_VER > 14 @@ -129,10 +149,10 @@ try { #endif for (; __idx != __last; ++__idx) - ::new ((void*)_VSTD::addressof(*__idx)) _ValueType; + ::new (_VSTD::__voidify(*__idx)) _ValueType; #ifndef _LIBCPP_NO_EXCEPTIONS } catch (...) { - _VSTD::destroy(__first, __idx); + _VSTD::__destroy(__first, __idx); throw; } #endif @@ -141,10 +161,11 @@ } template -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_HIDE_FROM_ABI void uninitialized_default_construct(_ForwardIterator __first, _ForwardIterator __last) { using _ValueType = typename iterator_traits<_ForwardIterator>::value_type; - (void)_VSTD::__uninitialized_default_construct<_ValueType>(__first, __last); + (void)_VSTD::__uninitialized_default_construct<_ValueType>( + _VSTD::move(__first), _VSTD::move(__last)); } // uninitialized_default_construct_n @@ -157,10 +178,10 @@ try { #endif for (; __n > 0; ++__idx, (void) --__n) - ::new ((void*)_VSTD::addressof(*__idx)) _ValueType; + ::new (_VSTD::__voidify(*__idx)) _ValueType; #ifndef _LIBCPP_NO_EXCEPTIONS } catch (...) { - _VSTD::destroy(__first, __idx); + _VSTD::__destroy(__first, __idx); throw; } #endif @@ -169,49 +190,68 @@ } template -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator uninitialized_default_construct_n(_ForwardIterator __first, _Size __n) { using _ValueType = typename iterator_traits<_ForwardIterator>::value_type; - return _VSTD::__uninitialized_default_construct_n<_ValueType>(__first, __n); + return _VSTD::__uninitialized_default_construct_n<_ValueType>(_VSTD::move(__first), __n); } -template -inline _LIBCPP_INLINE_VISIBILITY -void uninitialized_value_construct(_ForwardIterator __first, _ForwardIterator __last) { - using _Vt = typename iterator_traits<_ForwardIterator>::value_type; +// uninitialized_value_construct + +template +inline _LIBCPP_HIDE_FROM_ABI +_ForwardIterator __uninitialized_value_construct(_ForwardIterator __first, _Sentinel __last) { auto __idx = __first; #ifndef _LIBCPP_NO_EXCEPTIONS try { #endif for (; __idx != __last; ++__idx) - ::new ((void*)_VSTD::addressof(*__idx)) _Vt(); + ::new (_VSTD::__voidify(*__idx)) _ValueType(); #ifndef _LIBCPP_NO_EXCEPTIONS } catch (...) { - _VSTD::destroy(__first, __idx); + _VSTD::__destroy(__first, __idx); throw; } #endif + + return __idx; } -template -inline _LIBCPP_INLINE_VISIBILITY -_ForwardIterator uninitialized_value_construct_n(_ForwardIterator __first, _Size __n) { - using _Vt = typename iterator_traits<_ForwardIterator>::value_type; +template +inline _LIBCPP_HIDE_FROM_ABI +void uninitialized_value_construct(_ForwardIterator __first, _ForwardIterator __last) { + using _ValueType = typename iterator_traits<_ForwardIterator>::value_type; + (void)_VSTD::__uninitialized_value_construct<_ValueType>( + _VSTD::move(__first), _VSTD::move(__last)); +} + +// uninitialized_value_construct_n + +template +inline _LIBCPP_HIDE_FROM_ABI +_ForwardIterator __uninitialized_value_construct_n(_ForwardIterator __first, _Size __n) { auto __idx = __first; #ifndef _LIBCPP_NO_EXCEPTIONS try { #endif for (; __n > 0; ++__idx, (void) --__n) - ::new ((void*)_VSTD::addressof(*__idx)) _Vt(); - return __idx; + ::new (_VSTD::__voidify(*__idx)) _ValueType(); #ifndef _LIBCPP_NO_EXCEPTIONS } catch (...) { - _VSTD::destroy(__first, __idx); + _VSTD::__destroy(__first, __idx); throw; } #endif + + return __idx; } +template +inline _LIBCPP_HIDE_FROM_ABI +_ForwardIterator uninitialized_value_construct_n(_ForwardIterator __first, _Size __n) { + using _ValueType = typename iterator_traits<_ForwardIterator>::value_type; + return __uninitialized_value_construct_n<_ValueType>(_VSTD::move(__first), __n); +} template inline _LIBCPP_INLINE_VISIBILITY diff --git a/libcxx/include/__memory/voidify.h b/libcxx/include/__memory/voidify.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__memory/voidify.h @@ -0,0 +1,30 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MEMORY_VOIDIFY_H +#define _LIBCPP___MEMORY_VOIDIFY_H + +#include <__config> +#include <__memory/addressof.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 void* __voidify(_Tp& __from) { + // Cast away cv-qualifiers to allow modifying elements of a range through const iterators. + return const_cast(static_cast(_VSTD::addressof(__from))); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___MEMORY_VOIDIFY_H diff --git a/libcxx/include/memory b/libcxx/include/memory --- a/libcxx/include/memory +++ b/libcxx/include/memory @@ -188,10 +188,22 @@ template void uninitialized_fill(ForwardIterator first, ForwardIterator last, const T& x); +template Sentinel, class T> + requires constructible_from, const T&> +ForwardIterator ranges::uninitialized_fill(ForwardIterator first, Sentinel last, const T& x); // since C++20 + +template + requires constructible_from, const T&> +borrowed_iterator_t ranges::uninitialized_fill(ForwardRange&& range, const T& x); // since C++20 + template ForwardIterator uninitialized_fill_n(ForwardIterator first, Size n, const T& x); +template + requires constructible_from, const T&> +ForwardIterator ranges::uninitialized_fill_n(ForwardIterator first, iter_difference_t n); // since C++20 + template constexpr T* construct_at(T* location, Args&& ...args); // since C++20 @@ -213,9 +225,21 @@ template void uninitialized_value_construct(ForwardIterator first, ForwardIterator last); +template Sentinel> + requires default_initializable> + ForwardIterator ranges::uninitialized_value_construct(ForwardIterator first, Sentinel last); // since C++20 + +template + requires default_initializable> + borrowed_iterator_t ranges::uninitialized_value_construct(ForwardRange&& r); // since C++20 + template ForwardIterator uninitialized_value_construct_n(ForwardIterator first, Size n); +template + requires default_initializable> + ForwardIterator ranges::uninitialized_value_construct_n(ForwardIterator first, iter_difference_t n); // since C++20 + template void uninitialized_default_construct(ForwardIterator first, ForwardIterator last); diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -650,6 +650,7 @@ module uninitialized_algorithms { private header "__memory/uninitialized_algorithms.h" } module unique_ptr { private header "__memory/unique_ptr.h" } module uses_allocator { private header "__memory/uses_allocator.h" } + module voidify { private header "__memory/voidify.h" } } } module mutex { diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/memory/voidify.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/memory/voidify.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/memory/voidify.module.verify.cpp @@ -0,0 +1,15 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: modules-build + +// WARNING: This test was generated by 'generate_private_header_tests.py' +// and should not be edited manually. + +// expected-error@*:* {{use of private header from outside its module: '__memory/voidify.h'}} +#include <__memory/voidify.h> diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/buffer.h b/libcxx/test/std/utilities/memory/specialized.algorithms/buffer.h new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/memory/specialized.algorithms/buffer.h @@ -0,0 +1,25 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LIBCPP_TEST_STD_UTILITIES_MEMORY_SPECIALIZED_ALGORITHMS_BUFFER_H +#define LIBCPP_TEST_STD_UTILITIES_MEMORY_SPECIALIZED_ALGORITHMS_BUFFER_H + +template +struct Buffer { + alignas(T) char buffer[sizeof(T) * N] = {}; + + T* begin() { return reinterpret_cast(buffer); } + T* end() { return begin() + N; } + const T* cbegin() const { return reinterpret_cast(buffer); } + const T* cend() const { return cbegin() + N; } + + constexpr int size() const { return N; } +}; + +#endif // LIBCPP_TEST_STD_UTILITIES_MEMORY_SPECIALIZED_ALGORITHMS_BUFFER_H diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/counted.h b/libcxx/test/std/utilities/memory/specialized.algorithms/counted.h new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/memory/specialized.algorithms/counted.h @@ -0,0 +1,62 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LIBCPP_TEST_STD_UTILITIES_MEMORY_SPECIALIZED_ALGORITHMS_COUNTED_H +#define LIBCPP_TEST_STD_UTILITIES_MEMORY_SPECIALIZED_ALGORITHMS_COUNTED_H + +#include "test_macros.h" + +struct Counted { + static int current_objects; + static int total_objects; + static int throw_on; + + int value; + + explicit Counted() { + check_throw(); + increase_counters(); + } + + explicit Counted(int v) : value(v) { + check_throw(); + increase_counters(); + } + + ~Counted() { --current_objects; } + + static void reset() { + current_objects = total_objects = 0; + throw_on = -1; + } + + Counted(const Counted& rhs) : value(rhs.value) { + check_throw(); + increase_counters(); + } + + friend void operator&(Counted) = delete; + +private: + void check_throw() { + if (throw_on == total_objects) { + TEST_THROW(1); + } + } + + void increase_counters() { + ++current_objects; + ++total_objects; + } +}; +int Counted::current_objects = 0; +int Counted::total_objects = 0; +int Counted::throw_on = -1; + +#endif // LIBCPP_TEST_STD_UTILITIES_MEMORY_SPECIALIZED_ALGORITHMS_COUNTED_H 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 @@ -25,47 +25,11 @@ #include #include +#include "../buffer.h" +#include "../counted.h" #include "test_macros.h" #include "test_iterators.h" -struct Counted { - static int current_objects; - static int total_objects; - static int throw_on; - - explicit Counted() { - if (throw_on == total_objects) { - TEST_THROW(1); - } - - ++current_objects; - ++total_objects; - } - - ~Counted() { --current_objects; } - - static void reset() { - current_objects = total_objects = 0; - throw_on = -1; - } - - Counted(Counted const&) = delete; - friend void operator&(Counted) = delete; -}; -int Counted::current_objects = 0; -int Counted::total_objects = 0; -int Counted::throw_on = -1; - -template -struct Buffer { - alignas(T) char buffer[sizeof(T) * N] = {}; - - T* begin() { return reinterpret_cast(buffer); } - T* end() { return begin() + N; } - const T* cbegin() const { return reinterpret_cast(buffer); } - const T* cend() const { return cbegin() + N; } -}; - // Because this is a variable and not a function, it's guaranteed that ADL won't be used. However, // implementations are allowed to use a different mechanism to achieve this effect, so this check is // libc++-specific. @@ -145,8 +109,7 @@ constexpr int N = 3; Buffer buf; - auto counted_range = std::views::counted(buf.begin(), N); - std::ranges::uninitialized_default_construct(counted_range); + std::ranges::uninitialized_default_construct(std::views::counted(buf.begin(), N)); assert(Counted::current_objects == N); assert(Counted::total_objects == N); diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct_n.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct_n.pass.cpp --- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct_n.pass.cpp +++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct_n.pass.cpp @@ -20,47 +20,11 @@ #include #include +#include "../buffer.h" +#include "../counted.h" #include "test_macros.h" #include "test_iterators.h" -struct Counted { - static int current_objects; - static int total_objects; - static int throw_on; - - explicit Counted() { - if (throw_on == total_objects) { - TEST_THROW(1); - } - - ++current_objects; - ++total_objects; - } - - ~Counted() { --current_objects; } - - static void reset() { - current_objects = total_objects = 0; - throw_on = -1; - } - - Counted(Counted const&) = delete; - friend void operator&(Counted) = delete; -}; -int Counted::current_objects = 0; -int Counted::total_objects = 0; -int Counted::throw_on = -1; - -template -struct Buffer { - alignas(T) char buffer[sizeof(T) * N] = {}; - - T* begin() { return reinterpret_cast(buffer); } - T* end() { return begin() + N; } - const T* cbegin() const { return reinterpret_cast(buffer); } - const T* cend() const { return cbegin() + N; } -}; - // Because this is a variable and not a function, it's guaranteed that ADL won't be used. However, // implementations are allowed to use a different mechanism to achieve this effect, so this check is // libc++-specific. 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.value/ranges_uninitialized_value_construct.pass.cpp copy from libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct.pass.cpp copy to 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.default/ranges_uninitialized_default_construct.pass.cpp +++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/ranges_uninitialized_value_construct.pass.cpp @@ -13,11 +13,11 @@ // template Sentinel> // requires default_initializable> -// ForwardIterator ranges::uninitialized_default_construct(ForwardIterator first, Sentinel last); +// ForwardIterator ranges::uninitialized_value_construct(ForwardIterator first, Sentinel last); // // template // requires default_initializable> -// borrowed_iterator_t ranges::uninitialized_default_construct(ForwardRange&& range); +// borrowed_iterator_t ranges::uninitialized_value_construct(ForwardRange&& range); #include #include @@ -25,76 +25,42 @@ #include #include +#include "../buffer.h" +#include "../counted.h" #include "test_macros.h" #include "test_iterators.h" -struct Counted { - static int current_objects; - static int total_objects; - static int throw_on; - - explicit Counted() { - if (throw_on == total_objects) { - TEST_THROW(1); - } - - ++current_objects; - ++total_objects; - } - - ~Counted() { --current_objects; } - - static void reset() { - current_objects = total_objects = 0; - throw_on = -1; - } - - Counted(Counted const&) = delete; - friend void operator&(Counted) = delete; -}; -int Counted::current_objects = 0; -int Counted::total_objects = 0; -int Counted::throw_on = -1; - -template -struct Buffer { - alignas(T) char buffer[sizeof(T) * N] = {}; - - T* begin() { return reinterpret_cast(buffer); } - T* end() { return begin() + N; } - const T* cbegin() const { return reinterpret_cast(buffer); } - const T* cend() const { return cbegin() + N; } -}; - // Because this is a variable and not a function, it's guaranteed that ADL won't be used. However, // implementations are allowed to use a different mechanism to achieve this effect, so this check is // libc++-specific. -LIBCPP_STATIC_ASSERT(std::is_class_v); +LIBCPP_STATIC_ASSERT(std::is_class_v); -struct NotDefaultCtrable { NotDefaultCtrable() = delete; }; -static_assert(!std::is_invocable_v); +struct NotDefaultCtrable { + NotDefaultCtrable() = delete; +}; +static_assert( + !std::is_invocable_v); int main(int, char**) { // An empty range -- no default constructors should be invoked. { Buffer buf; - std::ranges::uninitialized_default_construct(buf.begin(), buf.begin()); + std::ranges::uninitialized_value_construct(buf.begin(), buf.begin()); assert(Counted::current_objects == 0); assert(Counted::total_objects == 0); - std::ranges::uninitialized_default_construct(std::ranges::empty_view()); + std::ranges::uninitialized_value_construct(std::ranges::empty_view()); assert(Counted::current_objects == 0); assert(Counted::total_objects == 0); forward_iterator it(buf.begin()); auto range = std::ranges::subrange(it, sentinel_wrapper>(it)); - std::ranges::uninitialized_default_construct(range.begin(), range.end()); + std::ranges::uninitialized_value_construct(range.begin(), range.end()); assert(Counted::current_objects == 0); assert(Counted::total_objects == 0); - std::ranges::uninitialized_default_construct(range); + std::ranges::uninitialized_value_construct(range); assert(Counted::current_objects == 0); assert(Counted::total_objects == 0); } @@ -102,9 +68,9 @@ // A range containing several objects, (iter, sentinel) overload. { constexpr int N = 5; - Buffer buf; + Buffer buf; - std::ranges::uninitialized_default_construct(buf.begin(), buf.end()); + std::ranges::uninitialized_value_construct(buf.begin(), buf.end()); assert(Counted::current_objects == N); assert(Counted::total_objects == N); @@ -118,7 +84,7 @@ Buffer buf; auto range = std::ranges::subrange(buf.begin(), buf.end()); - std::ranges::uninitialized_default_construct(range); + std::ranges::uninitialized_value_construct(range); assert(Counted::current_objects == N); assert(Counted::total_objects == N); @@ -131,8 +97,7 @@ constexpr int N = 3; Buffer buf; - std::ranges::uninitialized_default_construct( - std::counted_iterator(buf.begin(), N), std::default_sentinel); + std::ranges::uninitialized_value_construct(std::counted_iterator(buf.begin(), N), std::default_sentinel); assert(Counted::current_objects == N); assert(Counted::total_objects == N); @@ -145,8 +110,7 @@ constexpr int N = 3; Buffer buf; - auto counted_range = std::views::counted(buf.begin(), N); - std::ranges::uninitialized_default_construct(counted_range); + std::ranges::uninitialized_value_construct(std::views::counted(buf.begin(), N)); assert(Counted::current_objects == N); assert(Counted::total_objects == N); @@ -160,7 +124,7 @@ Buffer buf; auto range = std::ranges::subrange(buf.begin(), buf.begin() + N); - std::ranges::uninitialized_default_construct(std::ranges::reverse_view(range)); + std::ranges::uninitialized_value_construct(std::ranges::reverse_view(range)); assert(Counted::current_objects == N); assert(Counted::total_objects == N); @@ -168,6 +132,23 @@ Counted::reset(); } + // Any existing values should be overwritten by value constructors. + { + constexpr int N = 5; + int buffer[N] = {42, 42, 42, 42, 42}; + + std::ranges::uninitialized_value_construct(buffer, buffer + 1); + assert(buffer[0] == 0); + assert(buffer[1] == 42); + + std::ranges::uninitialized_value_construct(buffer, buffer + N); + assert(buffer[0] == 0); + assert(buffer[1] == 0); + assert(buffer[2] == 0); + assert(buffer[3] == 0); + assert(buffer[4] == 0); + } + // An exception is thrown while objects are being created -- the existing objects should stay // valid. (iterator, sentinel) overload. #ifndef TEST_HAS_NO_EXCEPTIONS @@ -176,8 +157,9 @@ Counted::throw_on = 3; // When constructing the fourth object (counting from one). try { - std::ranges::uninitialized_default_construct(buf.begin(), buf.end()); - } catch(...) {} + std::ranges::uninitialized_value_construct(buf.begin(), buf.end()); + } catch (...) { + } assert(Counted::current_objects == 0); assert(Counted::total_objects == 3); std::destroy(buf.begin(), buf.begin() + Counted::total_objects); @@ -192,21 +174,22 @@ Counted::throw_on = 3; // When constructing the fourth object. try { auto range = std::ranges::subrange(buf.begin(), buf.end()); - std::ranges::uninitialized_default_construct(range); - } catch(...) {} + std::ranges::uninitialized_value_construct(range); + } catch (...) { + } assert(Counted::current_objects == 0); assert(Counted::total_objects == 3); std::destroy(buf.begin(), buf.begin() + Counted::total_objects); Counted::reset(); } -#endif // TEST_HAS_NO_EXCEPTIONS +#endif // TEST_HAS_NO_EXCEPTIONS // Works with const iterators, (iter, sentinel) overload. { constexpr int N = 5; Buffer buf; - std::ranges::uninitialized_default_construct(buf.cbegin(), buf.cend()); + std::ranges::uninitialized_value_construct(buf.cbegin(), buf.cend()); assert(Counted::current_objects == N); assert(Counted::total_objects == N); std::destroy(buf.begin(), buf.end()); @@ -217,9 +200,9 @@ { constexpr int N = 5; Buffer buf; - auto range = std::ranges::subrange(buf.cbegin(), buf.cend()); - std::ranges::uninitialized_default_construct(range); + auto range = std::ranges::subrange(buf.cbegin(), buf.cend()); + std::ranges::uninitialized_value_construct(range); assert(Counted::current_objects == N); assert(Counted::total_objects == N); std::destroy(buf.begin(), buf.end()); diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct_n.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/ranges_uninitialized_value_construct_n.pass.cpp copy from libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct_n.pass.cpp copy to libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/ranges_uninitialized_value_construct_n.pass.cpp --- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct_n.pass.cpp +++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/ranges_uninitialized_value_construct_n.pass.cpp @@ -13,69 +13,34 @@ // template // requires default_initializable> -// ForwardIterator ranges::uninitialized_default_construct_n(ForwardIterator first, +// ForwardIterator ranges::uninitialized_value_construct_n(ForwardIterator first, // iter_difference_t n); #include #include #include +#include "../buffer.h" +#include "../counted.h" #include "test_macros.h" #include "test_iterators.h" -struct Counted { - static int current_objects; - static int total_objects; - static int throw_on; - - explicit Counted() { - if (throw_on == total_objects) { - TEST_THROW(1); - } - - ++current_objects; - ++total_objects; - } - - ~Counted() { --current_objects; } - - static void reset() { - current_objects = total_objects = 0; - throw_on = -1; - } - - Counted(Counted const&) = delete; - friend void operator&(Counted) = delete; -}; -int Counted::current_objects = 0; -int Counted::total_objects = 0; -int Counted::throw_on = -1; - -template -struct Buffer { - alignas(T) char buffer[sizeof(T) * N] = {}; - - T* begin() { return reinterpret_cast(buffer); } - T* end() { return begin() + N; } - const T* cbegin() const { return reinterpret_cast(buffer); } - const T* cend() const { return cbegin() + N; } -}; - // Because this is a variable and not a function, it's guaranteed that ADL won't be used. However, // implementations are allowed to use a different mechanism to achieve this effect, so this check is // libc++-specific. -LIBCPP_STATIC_ASSERT(std::is_class_v); +LIBCPP_STATIC_ASSERT(std::is_class_v); -struct NotDefaultCtrable { NotDefaultCtrable() = delete; }; -static_assert(!std::is_invocable_v); +struct NotDefaultCtrable { + NotDefaultCtrable() = delete; +}; +static_assert(!std::is_invocable_v); int main(int, char**) { // An empty range -- no default constructors should be invoked. { Buffer buf; - std::ranges::uninitialized_default_construct_n(buf.begin(), 0); + std::ranges::uninitialized_value_construct_n(buf.begin(), 0); assert(Counted::current_objects == 0); assert(Counted::total_objects == 0); } @@ -85,7 +50,7 @@ constexpr int N = 5; Buffer buf; - std::ranges::uninitialized_default_construct_n(buf.begin(), N); + std::ranges::uninitialized_value_construct_n(buf.begin(), N); assert(Counted::current_objects == N); assert(Counted::total_objects == N); @@ -93,6 +58,23 @@ Counted::reset(); } + // Any existing values should be overwritten by value constructors. + { + constexpr int N = 5; + int buffer[N] = {42, 42, 42, 42, 42}; + + std::ranges::uninitialized_value_construct_n(buffer, 1); + assert(buffer[0] == 0); + assert(buffer[1] == 42); + + std::ranges::uninitialized_value_construct_n(buffer, N); + assert(buffer[0] == 0); + assert(buffer[1] == 0); + assert(buffer[2] == 0); + assert(buffer[3] == 0); + assert(buffer[4] == 0); + } + // An exception is thrown while objects are being created -- the existing objects should stay // valid. #ifndef TEST_HAS_NO_EXCEPTIONS @@ -102,21 +84,22 @@ Counted::throw_on = 3; // When constructing the fourth object (counting from one). try { - std::ranges::uninitialized_default_construct_n(buf.begin(), N); - } catch(...) {} + std::ranges::uninitialized_value_construct_n(buf.begin(), N); + } catch (...) { + } assert(Counted::current_objects == 0); assert(Counted::total_objects == 3); std::destroy(buf.begin(), buf.begin() + Counted::total_objects); Counted::reset(); } -#endif // TEST_HAS_NO_EXCEPTIONS +#endif // TEST_HAS_NO_EXCEPTIONS // Works with const iterators. { constexpr int N = 5; Buffer buf; - std::ranges::uninitialized_default_construct_n(buf.cbegin(), N); + std::ranges::uninitialized_value_construct_n(buf.cbegin(), N); assert(Counted::current_objects == N); assert(Counted::total_objects == N); std::destroy(buf.begin(), buf.end()); diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct_n.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill.n/ranges_uninitialized_fill_n.pass.cpp copy from libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct_n.pass.cpp copy to 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.construct.default/ranges_uninitialized_default_construct_n.pass.cpp +++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill.n/ranges_uninitialized_fill_n.pass.cpp @@ -11,71 +11,42 @@ // -// template -// requires default_initializable> -// ForwardIterator ranges::uninitialized_default_construct_n(ForwardIterator first, -// iter_difference_t n); +// template +// requires constructible_from, const T&> +// ForwardIterator ranges::uninitialized_fill_n(ForwardIterator first, iter_difference_t n); +#include #include +#include #include #include +#include +#include "../buffer.h" +#include "../counted.h" #include "test_macros.h" #include "test_iterators.h" -struct Counted { - static int current_objects; - static int total_objects; - static int throw_on; - - explicit Counted() { - if (throw_on == total_objects) { - TEST_THROW(1); - } - - ++current_objects; - ++total_objects; - } - - ~Counted() { --current_objects; } - - static void reset() { - current_objects = total_objects = 0; - throw_on = -1; - } - - Counted(Counted const&) = delete; - friend void operator&(Counted) = delete; -}; -int Counted::current_objects = 0; -int Counted::total_objects = 0; -int Counted::throw_on = -1; - -template -struct Buffer { - alignas(T) char buffer[sizeof(T) * N] = {}; - - T* begin() { return reinterpret_cast(buffer); } - T* end() { return begin() + N; } - const T* cbegin() const { return reinterpret_cast(buffer); } - const T* cend() const { return cbegin() + N; } -}; - // Because this is a variable and not a function, it's guaranteed that ADL won't be used. However, // implementations are allowed to use a different mechanism to achieve this effect, so this check is // libc++-specific. -LIBCPP_STATIC_ASSERT(std::is_class_v); +LIBCPP_STATIC_ASSERT(std::is_class_v); -struct NotDefaultCtrable { NotDefaultCtrable() = delete; }; -static_assert(!std::is_invocable_v); +struct NotConvertibleFromInt {}; +static_assert(!std::is_invocable_v); int main(int, char**) { + constexpr int value = 42; + Counted x(value); + Counted::reset(); + auto pred = [](const Counted& e) { return e.value == value; }; + // An empty range -- no default constructors should be invoked. { Buffer buf; - std::ranges::uninitialized_default_construct_n(buf.begin(), 0); + std::ranges::uninitialized_fill_n(buf.begin(), 0, x); assert(Counted::current_objects == 0); assert(Counted::total_objects == 0); } @@ -85,40 +56,62 @@ constexpr int N = 5; Buffer buf; - std::ranges::uninitialized_default_construct_n(buf.begin(), N); + std::ranges::uninitialized_fill_n(buf.begin(), N, x); assert(Counted::current_objects == N); assert(Counted::total_objects == N); + assert(std::all_of(buf.begin(), buf.end(), pred)); std::destroy(buf.begin(), buf.end()); Counted::reset(); } + // Any existing values should be overwritten by value constructors. + { + constexpr int N = 5; + int buffer[N] = {value, value, value, value, value}; + + std::ranges::uninitialized_fill_n(buffer, 1, 0); + assert(buffer[0] == 0); + assert(buffer[1] == value); + + std::ranges::uninitialized_fill_n(buffer, N, 0); + assert(buffer[0] == 0); + assert(buffer[1] == 0); + assert(buffer[2] == 0); + assert(buffer[3] == 0); + assert(buffer[4] == 0); + } + // An exception is thrown while objects are being created -- the existing objects should stay - // valid. + // valid. (iterator, sentinel) overload. #ifndef TEST_HAS_NO_EXCEPTIONS { constexpr int N = 5; Buffer buf; - Counted::throw_on = 3; // When constructing the fourth object (counting from one). + Counted::throw_on = 3; // When constructing the fourth object. try { - std::ranges::uninitialized_default_construct_n(buf.begin(), N); - } catch(...) {} + std::ranges::uninitialized_fill_n(buf.begin(), N, x); + } catch (...) { + } assert(Counted::current_objects == 0); assert(Counted::total_objects == 3); - std::destroy(buf.begin(), buf.begin() + Counted::total_objects); + + std::destroy(buf.begin(), buf.begin() + 3); Counted::reset(); } -#endif // TEST_HAS_NO_EXCEPTIONS +#endif // TEST_HAS_NO_EXCEPTIONS // Works with const iterators. { constexpr int N = 5; Buffer buf; - std::ranges::uninitialized_default_construct_n(buf.cbegin(), N); + std::ranges::uninitialized_fill_n(buf.cbegin(), N, x); assert(Counted::current_objects == N); assert(Counted::total_objects == N); + assert(std::all_of(buf.begin(), buf.end(), pred)); + std::destroy(buf.begin(), buf.end()); Counted::reset(); } 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.fill/ranges_uninitialized_fill.pass.cpp copy from libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct.pass.cpp copy to libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill/ranges_uninitialized_fill.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.fill/ranges_uninitialized_fill.pass.cpp @@ -11,102 +11,75 @@ // -// template Sentinel> -// requires default_initializable> -// ForwardIterator ranges::uninitialized_default_construct(ForwardIterator first, Sentinel last); +// template Sentinel, class T> +// requires constructible_from, const T&> +// ForwardIterator ranges::uninitialized_fill(ForwardIterator first, Sentinel last, const T& x); // -// template -// requires default_initializable> -// borrowed_iterator_t ranges::uninitialized_default_construct(ForwardRange&& range); +// template +// requires constructible_from, const T&> +// borrowed_iterator_t ranges::uninitialized_fill(ForwardRange&& range, const T& x); +#include #include #include #include #include #include +#include "../buffer.h" +#include "../counted.h" #include "test_macros.h" #include "test_iterators.h" -struct Counted { - static int current_objects; - static int total_objects; - static int throw_on; - - explicit Counted() { - if (throw_on == total_objects) { - TEST_THROW(1); - } - - ++current_objects; - ++total_objects; - } - - ~Counted() { --current_objects; } - - static void reset() { - current_objects = total_objects = 0; - throw_on = -1; - } - - Counted(Counted const&) = delete; - friend void operator&(Counted) = delete; -}; -int Counted::current_objects = 0; -int Counted::total_objects = 0; -int Counted::throw_on = -1; - -template -struct Buffer { - alignas(T) char buffer[sizeof(T) * N] = {}; - - T* begin() { return reinterpret_cast(buffer); } - T* end() { return begin() + N; } - const T* cbegin() const { return reinterpret_cast(buffer); } - const T* cend() const { return cbegin() + N; } -}; - // Because this is a variable and not a function, it's guaranteed that ADL won't be used. However, // implementations are allowed to use a different mechanism to achieve this effect, so this check is // libc++-specific. -LIBCPP_STATIC_ASSERT(std::is_class_v); +LIBCPP_STATIC_ASSERT(std::is_class_v); -struct NotDefaultCtrable { NotDefaultCtrable() = delete; }; -static_assert(!std::is_invocable_v); +struct NotConvertibleFromInt {}; +static_assert(!std::is_invocable_v); int main(int, char**) { + constexpr int value = 42; + Counted x(value); + Counted::reset(); + auto pred = [](const Counted& e) { return e.value == value; }; + // An empty range -- no default constructors should be invoked. { Buffer buf; - std::ranges::uninitialized_default_construct(buf.begin(), buf.begin()); + std::ranges::uninitialized_fill(buf.begin(), buf.begin(), x); assert(Counted::current_objects == 0); assert(Counted::total_objects == 0); - std::ranges::uninitialized_default_construct(std::ranges::empty_view()); + std::ranges::uninitialized_fill(std::ranges::empty_view(), x); assert(Counted::current_objects == 0); assert(Counted::total_objects == 0); forward_iterator it(buf.begin()); auto range = std::ranges::subrange(it, sentinel_wrapper>(it)); - std::ranges::uninitialized_default_construct(range.begin(), range.end()); + std::ranges::uninitialized_fill(range.begin(), range.end(), x); assert(Counted::current_objects == 0); assert(Counted::total_objects == 0); + Counted::reset(); - std::ranges::uninitialized_default_construct(range); + std::ranges::uninitialized_fill(range, x); assert(Counted::current_objects == 0); assert(Counted::total_objects == 0); + Counted::reset(); } // A range containing several objects, (iter, sentinel) overload. { constexpr int N = 5; - Buffer buf; + Buffer buf; - std::ranges::uninitialized_default_construct(buf.begin(), buf.end()); + std::ranges::uninitialized_fill(buf.begin(), buf.end(), x); assert(Counted::current_objects == N); assert(Counted::total_objects == N); + assert(std::all_of(buf.begin(), buf.end(), pred)); std::destroy(buf.begin(), buf.end()); Counted::reset(); @@ -118,9 +91,10 @@ Buffer buf; auto range = std::ranges::subrange(buf.begin(), buf.end()); - std::ranges::uninitialized_default_construct(range); + std::ranges::uninitialized_fill(range, x); assert(Counted::current_objects == N); assert(Counted::total_objects == N); + assert(std::all_of(buf.begin(), buf.end(), pred)); std::destroy(buf.begin(), buf.end()); Counted::reset(); @@ -131,10 +105,10 @@ constexpr int N = 3; Buffer buf; - std::ranges::uninitialized_default_construct( - std::counted_iterator(buf.begin(), N), std::default_sentinel); + std::ranges::uninitialized_fill(std::counted_iterator(buf.begin(), N), std::default_sentinel, x); assert(Counted::current_objects == N); assert(Counted::total_objects == N); + assert(std::all_of(buf.begin(), buf.begin() + N, pred)); std::destroy(buf.begin(), buf.begin() + N); Counted::reset(); @@ -145,10 +119,10 @@ constexpr int N = 3; Buffer buf; - auto counted_range = std::views::counted(buf.begin(), N); - std::ranges::uninitialized_default_construct(counted_range); + std::ranges::uninitialized_fill(std::views::counted(buf.begin(), N), x); assert(Counted::current_objects == N); assert(Counted::total_objects == N); + assert(std::all_of(buf.begin(), buf.begin() + N, pred)); std::destroy(buf.begin(), buf.begin() + N); Counted::reset(); @@ -160,55 +134,81 @@ Buffer buf; auto range = std::ranges::subrange(buf.begin(), buf.begin() + N); - std::ranges::uninitialized_default_construct(std::ranges::reverse_view(range)); + std::ranges::uninitialized_fill(std::ranges::reverse_view(range), x); assert(Counted::current_objects == N); assert(Counted::total_objects == N); + assert(std::all_of(buf.begin(), buf.begin() + N, pred)); std::destroy(buf.begin(), buf.begin() + N); Counted::reset(); } + // Any existing values should be overwritten by value constructors. + { + constexpr int N = 5; + int buffer[N] = {value, value, value, value, value}; + + std::ranges::uninitialized_fill(buffer, buffer + 1, 0); + assert(buffer[0] == 0); + assert(buffer[1] == value); + + std::ranges::uninitialized_fill(buffer, buffer + N, 0); + assert(buffer[0] == 0); + assert(buffer[1] == 0); + assert(buffer[2] == 0); + assert(buffer[3] == 0); + assert(buffer[4] == 0); + } + // An exception is thrown while objects are being created -- the existing objects should stay // valid. (iterator, sentinel) overload. #ifndef TEST_HAS_NO_EXCEPTIONS { + constexpr int N = 3; Buffer buf; - Counted::throw_on = 3; // When constructing the fourth object (counting from one). + Counted::throw_on = N; // When constructing the fourth object. try { - std::ranges::uninitialized_default_construct(buf.begin(), buf.end()); - } catch(...) {} + std::ranges::uninitialized_fill(buf.begin(), buf.end(), x); + } catch (...) { + } assert(Counted::current_objects == 0); - assert(Counted::total_objects == 3); - std::destroy(buf.begin(), buf.begin() + Counted::total_objects); + assert(Counted::total_objects == N); + + std::destroy(buf.begin(), buf.begin() + N); Counted::reset(); } // An exception is thrown while objects are being created -- the existing objects should stay // valid. (range) overload. { + constexpr int N = 3; Buffer buf; - Counted::throw_on = 3; // When constructing the fourth object. + Counted::throw_on = N; // When constructing the fourth object. try { auto range = std::ranges::subrange(buf.begin(), buf.end()); - std::ranges::uninitialized_default_construct(range); - } catch(...) {} + std::ranges::uninitialized_fill(range, x); + } catch (...) { + } assert(Counted::current_objects == 0); - assert(Counted::total_objects == 3); - std::destroy(buf.begin(), buf.begin() + Counted::total_objects); + assert(Counted::total_objects == N); + + std::destroy(buf.begin(), buf.begin() + N); Counted::reset(); } -#endif // TEST_HAS_NO_EXCEPTIONS +#endif // TEST_HAS_NO_EXCEPTIONS // Works with const iterators, (iter, sentinel) overload. { constexpr int N = 5; Buffer buf; - std::ranges::uninitialized_default_construct(buf.cbegin(), buf.cend()); + std::ranges::uninitialized_fill(buf.cbegin(), buf.cend(), x); assert(Counted::current_objects == N); assert(Counted::total_objects == N); + assert(std::all_of(buf.begin(), buf.end(), pred)); + std::destroy(buf.begin(), buf.end()); Counted::reset(); } @@ -217,11 +217,13 @@ { constexpr int N = 5; Buffer buf; - auto range = std::ranges::subrange(buf.cbegin(), buf.cend()); - std::ranges::uninitialized_default_construct(range); + auto range = std::ranges::subrange(buf.cbegin(), buf.cend()); + std::ranges::uninitialized_fill(range, x); assert(Counted::current_objects == N); assert(Counted::total_objects == N); + assert(std::all_of(buf.begin(), buf.end(), pred)); + std::destroy(buf.begin(), buf.end()); Counted::reset(); }