libstdc++: implement constexpr memory algorithms
This commit adds support for C++26's constexpr specialized memory algorithms, introduced by P2283R2, P3508R0, P3369R0. The uninitialized_default, value, copy, move and fill algorithms are affected, in all of their variants (iterator-based, range-based and _n versions.) The changes are mostly mechanical -- add `constexpr` to a number of signatures when compiling in C++26 and above modes. The internal helper guard class for range algorithms instead can be marked unconditionally. uninitialized_default_construct is implemented in terms of the _Construct_novalue helper, which requires support for C++26's constexpr placement new from the compiler (P2747R2, which GCC implements). We can simply mark it as constexpr in C++26 language modes, even if the compiler does not support P2747R2 (e.g. Clang 17/18), because C++23's P2448R2 makes it OK to mark functions as constexpr even if they never qualify, and other compilers implement this. The only "real" change to the implementation of the algorithms is that during constant evaluation I need to dispatch to a constexpr-friendly version of them. For each algorithm family I've added only one test to cover it and its variants; the idea is to avoid too much repetition and simplify future maintenance. libstdc++-v3/ChangeLog: * include/bits/ranges_uninitialized.h: Mark the specialized memory algorithms as constexpr in C++26. Also mark the members of the _DestroyGuard helper class. * include/bits/stl_uninitialized.h: Ditto. * include/bits/stl_construct.h: (_Construct_novalue) Mark it as constexpr in C++26. * include/bits/version.def (raw_memory_algorithms): Bump the feature-testing macro for C++26. * include/bits/version.h: Regenerate. * testsuite/20_util/headers/memory/synopsis.cc: Add constexpr to the uninitialized_* algorithms (when in C++26) in the test. * testsuite/20_util/specialized_algorithms/feature_test_macro.cc: New test. * testsuite/20_util/specialized_algorithms/uninitialized_copy/constexpr.cc: New test. * testsuite/20_util/specialized_algorithms/uninitialized_default_construct/constexpr.cc: New test. * testsuite/20_util/specialized_algorithms/uninitialized_fill/constexpr.cc: New test. * testsuite/20_util/specialized_algorithms/uninitialized_move/constexpr.cc: New test. * testsuite/20_util/specialized_algorithms/uninitialized_value_construct/constexpr.cc: New test. Reviewed-by: Patrick Palka <ppalka@redhat.com>
This commit is contained in:
parent
705ae582d5
commit
3052b33645
12 changed files with 406 additions and 1 deletions
|
@ -105,15 +105,18 @@ namespace ranges
|
|||
const _Iter* _M_cur;
|
||||
|
||||
public:
|
||||
constexpr
|
||||
explicit
|
||||
_DestroyGuard(const _Iter& __iter)
|
||||
: _M_first(__iter), _M_cur(std::__addressof(__iter))
|
||||
{ }
|
||||
|
||||
constexpr
|
||||
void
|
||||
release() noexcept
|
||||
{ _M_cur = nullptr; }
|
||||
|
||||
constexpr
|
||||
~_DestroyGuard()
|
||||
{
|
||||
if (_M_cur != nullptr)
|
||||
|
@ -126,10 +129,12 @@ namespace ranges
|
|||
&& is_trivially_destructible_v<iter_value_t<_Iter>>
|
||||
struct _DestroyGuard<_Iter>
|
||||
{
|
||||
constexpr
|
||||
explicit
|
||||
_DestroyGuard(const _Iter&)
|
||||
{ }
|
||||
|
||||
constexpr
|
||||
void
|
||||
release() noexcept
|
||||
{ }
|
||||
|
@ -141,6 +146,7 @@ namespace ranges
|
|||
template<__detail::__nothrow_forward_iterator _Iter,
|
||||
__detail::__nothrow_sentinel<_Iter> _Sent>
|
||||
requires default_initializable<iter_value_t<_Iter>>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
_Iter
|
||||
operator()(_Iter __first, _Sent __last) const
|
||||
{
|
||||
|
@ -159,6 +165,7 @@ namespace ranges
|
|||
|
||||
template<__detail::__nothrow_forward_range _Range>
|
||||
requires default_initializable<range_value_t<_Range>>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
borrowed_iterator_t<_Range>
|
||||
operator()(_Range&& __r) const
|
||||
{
|
||||
|
@ -173,6 +180,7 @@ namespace ranges
|
|||
{
|
||||
template<__detail::__nothrow_forward_iterator _Iter>
|
||||
requires default_initializable<iter_value_t<_Iter>>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
_Iter
|
||||
operator()(_Iter __first, iter_difference_t<_Iter> __n) const
|
||||
{
|
||||
|
@ -198,6 +206,7 @@ namespace ranges
|
|||
template<__detail::__nothrow_forward_iterator _Iter,
|
||||
__detail::__nothrow_sentinel<_Iter> _Sent>
|
||||
requires default_initializable<iter_value_t<_Iter>>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
_Iter
|
||||
operator()(_Iter __first, _Sent __last) const
|
||||
{
|
||||
|
@ -217,6 +226,7 @@ namespace ranges
|
|||
|
||||
template<__detail::__nothrow_forward_range _Range>
|
||||
requires default_initializable<range_value_t<_Range>>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
borrowed_iterator_t<_Range>
|
||||
operator()(_Range&& __r) const
|
||||
{
|
||||
|
@ -231,6 +241,7 @@ namespace ranges
|
|||
{
|
||||
template<__detail::__nothrow_forward_iterator _Iter>
|
||||
requires default_initializable<iter_value_t<_Iter>>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
_Iter
|
||||
operator()(_Iter __first, iter_difference_t<_Iter> __n) const
|
||||
{
|
||||
|
@ -261,6 +272,7 @@ namespace ranges
|
|||
__detail::__nothrow_forward_iterator _Out,
|
||||
__detail::__nothrow_sentinel<_Out> _OSent>
|
||||
requires constructible_from<iter_value_t<_Out>, iter_reference_t<_Iter>>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
uninitialized_copy_result<_Iter, _Out>
|
||||
operator()(_Iter __ifirst, _ISent __ilast,
|
||||
_Out __ofirst, _OSent __olast) const
|
||||
|
@ -292,6 +304,7 @@ namespace ranges
|
|||
template<input_range _IRange, __detail::__nothrow_forward_range _ORange>
|
||||
requires constructible_from<range_value_t<_ORange>,
|
||||
range_reference_t<_IRange>>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
uninitialized_copy_result<borrowed_iterator_t<_IRange>,
|
||||
borrowed_iterator_t<_ORange>>
|
||||
operator()(_IRange&& __inr, _ORange&& __outr) const
|
||||
|
@ -311,6 +324,7 @@ namespace ranges
|
|||
template<input_iterator _Iter, __detail::__nothrow_forward_iterator _Out,
|
||||
__detail::__nothrow_sentinel<_Out> _Sent>
|
||||
requires constructible_from<iter_value_t<_Out>, iter_reference_t<_Iter>>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
uninitialized_copy_n_result<_Iter, _Out>
|
||||
operator()(_Iter __ifirst, iter_difference_t<_Iter> __n,
|
||||
_Out __ofirst, _Sent __olast) const
|
||||
|
@ -350,6 +364,7 @@ namespace ranges
|
|||
__detail::__nothrow_sentinel<_Out> _OSent>
|
||||
requires constructible_from<iter_value_t<_Out>,
|
||||
iter_rvalue_reference_t<_Iter>>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
uninitialized_move_result<_Iter, _Out>
|
||||
operator()(_Iter __ifirst, _ISent __ilast,
|
||||
_Out __ofirst, _OSent __olast) const
|
||||
|
@ -384,6 +399,7 @@ namespace ranges
|
|||
template<input_range _IRange, __detail::__nothrow_forward_range _ORange>
|
||||
requires constructible_from<range_value_t<_ORange>,
|
||||
range_rvalue_reference_t<_IRange>>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
uninitialized_move_result<borrowed_iterator_t<_IRange>,
|
||||
borrowed_iterator_t<_ORange>>
|
||||
operator()(_IRange&& __inr, _ORange&& __outr) const
|
||||
|
@ -404,6 +420,7 @@ namespace ranges
|
|||
__detail::__nothrow_sentinel<_Out> _Sent>
|
||||
requires constructible_from<iter_value_t<_Out>,
|
||||
iter_rvalue_reference_t<_Iter>>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
uninitialized_move_n_result<_Iter, _Out>
|
||||
operator()(_Iter __ifirst, iter_difference_t<_Iter> __n,
|
||||
_Out __ofirst, _Sent __olast) const
|
||||
|
@ -441,6 +458,7 @@ namespace ranges
|
|||
template<__detail::__nothrow_forward_iterator _Iter,
|
||||
__detail::__nothrow_sentinel<_Iter> _Sent, typename _Tp>
|
||||
requires constructible_from<iter_value_t<_Iter>, const _Tp&>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
_Iter
|
||||
operator()(_Iter __first, _Sent __last, const _Tp& __x) const
|
||||
{
|
||||
|
@ -460,6 +478,7 @@ namespace ranges
|
|||
|
||||
template<__detail::__nothrow_forward_range _Range, typename _Tp>
|
||||
requires constructible_from<range_value_t<_Range>, const _Tp&>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
borrowed_iterator_t<_Range>
|
||||
operator()(_Range&& __r, const _Tp& __x) const
|
||||
{
|
||||
|
@ -473,6 +492,7 @@ namespace ranges
|
|||
{
|
||||
template<__detail::__nothrow_forward_iterator _Iter, typename _Tp>
|
||||
requires constructible_from<iter_value_t<_Iter>, const _Tp&>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
_Iter
|
||||
operator()(_Iter __first, iter_difference_t<_Iter> __n,
|
||||
const _Tp& __x) const
|
||||
|
@ -573,6 +593,7 @@ namespace ranges
|
|||
}
|
||||
_GLIBCXX_END_NAMESPACE_VERSION
|
||||
} // namespace std
|
||||
|
||||
#endif // concepts
|
||||
#endif // C++20
|
||||
#endif // _RANGES_UNINITIALIZED_H
|
||||
|
|
|
@ -144,6 +144,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
#endif
|
||||
|
||||
template<typename _T1>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
inline void
|
||||
_Construct_novalue(_T1* __p)
|
||||
{ ::new(static_cast<void*>(__p)) _T1; }
|
||||
|
|
|
@ -226,6 +226,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
* Like std::copy, but does not require an initialized output range.
|
||||
*/
|
||||
template<typename _InputIterator, typename _ForwardIterator>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
inline _ForwardIterator
|
||||
uninitialized_copy(_InputIterator __first, _InputIterator __last,
|
||||
_ForwardIterator __result)
|
||||
|
@ -256,6 +257,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
using _Src = decltype(std::__niter_base(__first));
|
||||
using _ValT = typename iterator_traits<_ForwardIterator>::value_type;
|
||||
|
||||
#if __glibcxx_raw_memory_algorithms >= 202411L // >= C++26
|
||||
if consteval {
|
||||
return std::__do_uninit_copy(__first, __last, __result);
|
||||
}
|
||||
#endif
|
||||
if constexpr (!__is_trivially_constructible(_ValT, decltype(*__first)))
|
||||
return std::__do_uninit_copy(__first, __last, __result);
|
||||
else if constexpr (__memcpyable<_Dest, _Src>::__value)
|
||||
|
@ -381,6 +387,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
* Like std::fill, but does not require an initialized output range.
|
||||
*/
|
||||
template<typename _ForwardIterator, typename _Tp>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
inline void
|
||||
uninitialized_fill(_ForwardIterator __first, _ForwardIterator __last,
|
||||
const _Tp& __x)
|
||||
|
@ -400,6 +407,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
#if __cplusplus >= 201103L
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wc++17-extensions"
|
||||
#if __glibcxx_raw_memory_algorithms >= 202411L // >= C++26
|
||||
if consteval {
|
||||
return std::__do_uninit_fill(__first, __last, __x);
|
||||
}
|
||||
#endif
|
||||
if constexpr (__is_byte<_ValueType>::__value)
|
||||
if constexpr (is_same<_ValueType, _Tp>::value
|
||||
|| is_integral<_Tp>::value)
|
||||
|
@ -509,6 +521,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
* Like std::fill_n, but does not require an initialized output range.
|
||||
*/
|
||||
template<typename _ForwardIterator, typename _Size, typename _Tp>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
inline _ForwardIterator
|
||||
uninitialized_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x)
|
||||
{
|
||||
|
@ -522,6 +535,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
_ValueType;
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
#if __glibcxx_raw_memory_algorithms >= 202411L // >= C++26
|
||||
if consteval {
|
||||
return std::__do_uninit_fill_n(__first, __n, __x);
|
||||
}
|
||||
#endif
|
||||
if constexpr (__is_byte<_ValueType>::__value)
|
||||
if constexpr (is_integral<_Tp>::value)
|
||||
if constexpr (is_integral<_Size>::value)
|
||||
|
@ -815,6 +833,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
struct __uninitialized_default_1
|
||||
{
|
||||
template<typename _ForwardIterator>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
static void
|
||||
__uninit_default(_ForwardIterator __first, _ForwardIterator __last)
|
||||
{
|
||||
|
@ -829,6 +848,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
struct __uninitialized_default_1<true>
|
||||
{
|
||||
template<typename _ForwardIterator>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
static void
|
||||
__uninit_default(_ForwardIterator __first, _ForwardIterator __last)
|
||||
{
|
||||
|
@ -882,6 +902,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
// __uninitialized_default
|
||||
// Fills [first, last) with value-initialized value_types.
|
||||
template<typename _ForwardIterator>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
inline void
|
||||
__uninitialized_default(_ForwardIterator __first,
|
||||
_ForwardIterator __last)
|
||||
|
@ -979,6 +1000,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
struct __uninitialized_default_novalue_1
|
||||
{
|
||||
template<typename _ForwardIterator>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
static void
|
||||
__uninit_default_novalue(_ForwardIterator __first,
|
||||
_ForwardIterator __last)
|
||||
|
@ -994,6 +1016,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
struct __uninitialized_default_novalue_1<true>
|
||||
{
|
||||
template<typename _ForwardIterator>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
static void
|
||||
__uninit_default_novalue(_ForwardIterator, _ForwardIterator)
|
||||
{
|
||||
|
@ -1004,6 +1027,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
struct __uninitialized_default_novalue_n_1
|
||||
{
|
||||
template<typename _ForwardIterator, typename _Size>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
static _ForwardIterator
|
||||
__uninit_default_novalue_n(_ForwardIterator __first, _Size __n)
|
||||
{
|
||||
|
@ -1019,6 +1043,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
struct __uninitialized_default_novalue_n_1<true>
|
||||
{
|
||||
template<typename _ForwardIterator, typename _Size>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
static _ForwardIterator
|
||||
__uninit_default_novalue_n(_ForwardIterator __first, _Size __n)
|
||||
{ return std::next(__first, __n); }
|
||||
|
@ -1027,6 +1052,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
// __uninitialized_default_novalue
|
||||
// Fills [first, last) with default-initialized value_types.
|
||||
template<typename _ForwardIterator>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
inline void
|
||||
__uninitialized_default_novalue(_ForwardIterator __first,
|
||||
_ForwardIterator __last)
|
||||
|
@ -1042,6 +1068,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
// __uninitialized_default_novalue_n
|
||||
// Fills [first, first + n) with default-initialized value_types.
|
||||
template<typename _ForwardIterator, typename _Size>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
inline _ForwardIterator
|
||||
__uninitialized_default_novalue_n(_ForwardIterator __first, _Size __n)
|
||||
{
|
||||
|
@ -1055,6 +1082,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
|
||||
template<typename _InputIterator, typename _Size,
|
||||
typename _ForwardIterator>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
_ForwardIterator
|
||||
__uninitialized_copy_n(_InputIterator __first, _Size __n,
|
||||
_ForwardIterator __result, input_iterator_tag)
|
||||
|
@ -1068,6 +1096,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
|
||||
template<typename _RandomAccessIterator, typename _Size,
|
||||
typename _ForwardIterator>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
inline _ForwardIterator
|
||||
__uninitialized_copy_n(_RandomAccessIterator __first, _Size __n,
|
||||
_ForwardIterator __result,
|
||||
|
@ -1076,6 +1105,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
|
||||
template<typename _InputIterator, typename _Size,
|
||||
typename _ForwardIterator>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
pair<_InputIterator, _ForwardIterator>
|
||||
__uninitialized_copy_n_pair(_InputIterator __first, _Size __n,
|
||||
_ForwardIterator __result, input_iterator_tag)
|
||||
|
@ -1089,6 +1119,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
|
||||
template<typename _RandomAccessIterator, typename _Size,
|
||||
typename _ForwardIterator>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
inline pair<_RandomAccessIterator, _ForwardIterator>
|
||||
__uninitialized_copy_n_pair(_RandomAccessIterator __first, _Size __n,
|
||||
_ForwardIterator __result,
|
||||
|
@ -1112,6 +1143,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
* Like copy_n(), but does not require an initialized output range.
|
||||
*/
|
||||
template<typename _InputIterator, typename _Size, typename _ForwardIterator>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
inline _ForwardIterator
|
||||
uninitialized_copy_n(_InputIterator __first, _Size __n,
|
||||
_ForwardIterator __result)
|
||||
|
@ -1120,6 +1152,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
|
||||
/// @cond undocumented
|
||||
template<typename _InputIterator, typename _Size, typename _ForwardIterator>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
inline pair<_InputIterator, _ForwardIterator>
|
||||
__uninitialized_copy_n_pair(_InputIterator __first, _Size __n,
|
||||
_ForwardIterator __result)
|
||||
|
@ -1139,6 +1172,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
* @since C++17
|
||||
*/
|
||||
template <typename _ForwardIterator>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
inline void
|
||||
uninitialized_default_construct(_ForwardIterator __first,
|
||||
_ForwardIterator __last)
|
||||
|
@ -1154,6 +1188,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
* @since C++17
|
||||
*/
|
||||
template <typename _ForwardIterator, typename _Size>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
inline _ForwardIterator
|
||||
uninitialized_default_construct_n(_ForwardIterator __first, _Size __count)
|
||||
{
|
||||
|
@ -1167,6 +1202,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
* @since C++17
|
||||
*/
|
||||
template <typename _ForwardIterator>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
inline void
|
||||
uninitialized_value_construct(_ForwardIterator __first,
|
||||
_ForwardIterator __last)
|
||||
|
@ -1182,6 +1218,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
* @since C++17
|
||||
*/
|
||||
template <typename _ForwardIterator, typename _Size>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
inline _ForwardIterator
|
||||
uninitialized_value_construct_n(_ForwardIterator __first, _Size __count)
|
||||
{
|
||||
|
@ -1197,6 +1234,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
* @since C++17
|
||||
*/
|
||||
template <typename _InputIterator, typename _ForwardIterator>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
inline _ForwardIterator
|
||||
uninitialized_move(_InputIterator __first, _InputIterator __last,
|
||||
_ForwardIterator __result)
|
||||
|
@ -1215,6 +1253,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
* @since C++17
|
||||
*/
|
||||
template <typename _InputIterator, typename _Size, typename _ForwardIterator>
|
||||
_GLIBCXX26_CONSTEXPR
|
||||
inline pair<_InputIterator, _ForwardIterator>
|
||||
uninitialized_move_n(_InputIterator __first, _Size __count,
|
||||
_ForwardIterator __result)
|
||||
|
|
|
@ -521,6 +521,11 @@ ftms = {
|
|||
|
||||
ftms = {
|
||||
name = raw_memory_algorithms;
|
||||
values = {
|
||||
v = 202411;
|
||||
cxxmin = 26;
|
||||
extra_cond = "__cpp_constexpr >= 202406L";
|
||||
};
|
||||
values = {
|
||||
v = 201606;
|
||||
cxxmin = 17;
|
||||
|
|
|
@ -581,7 +581,12 @@
|
|||
#undef __glibcxx_want_gcd_lcm
|
||||
|
||||
#if !defined(__cpp_lib_raw_memory_algorithms)
|
||||
# if (__cplusplus >= 201703L)
|
||||
# if (__cplusplus > 202302L) && (__cpp_constexpr >= 202406L)
|
||||
# define __glibcxx_raw_memory_algorithms 202411L
|
||||
# if defined(__glibcxx_want_all) || defined(__glibcxx_want_raw_memory_algorithms)
|
||||
# define __cpp_lib_raw_memory_algorithms 202411L
|
||||
# endif
|
||||
# elif (__cplusplus >= 201703L)
|
||||
# define __glibcxx_raw_memory_algorithms 201606L
|
||||
# if defined(__glibcxx_want_all) || defined(__glibcxx_want_raw_memory_algorithms)
|
||||
# define __cpp_lib_raw_memory_algorithms 201606L
|
||||
|
|
|
@ -73,18 +73,30 @@ namespace std
|
|||
template <class T> T* addressof(T&) noexcept;
|
||||
#endif
|
||||
template <class InputIterator, class ForwardIterator>
|
||||
#if __cplusplus >= 202400L
|
||||
constexpr
|
||||
#endif
|
||||
ForwardIterator
|
||||
uninitialized_copy(InputIterator first, InputIterator last,
|
||||
ForwardIterator result);
|
||||
#if __cplusplus >= 201103L
|
||||
template <class InputIterator, class Size, class ForwardIterator>
|
||||
#if __cplusplus >= 202400L
|
||||
constexpr
|
||||
#endif
|
||||
ForwardIterator
|
||||
uninitialized_copy_n(InputIterator first, Size n, ForwardIterator result);
|
||||
#endif
|
||||
template <class ForwardIterator, class T>
|
||||
#if __cplusplus >= 202400L
|
||||
constexpr
|
||||
#endif
|
||||
void uninitialized_fill(ForwardIterator first, ForwardIterator last,
|
||||
const T& x);
|
||||
template <class ForwardIterator, class Size, class T>
|
||||
#if __cplusplus >= 202400L
|
||||
constexpr
|
||||
#endif
|
||||
void uninitialized_fill_n(ForwardIterator first, Size n, const T& x);
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
// { dg-do compile { target c++17 } }
|
||||
// { dg-add-options no_pch }
|
||||
|
||||
#include <memory>
|
||||
|
||||
#ifndef __cpp_lib_raw_memory_algorithms
|
||||
# error "Feature-test macro for raw memory algorithms missing"
|
||||
#elif __cplusplus > 202302L
|
||||
# if __cpp_lib_raw_memory_algorithms < 202411L
|
||||
# error "Feature-test macro for raw memory algorithms has wrong value"
|
||||
# endif
|
||||
#elif __cpp_lib_raw_memory_algorithms < 201606L
|
||||
# error "Feature-test macro for raw memory algorithms has wrong value"
|
||||
#endif
|
|
@ -0,0 +1,58 @@
|
|||
// { dg-do compile { target c++26 } }
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
template<typename T>
|
||||
constexpr
|
||||
bool
|
||||
test01_impl(std::vector<T> input)
|
||||
{
|
||||
static_assert(std::copy_constructible<T>);
|
||||
static_assert(std::equality_comparable<T>);
|
||||
|
||||
const std::size_t input_size = input.size();
|
||||
std::allocator<T> alloc;
|
||||
T* ptr = alloc.allocate(input_size);
|
||||
|
||||
std::uninitialized_copy(input.begin(), input.end(), ptr);
|
||||
if (!std::equal(input.begin(), input.end(), ptr, ptr + input_size))
|
||||
return false;
|
||||
std::destroy(ptr, ptr + input_size);
|
||||
|
||||
std::uninitialized_copy_n(input.begin(), input_size, ptr);
|
||||
if (!std::equal(input.begin(), input.end(), ptr, ptr + input_size))
|
||||
return false;
|
||||
std::destroy_n(ptr, input_size);
|
||||
|
||||
std::span<T> output(ptr, ptr + input_size);
|
||||
std::ranges::uninitialized_copy(input, output);
|
||||
if (!std::ranges::equal(input, output))
|
||||
return false;
|
||||
std::ranges::destroy(output);
|
||||
|
||||
std::ranges::uninitialized_copy_n(input.begin(), input_size, ptr, ptr + input_size);
|
||||
if (!std::ranges::equal(input.begin(), input.end(), ptr, ptr + input_size))
|
||||
return false;
|
||||
std::ranges::destroy_n(ptr, input_size);
|
||||
|
||||
alloc.deallocate(ptr, input_size);
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr
|
||||
bool
|
||||
test01()
|
||||
{
|
||||
return
|
||||
test01_impl<char>({'a', 'b', 'c'}) &&
|
||||
test01_impl<int>({1, 2, 3, 4}) &&
|
||||
test01_impl<double>({1.0, 2.0, 3.0, 4.0}) &&
|
||||
test01_impl<std::string>({"a", "b", "cc", "dddd", "eeeeeeeeeeeeeeee"}) &&
|
||||
test01_impl<std::vector<int>>({ {0}, {0, 1}, {0, 1, 2}});
|
||||
}
|
||||
|
||||
static_assert(test01());
|
|
@ -0,0 +1,67 @@
|
|||
// { dg-do compile { target c++26 } }
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
template<typename T>
|
||||
constexpr
|
||||
bool
|
||||
test01_impl()
|
||||
{
|
||||
static_assert(std::default_initializable<T>);
|
||||
static_assert(std::equality_comparable<T>);
|
||||
|
||||
constexpr std::size_t size = 42;
|
||||
std::allocator<T> alloc;
|
||||
T* ptr = alloc.allocate(size);
|
||||
|
||||
auto check = [&]() -> bool
|
||||
{
|
||||
if constexpr (!std::is_trivially_default_constructible_v<T>)
|
||||
return std::all_of(ptr, ptr + size, [](auto &&x) { return x == T(); });
|
||||
else
|
||||
return true;
|
||||
};
|
||||
|
||||
std::uninitialized_default_construct(ptr, ptr + size);
|
||||
if (!check())
|
||||
return false;
|
||||
std::destroy(ptr, ptr + size);
|
||||
|
||||
std::uninitialized_default_construct_n(ptr, size);
|
||||
if (!check())
|
||||
return false;
|
||||
std::destroy_n(ptr, size);
|
||||
|
||||
std::span<T> storage(ptr, ptr + size);
|
||||
std::ranges::uninitialized_default_construct(storage);
|
||||
if (!check())
|
||||
return false;
|
||||
std::ranges::destroy(storage);
|
||||
|
||||
std::ranges::uninitialized_default_construct_n(ptr, size);
|
||||
if (!check())
|
||||
return false;
|
||||
std::ranges::destroy_n(ptr, size);
|
||||
|
||||
alloc.deallocate(ptr, size);
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr
|
||||
bool
|
||||
test01()
|
||||
{
|
||||
return
|
||||
test01_impl<char>() &&
|
||||
test01_impl<int>() &&
|
||||
test01_impl<double>() &&
|
||||
test01_impl<std::string>() &&
|
||||
test01_impl<std::vector<int>>() &&
|
||||
test01_impl<std::unique_ptr<int>>();
|
||||
}
|
||||
|
||||
static_assert(test01());
|
|
@ -0,0 +1,68 @@
|
|||
// { dg-do compile { target c++26 } }
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
template<typename T, typename U = T>
|
||||
constexpr
|
||||
bool
|
||||
test01_impl(const U& value = U())
|
||||
{
|
||||
static_assert(std::constructible_from<T, U>);
|
||||
//static_assert(std::equality_comparable_with<T, U>); // unique_ptr fails with nullptr_t
|
||||
|
||||
constexpr std::size_t size = 42;
|
||||
std::allocator<T> alloc;
|
||||
T* ptr = alloc.allocate(size);
|
||||
|
||||
auto check = [&]() -> bool
|
||||
{
|
||||
return std::all_of(ptr, ptr + size, [&](auto &&x) { return x == value; });
|
||||
};
|
||||
|
||||
std::uninitialized_fill(ptr, ptr + size, value);
|
||||
if (!check())
|
||||
return false;
|
||||
std::destroy(ptr, ptr + size);
|
||||
|
||||
std::uninitialized_fill_n(ptr, size, value);
|
||||
if (!check())
|
||||
return false;
|
||||
std::destroy_n(ptr, size);
|
||||
|
||||
std::span<T> storage(ptr, ptr + size);
|
||||
std::ranges::uninitialized_fill(storage, value);
|
||||
if (!check())
|
||||
return false;
|
||||
std::ranges::destroy(storage);
|
||||
|
||||
std::ranges::uninitialized_fill_n(ptr, size, value);
|
||||
if (!check())
|
||||
return false;
|
||||
std::ranges::destroy_n(ptr, size);
|
||||
|
||||
alloc.deallocate(ptr, size);
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr
|
||||
bool
|
||||
test01()
|
||||
{
|
||||
return
|
||||
test01_impl<char>('\0') &&
|
||||
test01_impl<char>('x') &&
|
||||
test01_impl<int>(0) &&
|
||||
test01_impl<int>(42) &&
|
||||
test01_impl<double>(3.14) &&
|
||||
test01_impl<std::string>() &&
|
||||
test01_impl<std::string>(std::string("test")) &&
|
||||
test01_impl<std::vector<int>>() &&
|
||||
test01_impl<std::vector<int>>({1, 2, 3, 4}) &&
|
||||
test01_impl<std::unique_ptr<int>>(nullptr);
|
||||
}
|
||||
|
||||
static_assert(test01());
|
|
@ -0,0 +1,51 @@
|
|||
// { dg-do compile { target c++26 } }
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
template<typename T>
|
||||
constexpr
|
||||
bool
|
||||
test01_impl(std::vector<T> input)
|
||||
{
|
||||
static_assert(std::move_constructible<T>);
|
||||
static_assert(std::equality_comparable<T>);
|
||||
|
||||
const std::size_t input_size = input.size();
|
||||
std::allocator<T> alloc;
|
||||
T* ptr = alloc.allocate(input_size);
|
||||
|
||||
std::uninitialized_move(input.begin(), input.end(), ptr);
|
||||
std::destroy(ptr, ptr + input_size);
|
||||
|
||||
std::uninitialized_move_n(input.begin(), input_size, ptr);
|
||||
std::destroy_n(ptr, input_size);
|
||||
|
||||
std::span<T> output(ptr, ptr + input_size);
|
||||
std::ranges::uninitialized_move(input, output);
|
||||
std::ranges::destroy(output);
|
||||
|
||||
std::ranges::uninitialized_move_n(input.begin(), input_size, ptr, ptr + input_size);
|
||||
std::ranges::destroy_n(ptr, input_size);
|
||||
|
||||
alloc.deallocate(ptr, input_size);
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr
|
||||
bool
|
||||
test01()
|
||||
{
|
||||
return
|
||||
test01_impl<char>({'a', 'b', 'c'}) &&
|
||||
test01_impl<int>({1, 2, 3, 4}) &&
|
||||
test01_impl<double>({1.0, 2.0, 3.0, 4.0}) &&
|
||||
test01_impl<std::string>({"a", "b", "cc", "dddd", "eeeeeeeeeeeeeeee"}) &&
|
||||
test01_impl<std::vector<int>>({ {0}, {0, 1}, {0, 1, 2}}) &&
|
||||
test01_impl<std::unique_ptr<int>>(std::vector<std::unique_ptr<int>>(10));
|
||||
}
|
||||
|
||||
static_assert(test01());
|
|
@ -0,0 +1,64 @@
|
|||
// { dg-do compile { target c++26 } }
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
template<typename T>
|
||||
constexpr
|
||||
bool
|
||||
test01_impl()
|
||||
{
|
||||
static_assert(std::default_initializable<T>);
|
||||
static_assert(std::equality_comparable<T>);
|
||||
|
||||
constexpr std::size_t size = 42;
|
||||
std::allocator<T> alloc;
|
||||
T* ptr = alloc.allocate(size);
|
||||
|
||||
auto check = [&]() -> bool
|
||||
{
|
||||
return std::all_of(ptr, ptr + size, [](auto &&x) { return x == T(); });
|
||||
};
|
||||
|
||||
std::uninitialized_value_construct(ptr, ptr + size);
|
||||
if (!check())
|
||||
return false;
|
||||
std::destroy(ptr, ptr + size);
|
||||
|
||||
std::uninitialized_value_construct_n(ptr, size);
|
||||
if (!check())
|
||||
return false;
|
||||
std::destroy_n(ptr, size);
|
||||
|
||||
std::span<T> storage(ptr, ptr + size);
|
||||
std::ranges::uninitialized_value_construct(storage);
|
||||
if (!check())
|
||||
return false;
|
||||
std::ranges::destroy(storage);
|
||||
|
||||
std::ranges::uninitialized_value_construct_n(ptr, size);
|
||||
if (!check())
|
||||
return false;
|
||||
std::ranges::destroy_n(ptr, size);
|
||||
|
||||
alloc.deallocate(ptr, size);
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr
|
||||
bool
|
||||
test01()
|
||||
{
|
||||
return
|
||||
test01_impl<char>() &&
|
||||
test01_impl<int>() &&
|
||||
test01_impl<double>() &&
|
||||
test01_impl<std::string>() &&
|
||||
test01_impl<std::vector<int>>() &&
|
||||
test01_impl<std::unique_ptr<int>>();
|
||||
}
|
||||
|
||||
static_assert(test01());
|
Loading…
Add table
Reference in a new issue