Hello,the attached patch implements the C++26 papers that add `constexpr` to the specialized memory algorithms (the uninitialized_* family). Tested on x86-64 Linux.
Thank you, -- Giuseppe D'Angelo
From 8a4224674bf267c80924a9f69c634f050c3ad590 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo <giuseppe.dang...@kdab.com> Date: Sun, 16 Feb 2025 19:37:07 +0100 Subject: [PATCH] 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. I've introduced a helper macro to conditionally expand to `constexpr` only in C++26 and above modes. The internal helper guard class for range algorithms instead can be marked unconditionally. uninitialized_fill is the only algorithm where I had to add a branch to a constexpr-friendly version (already existing). 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: Mark _Construct_novalue (which uses placement new to do default initialization) as constexpr in C++26. This is possible due to P2747R2, which GCC already implements; check P2747's feature-testing macro to avoid issues with other compilers. * include/bits/version.def: Bump the feature-testing macro. * include/bits/version.h: Regenerate. * 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. Signed-off-by: Giuseppe D'Angelo <giuseppe.dang...@kdab.com> --- .../include/bits/ranges_uninitialized.h | 29 ++++++++ libstdc++-v3/include/bits/stl_construct.h | 3 + libstdc++-v3/include/bits/stl_uninitialized.h | 42 ++++++++++++ libstdc++-v3/include/bits/version.def | 5 ++ libstdc++-v3/include/bits/version.h | 7 +- .../feature_test_macro.cc | 14 ++++ .../uninitialized_copy/constexpr.cc | 58 ++++++++++++++++ .../constexpr.cc | 67 ++++++++++++++++++ .../uninitialized_fill/constexpr.cc | 68 +++++++++++++++++++ .../uninitialized_move/constexpr.cc | 51 ++++++++++++++ .../constexpr.cc | 64 +++++++++++++++++ 11 files changed, 407 insertions(+), 1 deletion(-) create mode 100644 libstdc++-v3/testsuite/20_util/specialized_algorithms/feature_test_macro.cc create mode 100644 libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/constexpr.cc create mode 100644 libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_default_construct/constexpr.cc create mode 100644 libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/constexpr.cc create mode 100644 libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/constexpr.cc create mode 100644 libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_value_construct/constexpr.cc diff --git a/libstdc++-v3/include/bits/ranges_uninitialized.h b/libstdc++-v3/include/bits/ranges_uninitialized.h index ced7bda5e37..337d321702d 100644 --- a/libstdc++-v3/include/bits/ranges_uninitialized.h +++ b/libstdc++-v3/include/bits/ranges_uninitialized.h @@ -35,6 +35,12 @@ #include <bits/ranges_algobase.h> +#if __glibcxx_raw_memory_algorithms >= 202411L // >= C++26 +# define _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS constexpr +#else +# define _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS +#endif + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -105,15 +111,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 +135,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 +152,7 @@ namespace ranges template<__detail::__nothrow_forward_iterator _Iter, __detail::__nothrow_sentinel<_Iter> _Sent> requires default_initializable<iter_value_t<_Iter>> + _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS _Iter operator()(_Iter __first, _Sent __last) const { @@ -159,6 +171,7 @@ namespace ranges template<__detail::__nothrow_forward_range _Range> requires default_initializable<range_value_t<_Range>> + _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS borrowed_iterator_t<_Range> operator()(_Range&& __r) const { @@ -173,6 +186,7 @@ namespace ranges { template<__detail::__nothrow_forward_iterator _Iter> requires default_initializable<iter_value_t<_Iter>> + _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS _Iter operator()(_Iter __first, iter_difference_t<_Iter> __n) const { @@ -198,6 +212,7 @@ namespace ranges template<__detail::__nothrow_forward_iterator _Iter, __detail::__nothrow_sentinel<_Iter> _Sent> requires default_initializable<iter_value_t<_Iter>> + _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS _Iter operator()(_Iter __first, _Sent __last) const { @@ -217,6 +232,7 @@ namespace ranges template<__detail::__nothrow_forward_range _Range> requires default_initializable<range_value_t<_Range>> + _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS borrowed_iterator_t<_Range> operator()(_Range&& __r) const { @@ -231,6 +247,7 @@ namespace ranges { template<__detail::__nothrow_forward_iterator _Iter> requires default_initializable<iter_value_t<_Iter>> + _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS _Iter operator()(_Iter __first, iter_difference_t<_Iter> __n) const { @@ -261,6 +278,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_RAW_MEMORY_ALGORITHMS uninitialized_copy_result<_Iter, _Out> operator()(_Iter __ifirst, _ISent __ilast, _Out __ofirst, _OSent __olast) const @@ -292,6 +310,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_RAW_MEMORY_ALGORITHMS uninitialized_copy_result<borrowed_iterator_t<_IRange>, borrowed_iterator_t<_ORange>> operator()(_IRange&& __inr, _ORange&& __outr) const @@ -311,6 +330,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_RAW_MEMORY_ALGORITHMS uninitialized_copy_n_result<_Iter, _Out> operator()(_Iter __ifirst, iter_difference_t<_Iter> __n, _Out __ofirst, _Sent __olast) const @@ -350,6 +370,7 @@ namespace ranges __detail::__nothrow_sentinel<_Out> _OSent> requires constructible_from<iter_value_t<_Out>, iter_rvalue_reference_t<_Iter>> + _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS uninitialized_move_result<_Iter, _Out> operator()(_Iter __ifirst, _ISent __ilast, _Out __ofirst, _OSent __olast) const @@ -384,6 +405,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_RAW_MEMORY_ALGORITHMS uninitialized_move_result<borrowed_iterator_t<_IRange>, borrowed_iterator_t<_ORange>> operator()(_IRange&& __inr, _ORange&& __outr) const @@ -404,6 +426,7 @@ namespace ranges __detail::__nothrow_sentinel<_Out> _Sent> requires constructible_from<iter_value_t<_Out>, iter_rvalue_reference_t<_Iter>> + _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS uninitialized_move_n_result<_Iter, _Out> operator()(_Iter __ifirst, iter_difference_t<_Iter> __n, _Out __ofirst, _Sent __olast) const @@ -441,6 +464,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_RAW_MEMORY_ALGORITHMS _Iter operator()(_Iter __first, _Sent __last, const _Tp& __x) const { @@ -460,6 +484,7 @@ namespace ranges template<__detail::__nothrow_forward_range _Range, typename _Tp> requires constructible_from<range_value_t<_Range>, const _Tp&> + _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS borrowed_iterator_t<_Range> operator()(_Range&& __r, const _Tp& __x) const { @@ -473,6 +498,7 @@ namespace ranges { template<__detail::__nothrow_forward_iterator _Iter, typename _Tp> requires constructible_from<iter_value_t<_Iter>, const _Tp&> + _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS _Iter operator()(_Iter __first, iter_difference_t<_Iter> __n, const _Tp& __x) const @@ -573,6 +599,9 @@ namespace ranges } _GLIBCXX_END_NAMESPACE_VERSION } // namespace std + +#undef _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS + #endif // concepts #endif // C++20 #endif // _RANGES_UNINITIALIZED_H diff --git a/libstdc++-v3/include/bits/stl_construct.h b/libstdc++-v3/include/bits/stl_construct.h index bd8235e901b..6d34edf02da 100644 --- a/libstdc++-v3/include/bits/stl_construct.h +++ b/libstdc++-v3/include/bits/stl_construct.h @@ -144,6 +144,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif template<typename _T1> +#if __cpp_constexpr >= 202406L // >= C++26 + _GLIBCXX26_CONSTEXPR +#endif inline void _Construct_novalue(_T1* __p) { ::new(static_cast<void*>(__p)) _T1; } diff --git a/libstdc++-v3/include/bits/stl_uninitialized.h b/libstdc++-v3/include/bits/stl_uninitialized.h index ed836663a44..04f9792d37e 100644 --- a/libstdc++-v3/include/bits/stl_uninitialized.h +++ b/libstdc++-v3/include/bits/stl_uninitialized.h @@ -68,6 +68,12 @@ #include <bits/stl_iterator.h> // __niter_base #include <ext/alloc_traits.h> // __alloc_traits +#if __glibcxx_raw_memory_algorithms >= 202411L // >= C++26 +# define _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS constexpr +#else +# define _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS +#endif + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -226,6 +232,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * Like std::copy, but does not require an initialized output range. */ template<typename _InputIterator, typename _ForwardIterator> + _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS inline _ForwardIterator uninitialized_copy(_InputIterator __first, _InputIterator __last, _ForwardIterator __result) @@ -256,6 +263,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using _Src = decltype(std::__niter_base(__first)); using _ValT = typename iterator_traits<_ForwardIterator>::value_type; + + if (__is_constant_evaluated()) + return std::__do_uninit_copy(__first, __last, __result); 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 +391,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * Like std::fill, but does not require an initialized output range. */ template<typename _ForwardIterator, typename _Tp> + _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS inline void uninitialized_fill(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __x) @@ -400,6 +411,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #if __cplusplus >= 201103L #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wc++17-extensions" + if (__is_constant_evaluated()) + { + std::__do_uninit_fill(__first, __last, __x); + return; + } if constexpr (__is_byte<_ValueType>::__value) if constexpr (is_same<_ValueType, _Tp>::value || is_integral<_Tp>::value) @@ -509,6 +525,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_RAW_MEMORY_ALGORITHMS inline _ForwardIterator uninitialized_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x) { @@ -522,6 +539,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _ValueType; #if __cplusplus >= 201103L + if (__is_constant_evaluated()) + return std::__do_uninit_fill_n(__first, __n, __x); if constexpr (__is_byte<_ValueType>::__value) if constexpr (is_integral<_Tp>::value) if constexpr (is_integral<_Size>::value) @@ -815,6 +834,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __uninitialized_default_1 { template<typename _ForwardIterator> + _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS static void __uninit_default(_ForwardIterator __first, _ForwardIterator __last) { @@ -829,6 +849,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __uninitialized_default_1<true> { template<typename _ForwardIterator> + _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS static void __uninit_default(_ForwardIterator __first, _ForwardIterator __last) { @@ -882,6 +903,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // __uninitialized_default // Fills [first, last) with value-initialized value_types. template<typename _ForwardIterator> + _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS inline void __uninitialized_default(_ForwardIterator __first, _ForwardIterator __last) @@ -979,6 +1001,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __uninitialized_default_novalue_1 { template<typename _ForwardIterator> + _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS static void __uninit_default_novalue(_ForwardIterator __first, _ForwardIterator __last) @@ -994,6 +1017,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __uninitialized_default_novalue_1<true> { template<typename _ForwardIterator> + _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS static void __uninit_default_novalue(_ForwardIterator, _ForwardIterator) { @@ -1004,6 +1028,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __uninitialized_default_novalue_n_1 { template<typename _ForwardIterator, typename _Size> + _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS static _ForwardIterator __uninit_default_novalue_n(_ForwardIterator __first, _Size __n) { @@ -1019,6 +1044,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __uninitialized_default_novalue_n_1<true> { template<typename _ForwardIterator, typename _Size> + _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS static _ForwardIterator __uninit_default_novalue_n(_ForwardIterator __first, _Size __n) { return std::next(__first, __n); } @@ -1027,6 +1053,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // __uninitialized_default_novalue // Fills [first, last) with default-initialized value_types. template<typename _ForwardIterator> + _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS inline void __uninitialized_default_novalue(_ForwardIterator __first, _ForwardIterator __last) @@ -1042,6 +1069,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_RAW_MEMORY_ALGORITHMS inline _ForwardIterator __uninitialized_default_novalue_n(_ForwardIterator __first, _Size __n) { @@ -1055,6 +1083,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _InputIterator, typename _Size, typename _ForwardIterator> + _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS _ForwardIterator __uninitialized_copy_n(_InputIterator __first, _Size __n, _ForwardIterator __result, input_iterator_tag) @@ -1068,6 +1097,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _RandomAccessIterator, typename _Size, typename _ForwardIterator> + _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS inline _ForwardIterator __uninitialized_copy_n(_RandomAccessIterator __first, _Size __n, _ForwardIterator __result, @@ -1076,6 +1106,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _InputIterator, typename _Size, typename _ForwardIterator> + _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS pair<_InputIterator, _ForwardIterator> __uninitialized_copy_n_pair(_InputIterator __first, _Size __n, _ForwardIterator __result, input_iterator_tag) @@ -1089,6 +1120,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _RandomAccessIterator, typename _Size, typename _ForwardIterator> + _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS inline pair<_RandomAccessIterator, _ForwardIterator> __uninitialized_copy_n_pair(_RandomAccessIterator __first, _Size __n, _ForwardIterator __result, @@ -1112,6 +1144,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_RAW_MEMORY_ALGORITHMS inline _ForwardIterator uninitialized_copy_n(_InputIterator __first, _Size __n, _ForwardIterator __result) @@ -1120,6 +1153,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// @cond undocumented template<typename _InputIterator, typename _Size, typename _ForwardIterator> + _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS inline pair<_InputIterator, _ForwardIterator> __uninitialized_copy_n_pair(_InputIterator __first, _Size __n, _ForwardIterator __result) @@ -1139,6 +1173,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @since C++17 */ template <typename _ForwardIterator> + _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS inline void uninitialized_default_construct(_ForwardIterator __first, _ForwardIterator __last) @@ -1154,6 +1189,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @since C++17 */ template <typename _ForwardIterator, typename _Size> + _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS inline _ForwardIterator uninitialized_default_construct_n(_ForwardIterator __first, _Size __count) { @@ -1167,6 +1203,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @since C++17 */ template <typename _ForwardIterator> + _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS inline void uninitialized_value_construct(_ForwardIterator __first, _ForwardIterator __last) @@ -1182,6 +1219,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @since C++17 */ template <typename _ForwardIterator, typename _Size> + _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS inline _ForwardIterator uninitialized_value_construct_n(_ForwardIterator __first, _Size __count) { @@ -1197,6 +1235,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @since C++17 */ template <typename _InputIterator, typename _ForwardIterator> + _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS inline _ForwardIterator uninitialized_move(_InputIterator __first, _InputIterator __last, _ForwardIterator __result) @@ -1215,6 +1254,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @since C++17 */ template <typename _InputIterator, typename _Size, typename _ForwardIterator> + _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS inline pair<_InputIterator, _ForwardIterator> uninitialized_move_n(_InputIterator __first, _Size __count, _ForwardIterator __result) @@ -1324,4 +1364,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_END_NAMESPACE_VERSION } // namespace +#undef _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS + #endif /* _STL_UNINITIALIZED_H */ diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def index 56843f817e8..7d10c0c4807 100644 --- a/libstdc++-v3/include/bits/version.def +++ b/libstdc++-v3/include/bits/version.def @@ -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; diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h index 8db03dd33b2..e6a306c8ad8 100644 --- a/libstdc++-v3/include/bits/version.h +++ b/libstdc++-v3/include/bits/version.h @@ -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 diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/feature_test_macro.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/feature_test_macro.cc new file mode 100644 index 00000000000..0252753aa66 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/feature_test_macro.cc @@ -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 diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/constexpr.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/constexpr.cc new file mode 100644 index 00000000000..6f05b0ce309 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/constexpr.cc @@ -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()); diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_default_construct/constexpr.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_default_construct/constexpr.cc new file mode 100644 index 00000000000..db39c8b4d05 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_default_construct/constexpr.cc @@ -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()); diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/constexpr.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/constexpr.cc new file mode 100644 index 00000000000..e43cd35a92d --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/constexpr.cc @@ -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()); diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/constexpr.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/constexpr.cc new file mode 100644 index 00000000000..47403ae706d --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/constexpr.cc @@ -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()); diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_value_construct/constexpr.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_value_construct/constexpr.cc new file mode 100644 index 00000000000..55dfc59b5ef --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_value_construct/constexpr.cc @@ -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()); -- 2.34.1
smime.p7s
Description: S/MIME Cryptographic Signature