From 4f4a8401c0df7f178412b1e5868b53a6704c0686 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Sat, 27 Feb 2021 13:03:37 +0100 Subject: [PATCH] [P2283R1] Implement constexpr specialized memory algorithms --- stl/inc/memory | 358 +++++++++++------- stl/inc/xmemory | 87 +++-- stl/inc/yvals_core.h | 26 +- tests/std/test.lst | 8 + .../env.lst | 4 + .../test.cpp | 241 ++++++++++++ .../env.lst | 4 + .../test.cpp | 206 ++++++++++ .../env.lst | 4 + .../test.cpp | 112 ++++++ .../env.lst | 4 + .../test.cpp | 105 +++++ .../env.lst | 4 + .../test.cpp | 246 ++++++++++++ .../env.lst | 4 + .../test.cpp | 212 +++++++++++ .../env.lst | 4 + .../test.cpp | 111 ++++++ .../env.lst | 4 + .../test.cpp | 104 +++++ .../test.compile.pass.cpp | 10 +- 21 files changed, 1677 insertions(+), 181 deletions(-) create mode 100644 tests/std/tests/P2283R2_constexpr_uninitialized_copy/env.lst create mode 100644 tests/std/tests/P2283R2_constexpr_uninitialized_copy/test.cpp create mode 100644 tests/std/tests/P2283R2_constexpr_uninitialized_copy_n/env.lst create mode 100644 tests/std/tests/P2283R2_constexpr_uninitialized_copy_n/test.cpp create mode 100644 tests/std/tests/P2283R2_constexpr_uninitialized_fill/env.lst create mode 100644 tests/std/tests/P2283R2_constexpr_uninitialized_fill/test.cpp create mode 100644 tests/std/tests/P2283R2_constexpr_uninitialized_fill_n/env.lst create mode 100644 tests/std/tests/P2283R2_constexpr_uninitialized_fill_n/test.cpp create mode 100644 tests/std/tests/P2283R2_constexpr_uninitialized_move/env.lst create mode 100644 tests/std/tests/P2283R2_constexpr_uninitialized_move/test.cpp create mode 100644 tests/std/tests/P2283R2_constexpr_uninitialized_move_n/env.lst create mode 100644 tests/std/tests/P2283R2_constexpr_uninitialized_move_n/test.cpp create mode 100644 tests/std/tests/P2283R2_constexpr_uninitialized_value_construct/env.lst create mode 100644 tests/std/tests/P2283R2_constexpr_uninitialized_value_construct/test.cpp create mode 100644 tests/std/tests/P2283R2_constexpr_uninitialized_value_construct_n/env.lst create mode 100644 tests/std/tests/P2283R2_constexpr_uninitialized_value_construct_n/test.cpp diff --git a/stl/inc/memory b/stl/inc/memory index 8de1c1561f2..e745303eaa0 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -39,7 +39,8 @@ namespace ranges { template _Se, _No_throw_forward_iterator _Out, _No_throw_sentinel_for<_Out> _OSe> requires constructible_from, iter_reference_t<_It>> - uninitialized_copy_result<_It, _Out> operator()(_It _First1, _Se _Last1, _Out _First2, _OSe _Last2) const { + _CONSTEXPR23 uninitialized_copy_result<_It, _Out> operator()( + _It _First1, _Se _Last1, _Out _First2, _OSe _Last2) const { // clang-format on _Adl_verify_range(_First1, _Last1); _Adl_verify_range(_First2, _Last2); @@ -55,8 +56,8 @@ namespace ranges { // clang-format off template requires constructible_from, range_reference_t<_Rng1>> - uninitialized_copy_result, borrowed_iterator_t<_Rng2>> operator()( - _Rng1&& _Range1, _Rng2&& _Range2) const { + _CONSTEXPR23 uninitialized_copy_result, borrowed_iterator_t<_Rng2>> + operator()(_Rng1&& _Range1, _Rng2&& _Range2) const { // clang-format on auto _First1 = _RANGES begin(_Range1); auto _UResult = _Uninitialized_copy_unchecked( @@ -68,7 +69,7 @@ namespace ranges { private: template - _NODISCARD static uninitialized_copy_result<_It, _Out> _Uninitialized_copy_unchecked( + _NODISCARD static _CONSTEXPR23 uninitialized_copy_result<_It, _Out> _Uninitialized_copy_unchecked( _It _IFirst, _Se _ILast, _Out _OFirst, _OSe _OLast) { _STL_INTERNAL_STATIC_ASSERT(input_iterator<_It>); _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>); @@ -81,25 +82,32 @@ namespace ranges { if constexpr (_Iter_copy_cat<_It, _Out>::_Bitcopy_constructible && _Sized_or_unreachable_sentinel_for<_Se, _It> // && _Sized_or_unreachable_sentinel_for<_OSe, _Out>) { - if constexpr (_Is_sized1 && _Is_sized2) { - return _Copy_memcpy_common(_IFirst, _RANGES next(_IFirst, _STD move(_ILast)), _OFirst, - _RANGES next(_OFirst, _STD move(_OLast))); - } else if constexpr (_Is_sized1) { - return _Copy_memcpy_distance(_IFirst, _OFirst, _IFirst, _RANGES next(_IFirst, _STD move(_ILast))); - } else if constexpr (_Is_sized2) { - return _Copy_memcpy_distance(_IFirst, _OFirst, _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); - } else { - _STL_ASSERT(false, "Tried to uninitialized_copy two ranges with unreachable sentinels"); +#if _HAS_CXX23 + if (!_STD is_constant_evaluated()) +#endif // _HAS_CXX23 + { + if constexpr (_Is_sized1 && _Is_sized2) { + return _Copy_memcpy_common(_IFirst, _RANGES next(_IFirst, _STD move(_ILast)), _OFirst, + _RANGES next(_OFirst, _STD move(_OLast))); + } else if constexpr (_Is_sized1) { + return _Copy_memcpy_distance( + _IFirst, _OFirst, _IFirst, _RANGES next(_IFirst, _STD move(_ILast))); + } else if constexpr (_Is_sized2) { + return _Copy_memcpy_distance( + _IFirst, _OFirst, _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); + } else { + _STL_ASSERT(false, "Tried to uninitialized_copy two ranges with unreachable sentinels"); + } } - } else { - _Uninitialized_backout _Backout{_STD move(_OFirst)}; + } - for (; _IFirst != _ILast && _Backout._Last != _OLast; ++_IFirst) { - _Backout._Emplace_back(*_IFirst); - } + _Uninitialized_backout _Backout{_STD move(_OFirst)}; - return {_STD move(_IFirst), _Backout._Release()}; + for (; _IFirst != _ILast && _Backout._Last != _OLast; ++_IFirst) { + _Backout._Emplace_back(*_IFirst); } + + return {_STD move(_IFirst), _Backout._Release()}; } }; @@ -108,7 +116,7 @@ namespace ranges { #endif // __cpp_lib_concepts template -_NoThrowFwdIt uninitialized_copy_n(const _InIt _First, const _Diff _Count_raw, _NoThrowFwdIt _Dest) { +_CONSTEXPR23 _NoThrowFwdIt uninitialized_copy_n(const _InIt _First, const _Diff _Count_raw, _NoThrowFwdIt _Dest) { // copy [_First, _First + _Count) to [_Dest, ...) _Algorithm_int_t<_Diff> _Count = _Count_raw; if (_Count <= 0) { @@ -118,18 +126,22 @@ _NoThrowFwdIt uninitialized_copy_n(const _InIt _First, const _Diff _Count_raw, _ auto _UFirst = _Get_unwrapped_n(_First, _Count); auto _UDest = _Get_unwrapped_n(_Dest, _Count); if constexpr (_Iter_copy_cat::_Bitcopy_constructible) { - _UDest = _Copy_memmove(_UFirst, _UFirst + _Count, _UDest); - } else { - _Uninitialized_backout _Backout{_UDest}; - - for (; _Count > 0; --_Count, (void) ++_UFirst) { - _Backout._Emplace_back(*_UFirst); +#if _HAS_CXX23 + if (!_STD is_constant_evaluated()) +#endif // _HAS_CXX23 + { + _Seek_wrapped(_Dest, _Copy_memmove(_UFirst, _UFirst + _Count, _UDest)); + return _Dest; } + } + + _Uninitialized_backout _Backout{_UDest}; - _UDest = _Backout._Release(); + for (; _Count > 0; --_Count, (void) ++_UFirst) { + _Backout._Emplace_back(*_UFirst); } - _Seek_wrapped(_Dest, _UDest); + _Seek_wrapped(_Dest, _Backout._Release()); return _Dest; } @@ -145,7 +157,7 @@ namespace ranges { // clang-format off template _OSe> requires constructible_from, iter_reference_t<_It>> - uninitialized_copy_n_result<_It, _Out> operator()( + _CONSTEXPR23 uninitialized_copy_n_result<_It, _Out> operator()( _It _First1, iter_difference_t<_It> _Count, _Out _First2, _OSe _Last2) const { // clang-format on if (_Count <= 0) { @@ -158,28 +170,35 @@ namespace ranges { auto _OLast = _Get_unwrapped(_STD move(_Last2)); if constexpr (_Iter_copy_cat<_It, _Out>::_Bitcopy_constructible && _Sized_or_unreachable_sentinel_for<_OSe, _Out>) { - if constexpr (sized_sentinel_for<_OSe, _Out>) { - auto _UResult = _Copy_memcpy_common( - _IFirst, _IFirst + _Count, _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); - _IFirst = _STD move(_UResult.in); - _OFirst = _STD move(_UResult.out); - } else { - auto _UResult = _Copy_memcpy_count(_IFirst, _OFirst, static_cast(_Count)); - _IFirst = _STD move(_UResult.in); - _OFirst = _STD move(_UResult.out); - } - } else { - _Uninitialized_backout _Backout{_STD move(_OFirst)}; +#if _HAS_CXX23 + if (!_STD is_constant_evaluated()) +#endif // _HAS_CXX23 + { + if constexpr (sized_sentinel_for<_OSe, _Out>) { + auto _UResult = _Copy_memcpy_common( + _IFirst, _IFirst + _Count, _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); + _IFirst = _STD move(_UResult.in); + _OFirst = _STD move(_UResult.out); + } else { + auto _UResult = _Copy_memcpy_count(_IFirst, _OFirst, static_cast(_Count)); + _IFirst = _STD move(_UResult.in); + _OFirst = _STD move(_UResult.out); + } - for (; _Count > 0 && _OFirst != _OLast; --_Count, (void) ++_IFirst) { - _Backout._Emplace_back(*_IFirst); + _Seek_wrapped(_First1, _IFirst); + _Seek_wrapped(_First2, _OFirst); + return {_STD move(_First1), _STD move(_First2)}; } + } + + _Uninitialized_backout _Backout{_STD move(_OFirst)}; - _OFirst = _Backout._Release(); + for (; _Count > 0 && _OFirst != _OLast; --_Count, (void) ++_IFirst) { + _Backout._Emplace_back(*_IFirst); } _Seek_wrapped(_First1, _IFirst); - _Seek_wrapped(_First2, _OFirst); + _Seek_wrapped(_First2, _Backout._Release()); return {_STD move(_First1), _STD move(_First2)}; } }; @@ -190,7 +209,7 @@ namespace ranges { #if _HAS_CXX17 template -_NoThrowFwdIt uninitialized_move(const _InIt _First, const _InIt _Last, _NoThrowFwdIt _Dest) { +_CONSTEXPR23 _NoThrowFwdIt uninitialized_move(const _InIt _First, const _InIt _Last, _NoThrowFwdIt _Dest) { // move [_First, _Last) to raw [_Dest, ...) _Adl_verify_range(_First, _Last); const auto _UFirst = _Get_unwrapped(_First); @@ -210,7 +229,8 @@ namespace ranges { template _Se, _No_throw_forward_iterator _Out, _No_throw_sentinel_for<_Out> _OSe> requires constructible_from, iter_rvalue_reference_t<_It>> - uninitialized_move_result<_It, _Out> operator()(_It _First1, _Se _Last1, _Out _First2, _OSe _Last2) const { + _CONSTEXPR23 uninitialized_move_result<_It, _Out> operator()( + _It _First1, _Se _Last1, _Out _First2, _OSe _Last2) const { // clang-format on _Adl_verify_range(_First1, _Last1); _Adl_verify_range(_First2, _Last2); @@ -226,8 +246,8 @@ namespace ranges { // clang-format off template requires constructible_from, range_rvalue_reference_t<_Rng1>> - uninitialized_move_result, borrowed_iterator_t<_Rng2>> operator()( - _Rng1&& _Range1, _Rng2&& _Range2) const { + _CONSTEXPR23 uninitialized_move_result, borrowed_iterator_t<_Rng2>> + operator()(_Rng1&& _Range1, _Rng2&& _Range2) const { // clang-format on auto _First1 = _RANGES begin(_Range1); auto _UResult = _RANGES _Uninitialized_move_unchecked( @@ -243,7 +263,8 @@ namespace ranges { #endif // __cpp_lib_concepts template -pair<_InIt, _NoThrowFwdIt> uninitialized_move_n(_InIt _First, const _Diff _Count_raw, _NoThrowFwdIt _Dest) { +_CONSTEXPR23 pair<_InIt, _NoThrowFwdIt> uninitialized_move_n( + _InIt _First, const _Diff _Count_raw, _NoThrowFwdIt _Dest) { // move [_First, _First + _Count) to [_Dest, ...) _Algorithm_int_t<_Diff> _Count = _Count_raw; if (_Count <= 0) { @@ -253,20 +274,26 @@ pair<_InIt, _NoThrowFwdIt> uninitialized_move_n(_InIt _First, const _Diff _Count auto _UFirst = _Get_unwrapped_n(_First, _Count); auto _UDest = _Get_unwrapped_n(_Dest, _Count); if constexpr (_Iter_move_cat::_Bitcopy_constructible) { - _UDest = _Copy_memmove(_UFirst, _UFirst + _Count, _UDest); - _UFirst += _Count; - } else { - _Uninitialized_backout _Backout{_UDest}; - - for (; _Count > 0; --_Count, (void) ++_UFirst) { - _Backout._Emplace_back(_STD move(*_UFirst)); +#if _HAS_CXX23 + if (!_STD is_constant_evaluated()) +#endif // _HAS_CXX23 + { + _UDest = _Copy_memmove(_UFirst, _UFirst + _Count, _UDest); + _UFirst += _Count; + _Seek_wrapped(_Dest, _UDest); + _Seek_wrapped(_First, _UFirst); + return {_First, _Dest}; } + } - _UDest = _Backout._Release(); + _Uninitialized_backout _Backout{_UDest}; + + for (; _Count > 0; --_Count, (void) ++_UFirst) { + _Backout._Emplace_back(_STD move(*_UFirst)); } - _Seek_wrapped(_Dest, _UDest); _Seek_wrapped(_First, _UFirst); + _Seek_wrapped(_Dest, _Backout._Release()); return {_First, _Dest}; } #endif // _HAS_CXX17 @@ -284,7 +311,7 @@ namespace ranges { // clang-format off template _OSe> requires constructible_from, iter_rvalue_reference_t<_It>> - uninitialized_move_n_result<_It, _Out> operator()( + _CONSTEXPR23 uninitialized_move_n_result<_It, _Out> operator()( _It _First1, iter_difference_t<_It> _Count, _Out _First2, _OSe _Last2) const { // clang-format on if (_Count <= 0) { @@ -297,28 +324,35 @@ namespace ranges { const auto _OLast = _Get_unwrapped(_STD move(_Last2)); if constexpr (_Iter_move_cat<_It, _Out>::_Bitcopy_constructible && _Sized_or_unreachable_sentinel_for<_OSe, _Out>) { - if constexpr (sized_sentinel_for<_OSe, _Out>) { - auto _UResult = _Copy_memcpy_common( - _IFirst, _IFirst + _Count, _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); - _IFirst = _STD move(_UResult.in); - _OFirst = _STD move(_UResult.out); - } else { - auto _UResult = _Copy_memcpy_count(_IFirst, _OFirst, static_cast(_Count)); - _IFirst = _STD move(_UResult.in); - _OFirst = _STD move(_UResult.out); - } - } else { - _Uninitialized_backout _Backout{_STD move(_OFirst)}; +#if _HAS_CXX23 + if (!_STD is_constant_evaluated()) +#endif // _HAS_CXX23 + { + if constexpr (sized_sentinel_for<_OSe, _Out>) { + auto _UResult = _Copy_memcpy_common( + _IFirst, _IFirst + _Count, _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); + _IFirst = _STD move(_UResult.in); + _OFirst = _STD move(_UResult.out); + } else { + auto _UResult = _Copy_memcpy_count(_IFirst, _OFirst, static_cast(_Count)); + _IFirst = _STD move(_UResult.in); + _OFirst = _STD move(_UResult.out); + } - for (; _Count > 0 && _Backout._Last != _OLast; --_Count, (void) ++_IFirst) { - _Backout._Emplace_back(_RANGES iter_move(_IFirst)); + _Seek_wrapped(_First1, _IFirst); + _Seek_wrapped(_First2, _OFirst); + return {_STD move(_First1), _STD move(_First2)}; } + } + + _Uninitialized_backout _Backout{_STD move(_OFirst)}; - _OFirst = _Backout._Release(); + for (; _Count > 0 && _Backout._Last != _OLast; --_Count, (void) ++_IFirst) { + _Backout._Emplace_back(_RANGES iter_move(_IFirst)); } _Seek_wrapped(_First1, _IFirst); - _Seek_wrapped(_First2, _OFirst); + _Seek_wrapped(_First2, _Backout._Release()); return {_STD move(_First1), _STD move(_First2)}; } }; @@ -332,7 +366,7 @@ namespace ranges { // clang-format off template <_No_throw_forward_iterator _It, _No_throw_sentinel_for<_It> _Se, class _Ty> requires constructible_from, const _Ty&> - _It operator()(_It _First, _Se _Last, const _Ty& _Val) const { + _CONSTEXPR23 _It operator()(_It _First, _Se _Last, const _Ty& _Val) const { // clang-format on _Adl_verify_range(_First, _Last); auto _UResult = _Uninitialized_fill_unchecked( @@ -345,39 +379,48 @@ namespace ranges { // clang-format off template <_No_throw_forward_range _Rng, class _Ty> requires constructible_from, const _Ty&> - borrowed_iterator_t<_Rng> operator()(_Rng&& _Range, const _Ty& _Val) const { + _CONSTEXPR23 borrowed_iterator_t<_Rng> operator()(_Rng&& _Range, const _Ty& _Val) const { // clang-format on return _Rewrap_iterator(_Range, _Uninitialized_fill_unchecked(_Ubegin(_Range), _Uend(_Range), _Val)); } private: template - _NODISCARD static _It _Uninitialized_fill_unchecked(_It _OFirst, _Se _OLast, const _Ty& _Val) { + _NODISCARD static _CONSTEXPR23 _It _Uninitialized_fill_unchecked(_It _OFirst, _Se _OLast, const _Ty& _Val) { _STL_INTERNAL_STATIC_ASSERT(_No_throw_forward_iterator<_It>); _STL_INTERNAL_STATIC_ASSERT(_No_throw_sentinel_for<_Se, _It>); _STL_INTERNAL_STATIC_ASSERT(constructible_from, const _Ty&>); if constexpr (_Fill_memset_is_safe<_It, _Ty>) { - const auto _OFinal = _RANGES next(_OFirst, _STD move(_OLast)); - _Fill_memset(_OFirst, _Val, static_cast(_OFinal - _OFirst)); - return _OFinal; - } else { - if constexpr (_Fill_zero_memset_is_safe<_It, _Ty>) { +#if _HAS_CXX23 + if (!_STD is_constant_evaluated()) +#endif // _HAS_CXX23 + { + const auto _OFinal = _RANGES next(_OFirst, _STD move(_OLast)); + _Fill_memset(_OFirst, _Val, static_cast(_OFinal - _OFirst)); + return _OFinal; + } + } + if constexpr (_Fill_zero_memset_is_safe<_It, _Ty>) { +#if _HAS_CXX23 + if (!_STD is_constant_evaluated()) +#endif // _HAS_CXX23 + { if (_Is_all_bits_zero(_Val)) { const auto _OFinal = _RANGES next(_OFirst, _STD move(_OLast)); _Fill_zero_memset(_OFirst, static_cast(_OFinal - _OFirst)); return _OFinal; } } + } - _Uninitialized_backout _Backout{_STD move(_OFirst)}; + _Uninitialized_backout _Backout{_STD move(_OFirst)}; - while (_Backout._Last != _OLast) { - _Backout._Emplace_back(_Val); - } - - return _Backout._Release(); + while (_Backout._Last != _OLast) { + _Backout._Emplace_back(_Val); } + + return _Backout._Release(); } }; @@ -386,7 +429,7 @@ namespace ranges { #endif // __cpp_lib_concepts template -_NoThrowFwdIt uninitialized_fill_n(_NoThrowFwdIt _First, const _Diff _Count_raw, const _Tval& _Val) { +_CONSTEXPR23 _NoThrowFwdIt uninitialized_fill_n(_NoThrowFwdIt _First, const _Diff _Count_raw, const _Tval& _Val) { // copy _Count copies of _Val to raw _First _Algorithm_int_t<_Diff> _Count = _Count_raw; if (_Count <= 0) { @@ -395,27 +438,35 @@ _NoThrowFwdIt uninitialized_fill_n(_NoThrowFwdIt _First, const _Diff _Count_raw, auto _UFirst = _Get_unwrapped_n(_First, _Count); if constexpr (_Fill_memset_is_safe) { - _Fill_memset(_UFirst, _Val, static_cast(_Count)); - _UFirst += _Count; - } else { - if constexpr (_Fill_zero_memset_is_safe) { +#if _HAS_CXX23 + if (!_STD is_constant_evaluated()) +#endif // _HAS_CXX23 + { + _Fill_memset(_UFirst, _Val, static_cast(_Count)); + _Seek_wrapped(_First, _UFirst + _Count); + return _First; + } + } + if constexpr (_Fill_zero_memset_is_safe) { +#if _HAS_CXX23 + if (!_STD is_constant_evaluated()) +#endif // _HAS_CXX23 + { if (_Is_all_bits_zero(_Val)) { _Fill_zero_memset(_UFirst, static_cast(_Count)); _Seek_wrapped(_First, _UFirst + _Count); return _First; } } + } - _Uninitialized_backout _Backout{_UFirst}; + _Uninitialized_backout _Backout{_UFirst}; - for (; _Count > 0; --_Count) { - _Backout._Emplace_back(_Val); - } - - _UFirst = _Backout._Release(); + for (; _Count > 0; --_Count) { + _Backout._Emplace_back(_Val); } - _Seek_wrapped(_First, _UFirst); + _Seek_wrapped(_First, _Backout._Release()); return _First; } @@ -428,7 +479,7 @@ namespace ranges { // clang-format off template <_No_throw_forward_iterator _It, class _Ty> requires constructible_from, const _Ty&> - _It operator()(_It _First, iter_difference_t<_It> _Count, const _Ty& _Val) const { + _CONSTEXPR23 _It operator()(_It _First, iter_difference_t<_It> _Count, const _Ty& _Val) const { // clang-format on if (_Count <= 0) { return _First; @@ -436,25 +487,35 @@ namespace ranges { auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); if constexpr (_Fill_memset_is_safe) { - _Fill_memset(_UFirst, _Val, static_cast(_Count)); - _Seek_wrapped(_First, _UFirst + _Count); - } else { - if constexpr (_Fill_zero_memset_is_safe) { +#if _HAS_CXX23 + if (!_STD is_constant_evaluated()) +#endif // _HAS_CXX23 + { + _Fill_memset(_UFirst, _Val, static_cast(_Count)); + _Seek_wrapped(_First, _UFirst + _Count); + return _First; + } + } + if constexpr (_Fill_zero_memset_is_safe) { +#if _HAS_CXX23 + if (!_STD is_constant_evaluated()) +#endif // _HAS_CXX23 + { if (_Is_all_bits_zero(_Val)) { _Fill_zero_memset(_UFirst, static_cast(_Count)); _Seek_wrapped(_First, _UFirst + _Count); return _First; } } + } - _Uninitialized_backout _Backout{_STD move(_UFirst)}; - - for (; _Count > 0; --_Count) { - _Backout._Emplace_back(_Val); - } + _Uninitialized_backout _Backout{_STD move(_UFirst)}; - _Seek_wrapped(_First, _Backout._Release()); + for (; _Count > 0; --_Count) { + _Backout._Emplace_back(_Val); } + + _Seek_wrapped(_First, _Backout._Release()); return _First; } }; @@ -751,22 +812,28 @@ namespace ranges { #endif // __cpp_lib_concepts template -void uninitialized_value_construct(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) { +_CONSTEXPR23 void uninitialized_value_construct(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) { // value-initialize all elements in [_First, _Last) _Adl_verify_range(_First, _Last); const auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); if constexpr (_Use_memset_value_construct_v<_Unwrapped_t>) { - _Zero_range(_UFirst, _ULast); - } else { - _Uninitialized_backout _Backout{_UFirst}; - - while (_Backout._Last != _ULast) { - _Backout._Emplace_back(); +#if _HAS_CXX23 + if (!_STD is_constant_evaluated()) +#endif // _HAS_CXX23 + { + _Zero_range(_UFirst, _ULast); + return; } + } - _Backout._Release(); + _Uninitialized_backout _Backout{_UFirst}; + + while (_Backout._Last != _ULast) { + _Backout._Emplace_back(); } + + _Backout._Release(); } #ifdef __cpp_lib_concepts @@ -778,7 +845,7 @@ namespace ranges { // clang-format off template <_No_throw_forward_iterator _It, _No_throw_sentinel_for<_It> _Se> requires default_initializable> - _It operator()(_It _First, _Se _Last) const { + _CONSTEXPR23 _It operator()(_It _First, _Se _Last) const { // clang-format on _Adl_verify_range(_First, _Last); auto _UResult = _Uninitialized_value_construct_unchecked( @@ -791,7 +858,7 @@ namespace ranges { // clang-format off template <_No_throw_forward_range _Rng> requires default_initializable> - borrowed_iterator_t<_Rng> operator()(_Rng&& _Range) const { + _CONSTEXPR23 borrowed_iterator_t<_Rng> operator()(_Rng&& _Range) const { // clang-format on auto _UResult = _Uninitialized_value_construct_unchecked(_Ubegin(_Range), _Uend(_Range)); @@ -800,22 +867,27 @@ namespace ranges { private: template - _NODISCARD static _It _Uninitialized_value_construct_unchecked(_It _OFirst, _Se _OLast) { + _NODISCARD static _CONSTEXPR23 _It _Uninitialized_value_construct_unchecked(_It _OFirst, _Se _OLast) { _STL_INTERNAL_STATIC_ASSERT(_No_throw_forward_iterator<_It>); _STL_INTERNAL_STATIC_ASSERT(_No_throw_sentinel_for<_Se, _It>); _STL_INTERNAL_STATIC_ASSERT(default_initializable>); if constexpr (_Use_memset_value_construct_v<_It>) { - return _Zero_range(_OFirst, _RANGES next(_OFirst, _STD move(_OLast))); - } else { - _Uninitialized_backout _Backout{_STD move(_OFirst)}; - - while (_Backout._Last != _OLast) { - _Backout._Emplace_back(); +#if _HAS_CXX23 + if (!_STD is_constant_evaluated()) +#endif // _HAS_CXX23 + { + return _Zero_range(_OFirst, _RANGES next(_OFirst, _STD move(_OLast))); } + } - return _Backout._Release(); + _Uninitialized_backout _Backout{_STD move(_OFirst)}; + + while (_Backout._Last != _OLast) { + _Backout._Emplace_back(); } + + return _Backout._Release(); } }; @@ -825,7 +897,7 @@ namespace ranges { #endif // __cpp_lib_concepts template -_NoThrowFwdIt uninitialized_value_construct_n(_NoThrowFwdIt _First, const _Diff _Count_raw) { +_CONSTEXPR23 _NoThrowFwdIt uninitialized_value_construct_n(_NoThrowFwdIt _First, const _Diff _Count_raw) { // value-initialize all elements in [_First, _First + _Count_raw) _Algorithm_int_t<_Diff> _Count = _Count_raw; if (_Count <= 0) { @@ -845,7 +917,7 @@ namespace ranges { // clang-format off template <_No_throw_forward_iterator _It> requires default_initializable> - _It operator()(_It _First, iter_difference_t<_It> _Count) const { + _CONSTEXPR23 _It operator()(_It _First, iter_difference_t<_It> _Count) const { // clang-format on if (_Count <= 0) { return _First; @@ -853,16 +925,22 @@ namespace ranges { auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); if constexpr (_Use_memset_value_construct_v<_It>) { - _Seek_wrapped(_First, _Zero_range(_UFirst, _UFirst + _Count)); - } else { - _Uninitialized_backout _Backout{_STD move(_UFirst)}; - - for (; _Count > 0; --_Count) { - _Backout._Emplace_back(); +#if _HAS_CXX23 + if (!_STD is_constant_evaluated()) +#endif // _HAS_CXX23 + { + _Seek_wrapped(_First, _Zero_range(_UFirst, _UFirst + _Count)); + return _First; } + } - _Seek_wrapped(_First, _Backout._Release()); + _Uninitialized_backout _Backout{_STD move(_UFirst)}; + + for (; _Count > 0; --_Count) { + _Backout._Emplace_back(); } + + _Seek_wrapped(_First, _Backout._Release()); return _First; } }; diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 0701858f35e..987ce6860d0 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1601,7 +1601,7 @@ namespace ranges { template _Se, _No_throw_forward_iterator _Out, _No_throw_sentinel_for<_Out> _OSe> requires (constructible_from, iter_rvalue_reference_t<_It>>) - uninitialized_move_result<_It, _Out> _Uninitialized_move_unchecked( + _CONSTEXPR23 uninitialized_move_result<_It, _Out> _Uninitialized_move_unchecked( _It _IFirst, _Se _ILast, _Out _OFirst, _OSe _OLast) { // clang-format on constexpr bool _Is_sized1 = sized_sentinel_for<_Se, _It>; @@ -1609,25 +1609,30 @@ namespace ranges { if constexpr (_Iter_move_cat<_It, _Out>::_Bitcopy_constructible && _Sized_or_unreachable_sentinel_for<_Se, _It> // && _Sized_or_unreachable_sentinel_for<_OSe, _Out>) { - if constexpr (_Is_sized1 && _Is_sized2) { - return _Copy_memcpy_common(_IFirst, _RANGES next(_IFirst, _STD move(_ILast)), _OFirst, - _RANGES next(_OFirst, _STD move(_OLast))); - } else if constexpr (_Is_sized1) { - return _Copy_memcpy_distance(_IFirst, _OFirst, _IFirst, _RANGES next(_IFirst, _STD move(_ILast))); - } else if constexpr (_Is_sized2) { - return _Copy_memcpy_distance(_IFirst, _OFirst, _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); - } else { - _STL_ASSERT(false, "Tried to uninitialized_move two ranges with unreachable sentinels"); +#if _HAS_CXX23 + if (!_STD is_constant_evaluated()) +#endif // _HAS_CXX23 + { + if constexpr (_Is_sized1 && _Is_sized2) { + return _Copy_memcpy_common(_IFirst, _RANGES next(_IFirst, _STD move(_ILast)), _OFirst, + _RANGES next(_OFirst, _STD move(_OLast))); + } else if constexpr (_Is_sized1) { + return _Copy_memcpy_distance(_IFirst, _OFirst, _IFirst, _RANGES next(_IFirst, _STD move(_ILast))); + } else if constexpr (_Is_sized2) { + return _Copy_memcpy_distance(_IFirst, _OFirst, _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); + } else { + _STL_ASSERT(false, "Tried to uninitialized_move two ranges with unreachable sentinels"); + } } - } else { - _Uninitialized_backout _Backout{_STD move(_OFirst)}; + } - for (; _IFirst != _ILast && _Backout._Last != _OLast; ++_IFirst) { - _Backout._Emplace_back(_RANGES iter_move(_IFirst)); - } + _Uninitialized_backout _Backout{_STD move(_OFirst)}; - return {_STD move(_IFirst), _Backout._Release()}; + for (; _IFirst != _ILast && _Backout._Last != _OLast; ++_IFirst) { + _Backout._Emplace_back(_RANGES iter_move(_IFirst)); } + + return {_STD move(_IFirst), _Backout._Release()}; } } // namespace ranges #endif // __cpp_lib_concepts @@ -1715,7 +1720,7 @@ _CONSTEXPR20 _NoThrowFwdIt _Uninitialized_copy_unchecked(_InIt _First, const _In } template -_NoThrowFwdIt uninitialized_copy(const _InIt _First, const _InIt _Last, _NoThrowFwdIt _Dest) { +_CONSTEXPR23 _NoThrowFwdIt uninitialized_copy(const _InIt _First, const _InIt _Last, _NoThrowFwdIt _Dest) { // copy [_First, _Last) to raw [_Dest, ...) _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); @@ -1786,28 +1791,37 @@ _CONSTEXPR20 _Alloc_ptr_t<_Alloc> _Uninitialized_fill_n( } template -void uninitialized_fill(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last, const _Tval& _Val) { +_CONSTEXPR23 void uninitialized_fill(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last, const _Tval& _Val) { // copy _Val throughout raw [_First, _Last) _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); if constexpr (_Fill_memset_is_safe<_Unwrapped_t, _Tval>) { - _Fill_memset(_UFirst, _Val, static_cast(_ULast - _UFirst)); - } else { - if constexpr (_Fill_zero_memset_is_safe<_Unwrapped_t, _Tval>) { +#if _HAS_CXX23 + if (!_STD is_constant_evaluated()) +#endif // _HAS_CXX23 + { + _Fill_memset(_UFirst, _Val, static_cast(_ULast - _UFirst)); + return; + } + } else if constexpr (_Fill_zero_memset_is_safe<_Unwrapped_t, _Tval>) { +#if _HAS_CXX23 + if (!_STD is_constant_evaluated()) +#endif // _HAS_CXX23 + { if (_Is_all_bits_zero(_Val)) { _Fill_zero_memset(_UFirst, static_cast(_ULast - _UFirst)); return; } } + } - _Uninitialized_backout<_Unwrapped_t> _Backout{_UFirst}; - while (_Backout._Last != _ULast) { - _Backout._Emplace_back(_Val); - } - - _Backout._Release(); + _Uninitialized_backout<_Unwrapped_t> _Backout{_UFirst}; + while (_Backout._Last != _ULast) { + _Backout._Emplace_back(_Val); } + + _Backout._Release(); } template @@ -1849,19 +1863,24 @@ _CONSTEXPR20 _Alloc_ptr_t<_Alloc> _Uninitialized_value_construct_n( } template -_NoThrowFwdIt _Uninitialized_value_construct_n_unchecked1(_NoThrowFwdIt _UFirst, _Diff _Count) { +_CONSTEXPR23 _NoThrowFwdIt _Uninitialized_value_construct_n_unchecked1(_NoThrowFwdIt _UFirst, _Diff _Count) { // value-initialize all elements in [_UFirst, _UFirst + _Count_raw) _STL_INTERNAL_CHECK(_Count >= 0); if constexpr (_Use_memset_value_construct_v<_NoThrowFwdIt>) { - return _Zero_range(_UFirst, _UFirst + _Count); - } else { - _Uninitialized_backout<_NoThrowFwdIt> _Backout{_UFirst}; - for (; 0 < _Count; --_Count) { - _Backout._Emplace_back(); +#if _HAS_CXX23 + if (!_STD is_constant_evaluated()) +#endif // _HAS_CXX23 + { + return _Zero_range(_UFirst, _UFirst + _Count); } + } - return _Backout._Release(); + _Uninitialized_backout<_NoThrowFwdIt> _Backout{_UFirst}; + for (; 0 < _Count; --_Count) { + _Backout._Emplace_back(); } + + return _Backout._Release(); } #if _HAS_DEPRECATED_TEMPORARY_BUFFER diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 037be9c5a92..3215ab7be0c 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -295,6 +295,7 @@ // P2136R3 invoke_r() // P2166R1 Prohibiting basic_string And basic_string_view Construction From nullptr // P2186R2 Removing Garbage Collection Support +// P2283R2 constexpr Specialized Memory Algorithms // Parallel Algorithms Notes // C++ allows an implementation to implement parallel algorithms as calls to the serial algorithms. @@ -620,6 +621,13 @@ #define _CONSTEXPR20 inline #endif // ^^^ inline (not constexpr) in C++17 and earlier ^^^ +// Functions that became constexpr in C++23 +#if _HAS_CXX23 +#define _CONSTEXPR23 constexpr +#else // ^^^ constexpr in C++23 and later / inline (not constexpr) in C++20 and earlier vvv +#define _CONSTEXPR23 inline +#endif // ^^^ inline (not constexpr) in C++20 and earlier ^^^ + // P0607R0 Inline Variables For The STL #if _HAS_CXX17 #define _INLINE_VAR inline @@ -1219,12 +1227,12 @@ #ifndef _M_CEE #define __cpp_lib_parallel_algorithm 201603L #endif // _M_CEE -#define __cpp_lib_raw_memory_algorithms 201606L -#define __cpp_lib_sample 201603L -#define __cpp_lib_scoped_lock 201703L -#define __cpp_lib_shared_ptr_weak_type 201606L -#define __cpp_lib_string_view 201803L -#define __cpp_lib_to_chars 201611L + +#define __cpp_lib_sample 201603L +#define __cpp_lib_scoped_lock 201703L +#define __cpp_lib_shared_ptr_weak_type 201606L +#define __cpp_lib_string_view 201803L +#define __cpp_lib_to_chars 201611L #endif // _HAS_CXX17 // C++20 @@ -1390,6 +1398,12 @@ #define __cpp_lib_to_underlying 202102L #endif // _HAS_CXX23 +#if _HAS_CXX23 +#define __cpp_lib_raw_memory_algorithms 202106L +#elif _HAS_CXX17 // _HAS_CXX17 +#define __cpp_lib_raw_memory_algorithms 201606L +#endif // _HAS_CXX17 + #define __cpp_lib_experimental_erase_if 201411L #define __cpp_lib_experimental_filesystem 201406L diff --git a/tests/std/test.lst b/tests/std/test.lst index 8ef66c88176..76d882beee5 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -452,6 +452,14 @@ tests\P1951R1_default_arguments_pair_forward_ctor tests\P2136R3_invoke_r tests\P2162R2_std_visit_for_derived_classes_from_variant tests\P2231R1_complete_constexpr_optional_variant +tests\P2283R2_constexpr_uninitialized_copy +tests\P2283R2_constexpr_uninitialized_copy_n +tests\P2283R2_constexpr_uninitialized_fill +tests\P2283R2_constexpr_uninitialized_fill_n +tests\P2283R2_constexpr_uninitialized_move +tests\P2283R2_constexpr_uninitialized_move_n +tests\P2283R2_constexpr_uninitialized_value_construct +tests\P2283R2_constexpr_uninitialized_value_construct_n tests\P2401R0_conditional_noexcept_for_exchange tests\P2415R2_owning_view tests\VSO_0000000_allocator_propagation diff --git a/tests/std/tests/P2283R2_constexpr_uninitialized_copy/env.lst b/tests/std/tests/P2283R2_constexpr_uninitialized_copy/env.lst new file mode 100644 index 00000000000..18e2d7c71ec --- /dev/null +++ b/tests/std/tests/P2283R2_constexpr_uninitialized_copy/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_latest_matrix.lst diff --git a/tests/std/tests/P2283R2_constexpr_uninitialized_copy/test.cpp b/tests/std/tests/P2283R2_constexpr_uninitialized_copy/test.cpp new file mode 100644 index 00000000000..6435373250d --- /dev/null +++ b/tests/std/tests/P2283R2_constexpr_uninitialized_copy/test.cpp @@ -0,0 +1,241 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +struct int_wrapper { + int val = 10; + + constexpr int_wrapper() noexcept = default; + constexpr int_wrapper(const int x) : val{x} {} + + constexpr auto operator==(const int_wrapper& right) const { + return val == right.val; + } + constexpr auto operator<=>(const int_wrapper&) const = default; +}; + +template +struct holder { + static_assert(N < ~size_t{0} / sizeof(T)); + T* _data = new T[N]; + + constexpr holder() = default; + constexpr ~holder() { + delete[] _data; + } + + constexpr auto as_span() noexcept { + return span{_data, N}; + } +}; + +struct instantiator { + static constexpr int expected_output[] = {13, 55, 12345}; + static constexpr int expected_output_long[] = {13, 55, 12345, -1}; + static constexpr int expected_input[] = {13, 55, 12345}; + static constexpr int expected_input_long[] = {13, 55, 12345, 42}; + + template + static constexpr void call() { + using ranges::common_range, ranges::range_value_t, ranges::range_reference_t; + + { // Validate range overload + int_wrapper input[3] = {13, 55, 12345}; + R wrapped_input{input}; + holder mem; + W wrapped_output{mem.as_span()}; + + const auto result = ranges::uninitialized_copy(wrapped_input, wrapped_output); + assert(result.in == wrapped_input.end()); + assert(result.out == wrapped_output.end()); + assert(ranges::equal(wrapped_output, expected_output)); + assert(ranges::equal(input, expected_input)); + } + + { // Validate iterator overload + int_wrapper input[3] = {13, 55, 12345}; + R wrapped_input{input}; + holder mem; + W wrapped_output{mem.as_span()}; + + const auto result = ranges::uninitialized_copy( + wrapped_input.begin(), wrapped_input.end(), wrapped_output.begin(), wrapped_output.end()); + assert(result.in == wrapped_input.end()); + assert(result.out == wrapped_output.end()); + assert(ranges::equal(wrapped_output, expected_output)); + assert(ranges::equal(input, expected_input)); + } + + if constexpr (common_range && is_same_v, remove_reference_t>>) { + // Validate iterator overload for std + int_wrapper input[3] = {13, 55, 12345}; + R wrapped_input{input}; + holder mem; + W wrapped_output{mem.as_span()}; + + const auto result = uninitialized_copy(wrapped_input.begin(), wrapped_input.end(), wrapped_output.begin()); + assert(result == wrapped_output.end()); + assert(ranges::equal(wrapped_output, expected_output)); + assert(ranges::equal(input, expected_input)); + } + + { // Validate range overload shorter output + int_wrapper input[4] = {13, 55, 12345, 42}; + R wrapped_input{input}; + holder mem; + W wrapped_output{mem.as_span()}; + + auto result = ranges::uninitialized_copy(wrapped_input, wrapped_output); + assert(++result.in == wrapped_input.end()); + assert(result.out == wrapped_output.end()); + assert(ranges::equal(wrapped_output, expected_output)); + assert(ranges::equal(input, expected_input_long)); + } + + { // Validate range overload shorter input + int_wrapper input[3] = {13, 55, 12345}; + R wrapped_input{input}; + holder mem; + W wrapped_output{mem.as_span()}; + + auto result = ranges::uninitialized_copy(wrapped_input, wrapped_output); + assert(result.in == wrapped_input.end()); + construct_at(addressof(*result.out), -1); // Need to construct non written element for comparison + assert(++result.out == wrapped_output.end()); + assert(ranges::equal(wrapped_output, expected_output_long)); + assert(ranges::equal(input, expected_input)); + } + + if constexpr (common_range && is_same_v, remove_reference_t>>) { + // Validate iterator overload shorter input for std + int_wrapper input[3] = {13, 55, 12345}; + R wrapped_input{input}; + holder mem; + W wrapped_output{mem.as_span()}; + + const auto result = uninitialized_copy(wrapped_input.begin(), wrapped_input.end(), wrapped_output.begin()); + construct_at(addressof(*result), -1); // Need to construct non written element for comparison + assert(++result == wrapped_output.end()); + assert(ranges::equal(wrapped_output, expected_output)); + assert(ranges::equal(input, expected_input)); + } + } +}; + +struct memcpy_test { + static constexpr int expected_output[] = {13, 55, 12345}; + static constexpr int expected_output_long[] = {13, 55, 12345, -1}; + static constexpr int expected_input[] = {13, 55, 12345}; + static constexpr int expected_input_long[] = {13, 55, 12345, 42}; + + static constexpr void call() { + { // Validate matching ranges + int input[] = {13, 55, 12345}; + int output[3]; + + const auto result = ranges::uninitialized_copy(input, output); + assert(result.in == end(input)); + assert(result.out == end(output)); + assert(ranges::equal(input, expected_input)); + assert(ranges::equal(output, expected_output)); + } + + { // Validate matching ranges std algorithm + int input[] = {13, 55, 12345}; + int output[3]; + + const auto result = uninitialized_copy(begin(input), end(input), begin(output)); + assert(result == end(output)); + assert(ranges::equal(input, expected_input)); + assert(ranges::equal(output, expected_output)); + } + + { // Validate input shorter + int input[] = {13, 55, 12345}; + int output[4]; + + auto result = ranges::uninitialized_copy(input, output); + construct_at(addressof(*result.out), -1); // Need to construct non written element for comparison + assert(result.in == end(input)); + assert(++result.out == end(output)); + assert(ranges::equal(input, expected_input)); + assert(ranges::equal(output, expected_output_long)); + } + + { // Validate input shorter std algorithm + int input[] = {13, 55, 12345}; + int output[4]; + + auto result = uninitialized_copy(begin(input), end(input), begin(output)); + construct_at(addressof(*result), -1); // Need to construct non written element for comparison + assert(++result == end(output)); + assert(ranges::equal(input, expected_input)); + assert(ranges::equal(output, expected_output_long)); + } + + { // Validate output shorter + int input[] = {13, 55, 12345, 42}; + int output[3]; + + auto result = ranges::uninitialized_copy(input, output); + assert(++result.in == end(input)); + assert(result.out == end(output)); + assert(ranges::equal(input, expected_input_long)); + assert(ranges::equal(output, expected_output)); + } + + { // Validate no common input range + int input[] = {13, 55, 12345}; + int output[3]; + + const auto result = + ranges::uninitialized_copy(begin(input), unreachable_sentinel, begin(output), end(output)); + assert(result.in == end(input)); + assert(result.out == end(output)); + assert(ranges::equal(input, expected_input)); + assert(ranges::equal(output, expected_output)); + } + + { // Validate no common output range + int input[] = {13, 55, 12345}; + int output[3]; + + const auto result = + ranges::uninitialized_copy(begin(input), end(input), begin(output), unreachable_sentinel); + assert(result.in == end(input)); + assert(result.out == end(output)); + assert(ranges::equal(input, expected_input)); + assert(ranges::equal(output, expected_output)); + } + } +}; + +template +using test_input = test::range; +using test_output = test::range; + +int main() { + // The algorithm is oblivious to non-required category, size, difference, and "proxyness" of the input range. It + // _is_ sensitive to proxyness in that it requires non-proxy references for the output range. + instantiator::call, test_output>(); + instantiator::call, test_output>(); + memcpy_test::call(); + + static_assert((instantiator::call, test_output>(), true)); + static_assert((instantiator::call, test_output>(), true)); + static_assert((memcpy_test::call(), true)); +} diff --git a/tests/std/tests/P2283R2_constexpr_uninitialized_copy_n/env.lst b/tests/std/tests/P2283R2_constexpr_uninitialized_copy_n/env.lst new file mode 100644 index 00000000000..18e2d7c71ec --- /dev/null +++ b/tests/std/tests/P2283R2_constexpr_uninitialized_copy_n/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_latest_matrix.lst diff --git a/tests/std/tests/P2283R2_constexpr_uninitialized_copy_n/test.cpp b/tests/std/tests/P2283R2_constexpr_uninitialized_copy_n/test.cpp new file mode 100644 index 00000000000..64d61a5353c --- /dev/null +++ b/tests/std/tests/P2283R2_constexpr_uninitialized_copy_n/test.cpp @@ -0,0 +1,206 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +struct int_wrapper { + int val = 10; + + constexpr int_wrapper() noexcept = default; + constexpr int_wrapper(const int x) : val{x} {} + + constexpr auto operator==(const int_wrapper& right) const { + return val == right.val; + } + constexpr auto operator<=>(const int_wrapper&) const = default; +}; + +template +struct holder { + static_assert(N < ~size_t{0} / sizeof(T)); + T* _data = new T[N]; + + constexpr holder() = default; + constexpr ~holder() { + delete[] _data; + } + + constexpr auto as_span() noexcept { + return span{_data, N}; + } +}; + +struct instantiator { + static constexpr int expected_output[] = {13, 55, 12345}; + static constexpr int expected_output_long[] = {13, 55, 12345, -1}; + static constexpr int expected_input[] = {13, 55, 12345}; + static constexpr int expected_input_long[] = {13, 55, 12345, 42}; + + template + static constexpr void call() { + using ranges::common_range, ranges::range_value_t, ranges::range_reference_t; + + { // Validate matching range + int_wrapper input[3] = {13, 55, 12345}; + R wrapped_input{input}; + holder mem; + W wrapped_output{mem.as_span()}; + + const auto result = + ranges::uninitialized_copy_n(wrapped_input.begin(), 3, wrapped_output.begin(), wrapped_output.end()); + assert(result.in == wrapped_input.end()); + assert(result.out == wrapped_output.end()); + assert(ranges::equal(wrapped_output, expected_output)); + assert(ranges::equal(input, expected_input)); + } + + if constexpr (common_range && is_same_v, remove_reference_t>>) { + // Validate matching range for std + int_wrapper input[3] = {13, 55, 12345}; + R wrapped_input{input}; + holder mem; + W wrapped_output{mem.as_span()}; + + const auto result = uninitialized_copy_n(wrapped_input.begin(), 3, wrapped_output.begin()); + assert(result == wrapped_output.end()); + assert(ranges::equal(wrapped_output, expected_output)); + assert(ranges::equal(input, expected_input)); + } + + { // Validate shorter output + int_wrapper input[4] = {13, 55, 12345, 42}; + R wrapped_input{input}; + holder mem; + W wrapped_output{mem.as_span()}; + + auto result = + ranges::uninitialized_copy_n(wrapped_input.begin(), 3, wrapped_output.begin(), wrapped_output.end()); + assert(++result.in == wrapped_input.end()); + assert(result.out == wrapped_output.end()); + assert(ranges::equal(wrapped_output, expected_output)); + assert(ranges::equal(input, expected_input_long)); + } + + { // Validate shorter input + int_wrapper input[3] = {13, 55, 12345}; + R wrapped_input{input}; + holder mem; + W wrapped_output{mem.as_span()}; + + auto result = + ranges::uninitialized_copy_n(wrapped_input.begin(), 3, wrapped_output.begin(), wrapped_output.end()); + assert(result.in == wrapped_input.end()); + construct_at(addressof(*result.out), -1); // Need to construct non written element for comparison + assert(++result.out == wrapped_output.end()); + assert(ranges::equal(wrapped_output, expected_output_long)); + assert(ranges::equal(input, expected_input)); + } + + if constexpr (common_range && is_same_v, remove_reference_t>>) { + // Validate shorter input for std + int_wrapper input[3] = {13, 55, 12345}; + R wrapped_input{input}; + holder mem; + W wrapped_output{mem.as_span()}; + + const auto result = uninitialized_copy_n(wrapped_input.begin(), 3, wrapped_output.begin()); + construct_at(addressof(*result), -1); // Need to construct non written element for comparison + assert(++result == wrapped_output.end()); + assert(ranges::equal(wrapped_output, expected_output)); + assert(ranges::equal(input, expected_input)); + } + } +}; + +struct memcpy_test { + static constexpr int expected_output[] = {13, 55, 12345}; + static constexpr int expected_output_long[] = {13, 55, 12345, -1}; + static constexpr int expected_input[] = {13, 55, 12345}; + static constexpr int expected_input_long[] = {13, 55, 12345, 42}; + + static constexpr void call() { + { // Validate matching range + int input[] = {13, 55, 12345}; + int output[3]; + + const auto result = ranges::uninitialized_copy_n(begin(input), 3, begin(output), end(output)); + assert(result.in == end(input)); + assert(result.out == end(output)); + assert(ranges::equal(input, expected_input)); + assert(ranges::equal(output, expected_output)); + } + + { // Validate matching range std algorithm + int input[] = {13, 55, 12345}; + int output[3]; + + const auto result = uninitialized_copy_n(begin(input), 3, begin(output)); + assert(result == end(output)); + assert(ranges::equal(input, expected_input)); + assert(ranges::equal(output, expected_output)); + } + + { // Validate output shorter + int input[] = {13, 55, 12345, 42}; + int output[3]; + + auto result = ranges::uninitialized_copy_n(begin(input), 3, begin(output), end(output)); + assert(++result.in == end(input)); + assert(result.out == end(output)); + assert(ranges::equal(input, expected_input_long)); + assert(ranges::equal(output, expected_output)); + } + + { // Validate input shorter + int input[] = {13, 55, 12345}; + int output[4]; + + auto result = ranges::uninitialized_copy_n(begin(input), 3, begin(output), end(output)); + construct_at(addressof(*result.out), -1); // Need to construct non written element for comparison + assert(result.in == end(input)); + assert(++result.out == end(output)); + assert(ranges::equal(input, expected_input)); + assert(ranges::equal(output, expected_output_long)); + } + + { // Validate input shorter std algorithm + int input[] = {13, 55, 12345}; + int output[4]; + + auto result = uninitialized_copy_n(begin(input), 3, begin(output)); + construct_at(addressof(*result), -1); // Need to construct non written element for comparison + assert(++result == end(output)); + assert(ranges::equal(input, expected_input)); + assert(ranges::equal(output, expected_output_long)); + } + } +}; + +template +using test_input = test::range; +using test_output = test::range; + +int main() { + // The algorithm is oblivious to non-required category, size, difference, and "proxyness" of the input range. It + // _is_ sensitive to proxyness in that it requires non-proxy references for the output range. + instantiator::call, test_output>(); + instantiator::call, test_output>(); + memcpy_test::call(); + + static_assert((instantiator::call, test_output>(), true)); + static_assert((instantiator::call, test_output>(), true)); + static_assert((memcpy_test::call(), true)); +} diff --git a/tests/std/tests/P2283R2_constexpr_uninitialized_fill/env.lst b/tests/std/tests/P2283R2_constexpr_uninitialized_fill/env.lst new file mode 100644 index 00000000000..18e2d7c71ec --- /dev/null +++ b/tests/std/tests/P2283R2_constexpr_uninitialized_fill/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_latest_matrix.lst diff --git a/tests/std/tests/P2283R2_constexpr_uninitialized_fill/test.cpp b/tests/std/tests/P2283R2_constexpr_uninitialized_fill/test.cpp new file mode 100644 index 00000000000..0be508dd337 --- /dev/null +++ b/tests/std/tests/P2283R2_constexpr_uninitialized_fill/test.cpp @@ -0,0 +1,112 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +struct int_wrapper { + int val = 10; + + constexpr int_wrapper() noexcept = default; + constexpr int_wrapper(const int x) : val{x} {} + + constexpr auto operator==(const int_wrapper& right) const { + return val == right.val; + } + constexpr auto operator<=>(const int_wrapper&) const = default; +}; + +template +struct holder { + static_assert(N < ~size_t{0} / sizeof(T)); + T* _data = new T[N]; + + constexpr holder() = default; + constexpr ~holder() { + delete[] _data; + } + + constexpr auto as_span() noexcept { + return span{_data, N}; + } +}; + +struct instantiator { + static constexpr int expected_output[] = {42, 42, 42}; + + template + static constexpr void call() { + { // Validate range overload + holder mem; + W wrapped_output{mem.as_span()}; + + const auto result = ranges::uninitialized_fill(wrapped_output, 42); + assert(result == wrapped_output.end()); + assert(ranges::equal(wrapped_output, expected_output)); + } + + { // Validate iterator overload + holder mem; + W wrapped_output{mem.as_span()}; + + const auto result = ranges::uninitialized_fill(wrapped_output.begin(), wrapped_output.end(), 42); + assert(result == wrapped_output.end()); + assert(ranges::equal(wrapped_output, expected_output)); + } + + if constexpr (ranges::common_range) { + // Validate iterator overload for std + holder mem; + W wrapped_output{mem.as_span()}; + + const auto result = uninitialized_fill(wrapped_output.begin(), wrapped_output.end(), 42); + assert(result == wrapped_output.end()); + assert(ranges::equal(wrapped_output, expected_output)); + } + } +}; + +struct memset_test { + static constexpr auto answer = static_cast(42); + static constexpr unsigned char expected[] = {answer, answer, answer}; + + static constexpr void call() { + { // Validate ranges algorithm + unsigned char input[3]; + + const auto result = ranges::uninitialized_fill(input, answer); + assert(result == end(input)); + assert(ranges::equal(input, expected)); + } + + { // Validate std algorithm + unsigned char input[3]; + + uninitialized_fill(begin(input), end(input), answer); + assert(ranges::equal(input, expected)); + } + } +}; + +using test_range = test::range; + +int main() { + // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it + // requires non-proxy references for the input range. + instantiator::call(); + memset_test::call(); + + static_assert((instantiator::call(), true)); + static_assert((memset_test::call(), true)); +} diff --git a/tests/std/tests/P2283R2_constexpr_uninitialized_fill_n/env.lst b/tests/std/tests/P2283R2_constexpr_uninitialized_fill_n/env.lst new file mode 100644 index 00000000000..18e2d7c71ec --- /dev/null +++ b/tests/std/tests/P2283R2_constexpr_uninitialized_fill_n/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_latest_matrix.lst diff --git a/tests/std/tests/P2283R2_constexpr_uninitialized_fill_n/test.cpp b/tests/std/tests/P2283R2_constexpr_uninitialized_fill_n/test.cpp new file mode 100644 index 00000000000..fb76264fd4c --- /dev/null +++ b/tests/std/tests/P2283R2_constexpr_uninitialized_fill_n/test.cpp @@ -0,0 +1,105 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +struct int_wrapper { + int val = 10; + + constexpr int_wrapper() noexcept = default; + constexpr int_wrapper(const int x) : val{x} {} + + constexpr auto operator==(const int_wrapper& right) const { + return val == right.val; + } + constexpr auto operator<=>(const int_wrapper&) const = default; +}; + +template +struct holder { + static_assert(N < ~size_t{0} / sizeof(T)); + T* _data = new T[N]; + + constexpr holder() = default; + constexpr ~holder() { + delete[] _data; + } + + constexpr auto as_span() noexcept { + return span{_data, N}; + } +}; + +struct instantiator { + static constexpr int expected_output[] = {42, 42, 42}; + + template + static constexpr void call() { + { // Validate iterator overload + holder mem; + W wrapped_output{mem.as_span()}; + + const auto result = ranges::uninitialized_fill_n(wrapped_output.begin(), 3, 42); + assert(result == wrapped_output.end()); + assert(ranges::equal(wrapped_output, expected_output)); + } + + if constexpr (ranges::common_range) { + // Validate iterator overload for std + holder mem; + W wrapped_output{mem.as_span()}; + + const auto result = uninitialized_fill_n(wrapped_output.begin(), 3, 42); + assert(result == wrapped_output.end()); + assert(ranges::equal(wrapped_output, expected_output)); + } + } +}; + +struct memset_test { + static constexpr auto answer = static_cast(42); + static constexpr unsigned char expected[] = {answer, answer, answer}; + + static constexpr void call() { + { // Validate ranges algorithm + unsigned char input[3]; + + const auto result = ranges::uninitialized_fill_n(begin(input), 3, answer); + assert(result == end(input)); + assert(ranges::equal(input, expected)); + } + + { // Validate std algorithm + unsigned char input[3]; + + const auto result = uninitialized_fill_n(begin(input), 3, answer); + assert(result == end(input)); + assert(ranges::equal(input, expected)); + } + } +}; + +using test_range = test::range; + + +int main() { + // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it + // requires non-proxy references for the input range. + instantiator::call(); + memset_test::call(); + + static_assert((instantiator::call(), true)); + static_assert((memset_test::call(), true)); +} diff --git a/tests/std/tests/P2283R2_constexpr_uninitialized_move/env.lst b/tests/std/tests/P2283R2_constexpr_uninitialized_move/env.lst new file mode 100644 index 00000000000..18e2d7c71ec --- /dev/null +++ b/tests/std/tests/P2283R2_constexpr_uninitialized_move/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_latest_matrix.lst diff --git a/tests/std/tests/P2283R2_constexpr_uninitialized_move/test.cpp b/tests/std/tests/P2283R2_constexpr_uninitialized_move/test.cpp new file mode 100644 index 00000000000..d971e4d69eb --- /dev/null +++ b/tests/std/tests/P2283R2_constexpr_uninitialized_move/test.cpp @@ -0,0 +1,246 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +struct int_wrapper { + int val = 10; + + constexpr int_wrapper() noexcept = default; + constexpr int_wrapper(const int x) : val{x} {} + constexpr int_wrapper(const int_wrapper&) = default; + constexpr int_wrapper(int_wrapper&& that) { + val = exchange(that.val, -1); + } + + constexpr auto operator==(const int_wrapper& right) const { + return val == right.val; + } + constexpr auto operator<=>(const int_wrapper&) const = default; +}; + +template +struct holder { + static_assert(N < ~size_t{0} / sizeof(T)); + T* _data = new T[N]; + + constexpr holder() = default; + constexpr ~holder() { + delete[] _data; + } + + constexpr auto as_span() noexcept { + return span{_data, N}; + } +}; + +struct instantiator { + static constexpr int expected_output[] = {13, 55, 12345}; + static constexpr int expected_output_long[] = {13, 55, 12345, -1}; + static constexpr int expected_input[] = {-1, -1, -1}; + static constexpr int expected_input_long[] = {-1, -1, -1, 42}; + + template + static constexpr void call() { + using ranges::uninitialized_move, ranges::common_range, ranges::equal, ranges::range_value_t, + ranges::range_reference_t; + + { // Validate range overload + int_wrapper input[3] = {13, 55, 12345}; + R wrapped_input{input}; + holder mem; + W wrapped_output{mem.as_span()}; + + const auto result = uninitialized_move(wrapped_input, wrapped_output); + assert(result.in == wrapped_input.end()); + assert(result.out == wrapped_output.end()); + assert(equal(wrapped_output, expected_output)); + assert(equal(input, expected_input)); + } + + { // Validate iterator overload + int_wrapper input[3] = {13, 55, 12345}; + R wrapped_input{input}; + holder mem; + W wrapped_output{mem.as_span()}; + + const auto result = uninitialized_move( + wrapped_input.begin(), wrapped_input.end(), wrapped_output.begin(), wrapped_output.end()); + assert(result.in == wrapped_input.end()); + assert(result.out == wrapped_output.end()); + assert(equal(wrapped_output, expected_output)); + assert(equal(input, expected_input)); + } + + if constexpr (common_range && is_same_v, remove_reference_t>>) { + // Validate iterator overload for std + int_wrapper input[3] = {13, 55, 12345}; + R wrapped_input{input}; + holder mem; + W wrapped_output{mem.as_span()}; + + const auto result = uninitialized_move(wrapped_input.begin(), wrapped_input.end(), wrapped_output.begin()); + assert(result == wrapped_output.end()); + assert(ranges::equal(wrapped_output, expected_output)); + assert(ranges::equal(input, expected_input)); + } + + { // Validate range overload shorter output + int_wrapper input[4] = {13, 55, 12345, 42}; + R wrapped_input{input}; + holder mem; + W wrapped_output{mem.as_span()}; + + auto result = ranges::uninitialized_move(wrapped_input, wrapped_output); + assert(++result.in == wrapped_input.end()); + assert(result.out == wrapped_output.end()); + assert(ranges::equal(wrapped_output, expected_output)); + assert(ranges::equal(input, expected_input_long)); + } + + { // Validate range overload shorter input + int_wrapper input[3] = {13, 55, 12345}; + R wrapped_input{input}; + holder mem; + W wrapped_output{mem.as_span()}; + + auto result = ranges::uninitialized_move(wrapped_input, wrapped_output); + assert(result.in == wrapped_input.end()); + construct_at(addressof(*result.out), -1); // Need to construct non written element for comparison + assert(++result.out == wrapped_output.end()); + assert(ranges::equal(wrapped_output, expected_output_long)); + assert(ranges::equal(input, expected_input)); + } + + if constexpr (common_range && is_same_v, remove_reference_t>>) { + // Validate iterator overload shorter input for std + int_wrapper input[3] = {13, 55, 12345}; + R wrapped_input{input}; + holder mem; + W wrapped_output{mem.as_span()}; + + const auto result = uninitialized_move(wrapped_input.begin(), wrapped_input.end(), wrapped_output.begin()); + construct_at(addressof(*result), -1); // Need to construct non written element for comparison + assert(++result == wrapped_output.end()); + assert(ranges::equal(wrapped_output, expected_output)); + assert(ranges::equal(input, expected_input)); + } + } +}; + +struct memcpy_test { + static constexpr int expected_output[] = {13, 55, 12345}; + static constexpr int expected_output_long[] = {13, 55, 12345, -1}; + static constexpr int expected_input[] = {13, 55, 12345}; + static constexpr int expected_input_long[] = {13, 55, 12345, 42}; + + static constexpr void call() { + { // Validate matching ranges + int input[] = {13, 55, 12345}; + int output[3]; + + const auto result = ranges::uninitialized_move(input, output); + assert(result.in == end(input)); + assert(result.out == end(output)); + assert(ranges::equal(input, expected_input)); + assert(ranges::equal(output, expected_output)); + } + + { // Validate matching range std algorithm + int input[] = {13, 55, 12345}; + int output[3]; + + const auto result = uninitialized_move(begin(input), end(input), begin(output)); + assert(result == end(output)); + assert(ranges::equal(input, expected_input)); + assert(ranges::equal(output, expected_output)); + } + + { // Validate input shorter + int input[] = {13, 55, 12345}; + int output[4]; + + auto result = ranges::uninitialized_move(input, output); + construct_at(addressof(*result.out), -1); // Need to construct non written element for comparison + assert(result.in == end(input)); + assert(++result.out == end(output)); + assert(ranges::equal(input, expected_input)); + assert(ranges::equal(output, expected_output_long)); + } + + { // Validate input shorter std algorithm + int input[] = {13, 55, 12345}; + int output[4]; + + auto result = uninitialized_move(begin(input), end(input), begin(output)); + construct_at(addressof(*result), -1); // Need to construct non written element for comparison + assert(++result == end(output)); + assert(ranges::equal(input, expected_input)); + assert(ranges::equal(output, expected_output_long)); + } + + { // Validate output shorter + int input[] = {13, 55, 12345, 42}; + int output[3]; + + auto result = ranges::uninitialized_move(input, output); + assert(++result.in == end(input)); + assert(result.out == end(output)); + assert(ranges::equal(input, expected_input_long)); + assert(ranges::equal(output, expected_output)); + } + + { // Validate no common input range + int input[] = {13, 55, 12345}; + int output[3]; + + const auto result = + ranges::uninitialized_move(begin(input), unreachable_sentinel, begin(output), end(output)); + assert(result.in == end(input)); + assert(result.out == end(output)); + assert(ranges::equal(input, expected_input)); + assert(ranges::equal(output, expected_output)); + } + + { // Validate no common output range + int input[] = {13, 55, 12345}; + int output[3]; + + const auto result = + ranges::uninitialized_move(begin(input), end(input), begin(output), unreachable_sentinel); + assert(result.in == end(input)); + assert(result.out == end(output)); + assert(ranges::equal(input, expected_input)); + assert(ranges::equal(output, expected_output)); + } + } +}; + +template +using test_input = test::range; +using test_output = test::range; + +int main() { + // The algorithm is oblivious to non-required category, size, difference, and "proxyness" of the input range. It + // _is_ sensitive to proxyness in that it requires non-proxy references for the output range. + instantiator::call, test_output>(); + instantiator::call, test_output>(); + memcpy_test::call(); + + static_assert((instantiator::call, test_output>(), true)); + static_assert((instantiator::call, test_output>(), true)); + static_assert((memcpy_test::call(), true)); +} diff --git a/tests/std/tests/P2283R2_constexpr_uninitialized_move_n/env.lst b/tests/std/tests/P2283R2_constexpr_uninitialized_move_n/env.lst new file mode 100644 index 00000000000..18e2d7c71ec --- /dev/null +++ b/tests/std/tests/P2283R2_constexpr_uninitialized_move_n/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_latest_matrix.lst diff --git a/tests/std/tests/P2283R2_constexpr_uninitialized_move_n/test.cpp b/tests/std/tests/P2283R2_constexpr_uninitialized_move_n/test.cpp new file mode 100644 index 00000000000..05b90fc9064 --- /dev/null +++ b/tests/std/tests/P2283R2_constexpr_uninitialized_move_n/test.cpp @@ -0,0 +1,212 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +struct int_wrapper { + int val = 10; + + constexpr int_wrapper() noexcept = default; + constexpr int_wrapper(const int x) : val{x} {} + constexpr int_wrapper(const int_wrapper&) = default; + constexpr int_wrapper(int_wrapper&& that) { + val = exchange(that.val, -1); + } + + constexpr auto operator==(const int_wrapper& right) const { + return val == right.val; + } + constexpr auto operator<=>(const int_wrapper&) const = default; +}; + +template +struct holder { + static_assert(N < ~size_t{0} / sizeof(T)); + T* _data = new T[N]; + + constexpr holder() = default; + constexpr ~holder() { + delete[] _data; + } + + constexpr auto as_span() noexcept { + return span{_data, N}; + } +}; + +struct instantiator { + static constexpr int expected_output[] = {13, 55, 12345}; + static constexpr int expected_output_long[] = {13, 55, 12345, -1}; + static constexpr int expected_input[] = {-1, -1, -1}; + static constexpr int expected_input_long[] = {-1, -1, -1, 42}; + + template + static constexpr void call() { + using ranges::common_range, ranges::range_value_t, ranges::range_reference_t; + + { // Validate matching range + int_wrapper input[3] = {13, 55, 12345}; + R wrapped_input{input}; + holder mem; + W wrapped_output{mem.as_span()}; + + const auto result = + ranges::uninitialized_move_n(wrapped_input.begin(), 3, wrapped_output.begin(), wrapped_output.end()); + assert(result.in == wrapped_input.end()); + assert(result.out == wrapped_output.end()); + assert(ranges::equal(wrapped_output, expected_output)); + assert(ranges::equal(input, expected_input)); + } + + if constexpr (common_range && is_same_v, remove_reference_t>>) { + // Validate matching range for std + int_wrapper input[3] = {13, 55, 12345}; + R wrapped_input{input}; + holder mem; + W wrapped_output{mem.as_span()}; + + const auto result = uninitialized_move_n(wrapped_input.begin(), 3, wrapped_output.begin()); + assert(result == wrapped_output.end()); + assert(ranges::equal(wrapped_output, expected_output)); + assert(ranges::equal(input, expected_input)); + } + + { // Validate shorter output + int_wrapper input[4] = {13, 55, 12345, 42}; + R wrapped_input{input}; + holder mem; + W wrapped_output{mem.as_span()}; + + auto result = + ranges::uninitialized_move_n(wrapped_input.begin(), 3, wrapped_output.begin(), wrapped_output.end()); + assert(++result.in == wrapped_input.end()); + assert(result.out == wrapped_output.end()); + assert(ranges::equal(wrapped_output, expected_output)); + assert(ranges::equal(input, expected_input_long)); + } + + { // Validate shorter input + int_wrapper input[3] = {13, 55, 12345}; + R wrapped_input{input}; + holder mem; + W wrapped_output{mem.as_span()}; + + auto result = + ranges::uninitialized_move_n(wrapped_input.begin(), 3, wrapped_output.begin(), wrapped_output.end()); + assert(result.in == wrapped_input.end()); + construct_at(addressof(*result.out), -1); // Need to construct non written element for comparison + assert(++result.out == wrapped_output.end()); + assert(ranges::equal(wrapped_output, expected_output_long)); + assert(ranges::equal(input, expected_input)); + } + + if constexpr (common_range && is_same_v, remove_reference_t>>) { + // Validate shorter input for std + int_wrapper input[3] = {13, 55, 12345}; + R wrapped_input{input}; + holder mem; + W wrapped_output{mem.as_span()}; + + const auto result = uninitialized_move_n(wrapped_input.begin(), 3, wrapped_output.begin()); + construct_at(addressof(*result), -1); // Need to construct non written element for comparison + assert(++result == wrapped_output.end()); + assert(ranges::equal(wrapped_output, expected_output)); + assert(ranges::equal(input, expected_input)); + } + } +}; + +struct memcpy_test { + static constexpr int expected_output[] = {13, 55, 12345}; + static constexpr int expected_output_long[] = {13, 55, 12345, -1}; + static constexpr int expected_input[] = {13, 55, 12345}; + static constexpr int expected_input_long[] = {13, 55, 12345, 42}; + + static constexpr void call() { + { // Validate matching range + int input[] = {13, 55, 12345}; + int output[3]; + + const auto result = ranges::uninitialized_move_n(begin(input), 3, begin(output), end(output)); + assert(result.in == end(input)); + assert(result.out == end(output)); + assert(ranges::equal(input, expected_input)); + assert(ranges::equal(output, expected_output)); + } + + { // Validate matching range std algorithm + int input[] = {13, 55, 12345}; + int output[3]; + + const auto result = uninitialized_move_n(begin(input), 3, begin(output)); + assert(result.first == end(input)); + assert(result.second == end(output)); + assert(ranges::equal(input, expected_input)); + assert(ranges::equal(output, expected_output)); + } + + { // Validate output shorter + int input[] = {13, 55, 12345, 42}; + int output[3]; + + auto result = ranges::uninitialized_move_n(begin(input), 4, begin(output), end(output)); + assert(++result.in == end(input)); + assert(result.out == end(output)); + assert(ranges::equal(input, expected_input_long)); + assert(ranges::equal(output, expected_output)); + } + + { // Validate input shorter + int input[] = {13, 55, 12345}; + int output[4]; + + auto result = ranges::uninitialized_move_n(begin(input), 3, begin(output), end(output)); + construct_at(addressof(*result.out), -1); // Need to construct non written element for comparison + assert(result.in == end(input)); + assert(++result.out == end(output)); + assert(ranges::equal(input, expected_input)); + assert(ranges::equal(output, expected_output_long)); + } + + { // Validate input shorter std algorithm + int input[] = {13, 55, 12345}; + int output[4]; + + auto result = uninitialized_move_n(begin(input), 3, begin(output)); + construct_at(addressof(*result.second), -1); // Need to construct non written element for comparison + assert(result.first == end(input)); + assert(++result.second == end(output)); + assert(ranges::equal(input, expected_input)); + assert(ranges::equal(output, expected_output_long)); + } + } +}; + +template +using test_input = test::range; +using test_output = test::range; + +int main() { + // The algorithm is oblivious to non-required category, size, difference, and "proxyness" of the input range. It + // _is_ sensitive to proxyness in that it requires non-proxy references for the output range. + instantiator::call, test_output>(); + instantiator::call, test_output>(); + memcpy_test::call(); + + static_assert((instantiator::call, test_output>(), true)); + static_assert((instantiator::call, test_output>(), true)); + static_assert((memcpy_test::call(), true)); +} diff --git a/tests/std/tests/P2283R2_constexpr_uninitialized_value_construct/env.lst b/tests/std/tests/P2283R2_constexpr_uninitialized_value_construct/env.lst new file mode 100644 index 00000000000..18e2d7c71ec --- /dev/null +++ b/tests/std/tests/P2283R2_constexpr_uninitialized_value_construct/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_latest_matrix.lst diff --git a/tests/std/tests/P2283R2_constexpr_uninitialized_value_construct/test.cpp b/tests/std/tests/P2283R2_constexpr_uninitialized_value_construct/test.cpp new file mode 100644 index 00000000000..dfaffadf46d --- /dev/null +++ b/tests/std/tests/P2283R2_constexpr_uninitialized_value_construct/test.cpp @@ -0,0 +1,111 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +struct int_wrapper { + int val = 10; + + constexpr int_wrapper() noexcept = default; + constexpr int_wrapper(const int x) : val{x} {} + + constexpr auto operator==(const int_wrapper& right) const { + return val == right.val; + } + constexpr auto operator<=>(const int_wrapper&) const = default; +}; + +template +struct holder { + static_assert(N < ~size_t{0} / sizeof(T)); + T* _data = new T[N]; + + constexpr holder() = default; + constexpr ~holder() { + delete[] _data; + } + + constexpr auto as_span() noexcept { + return span{_data, N}; + } +}; + +struct instantiator { + static constexpr int expected_output[] = {10, 10, 10}; + + template + static constexpr void call() { + { // Validate range overload + holder mem; + W wrapped_output{mem.as_span()}; + + const auto result = ranges::uninitialized_value_construct(wrapped_output); + assert(result == wrapped_output.end()); + assert(ranges::equal(wrapped_output, expected_output)); + } + + { // Validate iterator overload + holder mem; + W wrapped_output{mem.as_span()}; + + const auto result = ranges::uninitialized_value_construct(wrapped_output.begin(), wrapped_output.end()); + assert(result == wrapped_output.end()); + assert(ranges::equal(wrapped_output, expected_output)); + } + + if constexpr (ranges::common_range) { + // Validate iterator overload for std + holder mem; + W wrapped_output{mem.as_span()}; + + const auto result = std::uninitialized_value_construct(wrapped_output.begin(), wrapped_output.end()); + assert(result == wrapped_output.end()); + assert(ranges::equal(wrapped_output, expected_output)); + } + } +}; + +struct memset_test { + static constexpr int expected[] = {0, 0, 0}; + + static constexpr void call() { + { // Validate ranges algorithm + int input[3]; + + const auto result = ranges::uninitialized_value_construct(input); + assert(result == end(input)); + assert(ranges::equal(input, expected)); + } + + { // Validate std algorithm + int input[3]; + + std::uninitialized_value_construct(begin(input), end(input)); + assert(ranges::equal(input, expected)); + } + } +}; + +using test_range = test::range; + +int main() { + // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it + // requires non-proxy references for the input range. + instantiator::call(); + memset_test::call(); + + static_assert((instantiator::call(), true)); + static_assert((memset_test::call(), true)); +} diff --git a/tests/std/tests/P2283R2_constexpr_uninitialized_value_construct_n/env.lst b/tests/std/tests/P2283R2_constexpr_uninitialized_value_construct_n/env.lst new file mode 100644 index 00000000000..18e2d7c71ec --- /dev/null +++ b/tests/std/tests/P2283R2_constexpr_uninitialized_value_construct_n/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_latest_matrix.lst diff --git a/tests/std/tests/P2283R2_constexpr_uninitialized_value_construct_n/test.cpp b/tests/std/tests/P2283R2_constexpr_uninitialized_value_construct_n/test.cpp new file mode 100644 index 00000000000..be288bbe864 --- /dev/null +++ b/tests/std/tests/P2283R2_constexpr_uninitialized_value_construct_n/test.cpp @@ -0,0 +1,104 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +struct int_wrapper { + int val = 10; + + constexpr int_wrapper() noexcept = default; + constexpr int_wrapper(const int x) : val{x} {} + + constexpr auto operator==(const int_wrapper& right) const { + return val == right.val; + } + constexpr auto operator<=>(const int_wrapper&) const = default; +}; + +template +struct holder { + static_assert(N < ~size_t{0} / sizeof(T)); + T* _data = new T[N]; + + constexpr holder() = default; + constexpr ~holder() { + delete[] _data; + } + + constexpr auto as_span() noexcept { + return span{_data, N}; + } +}; + +struct instantiator { + static constexpr int expected_output[] = {10, 10, 10}; + + template + static constexpr void call() { + { // Validate iterator overload + holder mem; + W wrapped_output{mem.as_span()}; + + const auto result = ranges::uninitialized_value_construct_n(wrapped_output.begin(), 3); + assert(result == wrapped_output.end()); + assert(ranges::equal(wrapped_output, expected_output)); + } + + if constexpr (ranges::common_range) { + // Validate iterator overload for std + holder mem; + W wrapped_output{mem.as_span()}; + + const auto result = std::uninitialized_value_construct_n(wrapped_output.begin(), 3); + assert(result == wrapped_output.end()); + assert(ranges::equal(wrapped_output, expected_output)); + } + } +}; + +struct memset_test { + static constexpr int expected[] = {0, 0, 0}; + + static constexpr void call() { + { // Validate ranges algorithm + int input[3]; + + const auto result = ranges::uninitialized_value_construct_n(begin(input), 3); + assert(result == end(input)); + assert(ranges::equal(input, expected)); + } + + { // Validate std algorithm + int input[3]; + + const auto result = std::uninitialized_value_construct_n(begin(input), 3); + assert(result == end(input)); + assert(ranges::equal(input, expected)); + } + } +}; + +using test_range = test::range; + + +int main() { + // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it + // requires non-proxy references for the input range. + instantiator::call(); + memset_test::call(); + + static_assert((instantiator::call(), true)); + static_assert((memset_test::call(), true)); +} diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp index 00ae965fee5..a1e86272def 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp @@ -1322,7 +1322,15 @@ STATIC_ASSERT(__cpp_lib_ranges_starts_ends_with == 202106L); #endif #endif -#if _HAS_CXX17 +#if _HAS_CXX23 +#ifndef __cpp_lib_raw_memory_algorithms +#error __cpp_lib_raw_memory_algorithms is not defined +#elif __cpp_lib_raw_memory_algorithms != 202106L +#error __cpp_lib_raw_memory_algorithms is not 202106L +#else +STATIC_ASSERT(__cpp_lib_raw_memory_algorithms == 202106L); +#endif +#elif _HAS_CXX17 #ifndef __cpp_lib_raw_memory_algorithms #error __cpp_lib_raw_memory_algorithms is not defined #elif __cpp_lib_raw_memory_algorithms != 201606L