From ad2c84f494eaf27bc173c0cef0c15ede8db28cd3 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Tue, 21 Jan 2020 15:44:28 -0800 Subject: [PATCH 1/5] Implement constexpr algorithms. Resolves GH-6 ( P0202R3 ), GH-38 ( P0879R0 ), and drive-by fixes GH-414. Everywhere: Add constexpr, _CONSTEXPR20, and _CONSTEXPR20_ICE to things. skipped_tests.txt: Turn on all tests previously blocked by missing constexpr algorithms (and exchange and swap). Mark those algorithms that cannot be turned on that we have outstanding PRs for with their associated PRs. yvals_core.h: Turn on feature test macros. xutility: * Move the _Ptr_cat family down to copy, and fix associated SHOUTY comments to indicate that this is really an implementation detail of copy, not something the rest of the standard library intends to use directly. Removed and clarified some of the comments as requested by Casey Carter. * Extract _Copy_n_core which implements copy_n using only the core language (rather than memcpy-as-an-intrinsic). Note that we cannot use __builtin_memcpy or similar to avoid the is_constant_evaluated check here; builtin_memcpy only works in constexpr contexts when the inputs are of type char. numeric: Refactor as suggested by GH-414. --- llvm-project | 2 +- stl/inc/algorithm | 401 ++++++++++++++----------- stl/inc/numeric | 57 ++-- stl/inc/type_traits | 4 +- stl/inc/utility | 11 +- stl/inc/xmemory | 6 +- stl/inc/xutility | 529 +++++++++++++++++++++------------ stl/inc/yvals_core.h | 3 +- tests/libcxx/skipped_tests.txt | 116 ++------ 9 files changed, 630 insertions(+), 499 deletions(-) diff --git a/llvm-project b/llvm-project index 85ee4ff4e47..6d8abe424a7 160000 --- a/llvm-project +++ b/llvm-project @@ -1 +1 @@ -Subproject commit 85ee4ff4e474788abc7abdc939114281c2a68ec1 +Subproject commit 6d8abe424a77f736fbed114eeac574b9bfe6b0c1 diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 1ed36d82b42..6c381b4723d 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -80,7 +80,7 @@ struct _Optimistic_temporary_buffer { // temporary storage with _alloca-like att // FUNCTION TEMPLATE for_each template -_Fn for_each(_InIt _First, _InIt _Last, _Fn _Func) { // perform function for each element [_First, _Last) +_CONSTEXPR20 _Fn for_each(_InIt _First, _InIt _Last, _Fn _Func) { // perform function for each element [_First, _Last) _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); @@ -97,7 +97,7 @@ void for_each(_ExPo&& _Exec, _FwdIt _First, _FwdIt _Last, _Fn _Func) noexcept; / // FUNCTION TEMPLATE for_each_n template -_InIt for_each_n(_InIt _First, const _Diff _Count_raw, _Fn _Func) { +_CONSTEXPR20 _InIt for_each_n(_InIt _First, const _Diff _Count_raw, _Fn _Func) { // perform function for each element [_First, _First + _Count) _Algorithm_int_t<_Diff> _Count = _Count_raw; if (0 < _Count) { @@ -119,7 +119,7 @@ _FwdIt for_each_n(_ExPo&& _Exec, _FwdIt _First, _Diff _Count_raw, _Fn _Func) noe #if _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_InTy* for_each_n(_InTy (&_First)[_InSize], const _Diff _Count_raw, _Fn _Func) { +_CONSTEXPR20 _InTy* for_each_n(_InTy (&_First)[_InSize], const _Diff _Count_raw, _Fn _Func) { // perform function for each element [_First, _First + _Count) _Algorithm_int_t<_Diff> _Count = _Count_raw; _STL_VERIFY_ARRAY_SIZE(_First, _Count); @@ -146,7 +146,8 @@ _NODISCARD _FwdIt find_if(_ExPo&& _Exec, _FwdIt _First, const _FwdIt _Last, _Pr // FUNCTION TEMPLATE find_if_not template -_NODISCARD _InIt find_if_not(_InIt _First, const _InIt _Last, _Pr _Pred) { // find first element that satisfies !_Pred +_NODISCARD _CONSTEXPR20 _InIt find_if_not(_InIt _First, const _InIt _Last, _Pr _Pred) { + // find first element that satisfies !_Pred _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); @@ -167,7 +168,7 @@ _NODISCARD _FwdIt find_if_not(_ExPo&& _Exec, _FwdIt _First, _FwdIt _Last, _Pr _P // FUNCTION TEMPLATE adjacent_find template -_NODISCARD _FwdIt adjacent_find(const _FwdIt _First, _FwdIt _Last, _Pr _Pred) { +_NODISCARD _CONSTEXPR20 _FwdIt adjacent_find(const _FwdIt _First, _FwdIt _Last, _Pr _Pred) { // find first satisfying _Pred with successor _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); @@ -186,7 +187,7 @@ _NODISCARD _FwdIt adjacent_find(const _FwdIt _First, _FwdIt _Last, _Pr _Pred) { } template -_NODISCARD _FwdIt adjacent_find(const _FwdIt _First, const _FwdIt _Last) { // find first matching successor +_NODISCARD _CONSTEXPR20 _FwdIt adjacent_find(const _FwdIt _First, const _FwdIt _Last) { // find first matching successor return _STD adjacent_find(_First, _Last, equal_to<>()); } @@ -203,7 +204,8 @@ _NODISCARD _FwdIt adjacent_find(_ExPo&& _Exec, const _FwdIt _First, const _FwdIt // FUNCTION TEMPLATE count_if template -_NODISCARD _Iter_diff_t<_InIt> count_if(_InIt _First, _InIt _Last, _Pr _Pred) { // count elements satisfying _Pred +_NODISCARD _CONSTEXPR20 _Iter_diff_t<_InIt> count_if(_InIt _First, _InIt _Last, _Pr _Pred) { + // count elements satisfying _Pred _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); @@ -225,7 +227,7 @@ _NODISCARD _Iter_diff_t<_FwdIt> count_if( // FUNCTION TEMPLATE mismatch template -_NODISCARD pair<_InIt1, _InIt2> mismatch(_InIt1 _First1, const _InIt1 _Last1, _InIt2 _First2, _Pr _Pred) { +_NODISCARD _CONSTEXPR20 pair<_InIt1, _InIt2> mismatch(_InIt1 _First1, const _InIt1 _Last1, _InIt2 _First2, _Pr _Pred) { // return [_First1, _Last1)/[_First2, ...) mismatch using _Pred _Adl_verify_range(_First1, _Last1); auto _UFirst1 = _Get_unwrapped(_First1); @@ -243,8 +245,9 @@ _NODISCARD pair<_InIt1, _InIt2> mismatch(_InIt1 _First1, const _InIt1 _Last1, _I #if _ITERATOR_DEBUG_ARRAY_OVERLOADS template , int> = 0> -_NODISCARD pair<_InIt1, _RightTy*> mismatch(const _InIt1 _First1, const _InIt1 _Last1, _RightTy (&_First2)[_RightSize], - _Pr _Pred) { // return [_First1, _Last1)/[_First2, ...) mismatch using _Pred +_NODISCARD _CONSTEXPR20 pair<_InIt1, _RightTy*> mismatch( + const _InIt1 _First1, const _InIt1 _Last1, _RightTy (&_First2)[_RightSize], _Pr _Pred) { + // return [_First1, _Last1)/[_First2, ...) mismatch using _Pred const auto _Result = _STD mismatch(_First1, _Last1, _Array_iterator<_RightTy, _RightSize>(_First2), _Pass_fn(_Pred)); return {_Result.first, _Result.second._Unwrapped()}; @@ -270,14 +273,14 @@ _NODISCARD pair<_FwdIt1, _RightTy*> mismatch(_ExPo&& _Exec, const _FwdIt1 _First #endif // _HAS_CXX17 template -_NODISCARD pair<_InIt1, _InIt2> mismatch(const _InIt1 _First1, const _InIt1 _Last1, const _InIt2 _First2) { +_NODISCARD _CONSTEXPR20 pair<_InIt1, _InIt2> mismatch(const _InIt1 _First1, const _InIt1 _Last1, const _InIt2 _First2) { // return [_First1, _Last1)/[_First2, ...) mismatch return _STD mismatch(_First1, _Last1, _First2, equal_to<>()); } #if _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_NODISCARD pair<_InIt1, _RightTy*> mismatch( +_NODISCARD _CONSTEXPR20 pair<_InIt1, _RightTy*> mismatch( const _InIt1 _First1, const _InIt1 _Last1, _RightTy (&_First2)[_RightSize]) { // return [_First1, _Last1)/[_First2, ...) mismatch, array source return _STD mismatch(_First1, _Last1, _First2, equal_to<>()); @@ -307,7 +310,8 @@ _NODISCARD pair<_FwdIt1, _RightTy*> mismatch(_ExPo&& _Exec, const _FwdIt1 _First #if _HAS_IF_CONSTEXPR template -_NODISCARD pair<_InIt1, _InIt2> mismatch(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _Pr _Pred) { +_NODISCARD _CONSTEXPR20 pair<_InIt1, _InIt2> mismatch( + _InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _Pr _Pred) { // return [_First1, _Last1)/[_First2, _Last2) mismatch using _Pred _Adl_verify_range(_First1, _Last1); _Adl_verify_range(_First2, _Last2); @@ -380,7 +384,7 @@ _NODISCARD pair<_FwdIt1, _FwdIt2> mismatch( #endif // _HAS_CXX17 template -_NODISCARD pair<_InIt1, _InIt2> mismatch(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2) { +_NODISCARD _CONSTEXPR20 pair<_InIt1, _InIt2> mismatch(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2) { // return [_First1, _Last1)/[_First2, _Last2) mismatch return _STD mismatch(_First1, _Last1, _First2, _Last2, equal_to<>()); } @@ -398,7 +402,7 @@ _NODISCARD pair<_FwdIt1, _FwdIt2> mismatch( // FUNCTION TEMPLATE all_of template -_NODISCARD bool all_of(_InIt _First, _InIt _Last, _Pr _Pred) { // test if all elements satisfy _Pred +_NODISCARD _CONSTEXPR20 bool all_of(_InIt _First, _InIt _Last, _Pr _Pred) { // test if all elements satisfy _Pred _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); @@ -418,7 +422,8 @@ _NODISCARD bool all_of(_ExPo&&, _FwdIt _First, _FwdIt _Last, _Pr _Pred) noexcept // FUNCTION TEMPLATE any_of template -_NODISCARD bool any_of(const _InIt _First, const _InIt _Last, _Pr _Pred) { // test if any element satisfies _Pred +_NODISCARD _CONSTEXPR20 bool any_of(const _InIt _First, const _InIt _Last, _Pr _Pred) { + // test if any element satisfies _Pred _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); @@ -438,7 +443,8 @@ _NODISCARD bool any_of(_ExPo&&, const _FwdIt _First, const _FwdIt _Last, _Pr _Pr // FUNCTION TEMPLATE none_of template -_NODISCARD bool none_of(const _InIt _First, const _InIt _Last, _Pr _Pred) { // test if no elements satisfy _Pred +_NODISCARD _CONSTEXPR20 bool none_of(const _InIt _First, const _InIt _Last, _Pr _Pred) { + // test if no elements satisfy _Pred _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); @@ -458,7 +464,7 @@ _NODISCARD bool none_of(_ExPo&&, const _FwdIt _First, const _FwdIt _Last, _Pr _P // FUNCTION TEMPLATE copy_if template -_OutIt copy_if(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred) { // copy each satisfying _Pred +_CONSTEXPR20 _OutIt copy_if(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred) { // copy each satisfying _Pred _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); @@ -476,7 +482,7 @@ _OutIt copy_if(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred) { // copy eac #if _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_DestTy* copy_if(_InIt _First, _InIt _Last, _DestTy (&_Dest)[_DestSize], _Pr _Pred) { +_CONSTEXPR20 _DestTy* copy_if(_InIt _First, _InIt _Last, _DestTy (&_Dest)[_DestSize], _Pr _Pred) { // copy each satisfying _Pred, array dest return _STD copy_if(_First, _Last, _Array_iterator<_DestTy, _DestSize>(_Dest), _Pass_fn(_Pred))._Unwrapped(); } @@ -507,7 +513,8 @@ _DestTy* copy_if( // FUNCTION TEMPLATE partition_copy template -pair<_OutIt1, _OutIt2> partition_copy(_InIt _First, _InIt _Last, _OutIt1 _Dest_true, _OutIt2 _Dest_false, _Pr _Pred) { +_CONSTEXPR20 pair<_OutIt1, _OutIt2> partition_copy( + _InIt _First, _InIt _Last, _OutIt1 _Dest_true, _OutIt2 _Dest_false, _Pr _Pred) { // copy true partition to _Dest_true, false to _Dest_false _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); @@ -531,15 +538,16 @@ pair<_OutIt1, _OutIt2> partition_copy(_InIt _First, _InIt _Last, _OutIt1 _Dest_t #if _ITERATOR_DEBUG_ARRAY_OVERLOADS template -pair<_DestTrueTy*, _OutIt2> partition_copy(_InIt _First, _InIt _Last, _DestTrueTy (&_Dest_true)[_DestTrueSize], - _OutIt2 _Dest_false, _Pr _Pred) { // copy true partition to _Dest_true, false to _Dest_false, array dest +_CONSTEXPR20 pair<_DestTrueTy*, _OutIt2> partition_copy( + _InIt _First, _InIt _Last, _DestTrueTy (&_Dest_true)[_DestTrueSize], _OutIt2 _Dest_false, _Pr _Pred) { + // copy true partition to _Dest_true, false to _Dest_false, array dest const auto _Result = _STD partition_copy( _First, _Last, _Array_iterator<_DestTrueTy, _DestTrueSize>(_Dest_true), _Dest_false, _Pass_fn(_Pred)); return {_Result.first._Unwrapped(), _Result.second}; } template -pair<_OutIt1, _DestFalseTy*> partition_copy( +_CONSTEXPR20 pair<_OutIt1, _DestFalseTy*> partition_copy( _InIt _First, _InIt _Last, _OutIt1 _Dest_true, _DestFalseTy (&_Dest_false)[_DestFalseSize], _Pr _Pred) { // copy true partition to _Dest_true, false to _Dest_false, array dest const auto _Result = _STD partition_copy( @@ -548,8 +556,8 @@ pair<_OutIt1, _DestFalseTy*> partition_copy( } template -pair<_DestTrueTy*, _DestFalseTy*> partition_copy(_InIt _First, _InIt _Last, _DestTrueTy (&_Dest_true)[_DestTrueSize], - _DestFalseTy (&_Dest_false)[_DestFalseSize], _Pr _Pred) { +_CONSTEXPR20 pair<_DestTrueTy*, _DestFalseTy*> partition_copy(_InIt _First, _InIt _Last, + _DestTrueTy (&_Dest_true)[_DestTrueSize], _DestFalseTy (&_Dest_false)[_DestFalseSize], _Pr _Pred) { // copy true partition to _Dest_true, false to _Dest_false, array dest const auto _Result = _STD partition_copy(_First, _Last, _Array_iterator<_DestTrueTy, _DestTrueSize>(_Dest_true), _Array_iterator<_DestFalseTy, _DestFalseSize>(_Dest_false), _Pass_fn(_Pred)); @@ -607,7 +615,7 @@ pair<_DestTrueTy*, _DestFalseTy*> partition_copy(_ExPo&&, _FwdIt1 _First, _FwdIt // FUNCTION TEMPLATE is_partitioned template -_NODISCARD bool is_partitioned(const _InIt _First, const _InIt _Last, _Pr _Pred) { +_NODISCARD _CONSTEXPR20 bool is_partitioned(const _InIt _First, const _InIt _Last, _Pr _Pred) { // test if [_First, _Last) partitioned by _Pred _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); @@ -639,7 +647,7 @@ _NODISCARD bool is_partitioned(_ExPo&&, const _FwdIt _First, const _FwdIt _Last, // FUNCTION TEMPLATE partition_point template -_NODISCARD _FwdIt partition_point(_FwdIt _First, _FwdIt _Last, _Pr _Pred) { +_NODISCARD _CONSTEXPR20 _FwdIt partition_point(_FwdIt _First, _FwdIt _Last, _Pr _Pred) { // find beginning of false partition in [_First, _Last) _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); @@ -665,13 +673,27 @@ _NODISCARD _FwdIt partition_point(_FwdIt _First, _FwdIt _Last, _Pr _Pred) { // FUNCTION TEMPLATE _Equal_rev_pred_unchecked #if _HAS_IF_CONSTEXPR template -bool _Equal_rev_pred_unchecked(_InIt1 _First1, _InIt2 _First2, const _InIt2 _Last2, _Pr _Pred) { +_NODISCARD _CONSTEXPR20_ICE bool _Equal_rev_pred_unchecked( + _InIt1 _First1, _InIt2 _First2, const _InIt2 _Last2, _Pr _Pred) { // compare [_First1, ...) to [_First2, _Last2) using _Pred if constexpr (decltype(_Equal_memcmp_is_safe(_First1, _First2, _Pred))::value) { - const auto _First1_ch = reinterpret_cast(_First1); - const auto _First2_ch = reinterpret_cast(_First2); - const auto _Count = static_cast(reinterpret_cast(_Last2) - _First2_ch); - return _CSTD memcmp(_First1_ch, _First2_ch, _Count) == 0; +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + for (; _First2 != _Last2; ++_First1, (void) ++_First2) { + if (!_Pred(*_First1, *_First2)) { + return false; + } + } + + return true; + } else +#endif // __cpp_lib_is_constant_evaluated + { + const auto _First1_ch = reinterpret_cast(_First1); + const auto _First2_ch = reinterpret_cast(_First2); + const auto _Count = static_cast(reinterpret_cast(_Last2) - _First2_ch); + return _CSTD memcmp(_First1_ch, _First2_ch, _Count) == 0; + } } else { for (; _First2 != _Last2; ++_First1, (void) ++_First2) { if (!_Pred(*_First1, *_First2)) { @@ -714,8 +736,8 @@ bool _Equal_rev_pred_unchecked(const _InIt1 _First1, const _InIt2 _First2, const // FUNCTION TEMPLATE search #if _HAS_IF_CONSTEXPR template -_NODISCARD _FwdItHaystack search(_FwdItHaystack _First1, _FwdItHaystack _Last1, const _FwdItPat _First2, - const _FwdItPat _Last2, _Pr _Pred) { // find first [_First2, _Last2) satisfying _Pred +_NODISCARD _CONSTEXPR20_ICE _FwdItHaystack search(_FwdItHaystack _First1, _FwdItHaystack _Last1, + const _FwdItPat _First2, const _FwdItPat _Last2, _Pr _Pred) { // find first [_First2, _Last2) satisfying _Pred _Adl_verify_range(_First1, _Last1); _Adl_verify_range(_First2, _Last2); auto _UFirst1 = _Get_unwrapped(_First1); @@ -814,8 +836,9 @@ _NODISCARD _FwdItHaystack search(_ExPo&& _Exec, const _FwdItHaystack _First1, _F #endif // _HAS_CXX17 template -_NODISCARD _FwdItHaystack search(const _FwdItHaystack _First1, const _FwdItHaystack _Last1, const _FwdItPat _First2, - const _FwdItPat _Last2) { // find first [_First2, _Last2) match +_NODISCARD _CONSTEXPR20_ICE _FwdItHaystack search( + const _FwdItHaystack _First1, const _FwdItHaystack _Last1, const _FwdItPat _First2, const _FwdItPat _Last2) { + // find first [_First2, _Last2) match return _STD search(_First1, _Last1, _First2, _Last2, equal_to<>()); } @@ -829,7 +852,8 @@ _NODISCARD _FwdItHaystack search(_ExPo&& _Exec, const _FwdItHaystack _First1, co #endif // _HAS_CXX17 template -_NODISCARD _FwdItHaystack search(const _FwdItHaystack _First, const _FwdItHaystack _Last, const _Searcher& _Search) { +_NODISCARD _CONSTEXPR20 _FwdItHaystack search( + const _FwdItHaystack _First, const _FwdItHaystack _Last, const _Searcher& _Search) { // find _Search's pattern in [_First, _Last) return _Search(_First, _Last).first; } @@ -837,7 +861,8 @@ _NODISCARD _FwdItHaystack search(const _FwdItHaystack _First, const _FwdItHaysta // FUNCTION TEMPLATE search_n #if _HAS_IF_CONSTEXPR template -_NODISCARD _FwdIt search_n(const _FwdIt _First, _FwdIt _Last, const _Diff _Count_raw, const _Ty& _Val, _Pr _Pred) { +_NODISCARD _CONSTEXPR20 _FwdIt search_n( + const _FwdIt _First, _FwdIt _Last, const _Diff _Count_raw, const _Ty& _Val, _Pr _Pred) { // find first _Count * _Val satisfying _Pred const _Algorithm_int_t<_Diff> _Count = _Count_raw; if (_Count <= 0) { @@ -996,8 +1021,8 @@ _NODISCARD _FwdIt search_n(_ExPo&& _Exec, const _FwdIt _First, _FwdIt _Last, con #endif // _HAS_CXX17 template -_NODISCARD _FwdIt search_n( - const _FwdIt _First, const _FwdIt _Last, const _Diff _Count, const _Ty& _Val) { // find first _Count * _Val match +_NODISCARD _CONSTEXPR20 _FwdIt search_n(const _FwdIt _First, const _FwdIt _Last, const _Diff _Count, const _Ty& _Val) { + // find first _Count * _Val match return _STD search_n(_First, _Last, _Count, _Val, equal_to<>()); } @@ -1012,8 +1037,9 @@ _NODISCARD _FwdIt search_n(_ExPo&& _Exec, const _FwdIt _First, const _FwdIt _Las // FUNCTION TEMPLATE find_end #if _HAS_IF_CONSTEXPR template -_NODISCARD _FwdIt1 find_end(_FwdIt1 _First1, const _FwdIt1 _Last1, const _FwdIt2 _First2, const _FwdIt2 _Last2, - _Pr _Pred) { // find last [_First2, _Last2) satisfying _Pred +_NODISCARD _CONSTEXPR20 _FwdIt1 find_end( + _FwdIt1 _First1, const _FwdIt1 _Last1, const _FwdIt2 _First2, const _FwdIt2 _Last2, _Pr _Pred) { + // find last [_First2, _Last2) satisfying _Pred _Adl_verify_range(_First1, _Last1); _Adl_verify_range(_First2, _Last2); auto _UFirst1 = _Get_unwrapped(_First1); @@ -1182,7 +1208,8 @@ _NODISCARD _FwdIt1 find_end(_FwdIt1 _First1, const _FwdIt1 _Last1, const _FwdIt2 #endif // _HAS_IF_CONSTEXPR template -_NODISCARD _FwdIt1 find_end(_FwdIt1 const _First1, const _FwdIt1 _Last1, const _FwdIt2 _First2, const _FwdIt2 _Last2) { +_NODISCARD _CONSTEXPR20 _FwdIt1 find_end( + _FwdIt1 const _First1, const _FwdIt1 _Last1, const _FwdIt2 _First2, const _FwdIt2 _Last2) { // find last [_First2, _Last2) match return _STD find_end(_First1, _Last1, _First2, _Last2, equal_to<>()); } @@ -1201,8 +1228,9 @@ _NODISCARD _FwdIt1 find_end(_ExPo&& _Exec, _FwdIt1 _First1, _FwdIt1 _Last1, _Fwd // FUNCTION TEMPLATE find_first_of template -_NODISCARD _FwdIt1 find_first_of(_FwdIt1 _First1, const _FwdIt1 _Last1, const _FwdIt2 _First2, const _FwdIt2 _Last2, - _Pr _Pred) { // look for one of [_First2, _Last2) satisfying _Pred with element +_NODISCARD _CONSTEXPR20 _FwdIt1 find_first_of( + _FwdIt1 _First1, const _FwdIt1 _Last1, const _FwdIt2 _First2, const _FwdIt2 _Last2, _Pr _Pred) { + // look for one of [_First2, _Last2) satisfying _Pred with element _Adl_verify_range(_First1, _Last1); _Adl_verify_range(_First2, _Last2); auto _UFirst1 = _Get_unwrapped(_First1); @@ -1223,7 +1251,7 @@ _NODISCARD _FwdIt1 find_first_of(_FwdIt1 _First1, const _FwdIt1 _Last1, const _F } template -_NODISCARD _FwdIt1 find_first_of(const _FwdIt1 _First1, const _FwdIt1 _Last1, const _FwdIt2 _First2, +_NODISCARD _CONSTEXPR20 _FwdIt1 find_first_of(const _FwdIt1 _First1, const _FwdIt1 _Last1, const _FwdIt2 _First2, const _FwdIt2 _Last2) { // look for one of [_First2, _Last2) that matches element return _STD find_first_of(_First1, _Last1, _First2, _Last2, equal_to<>()); } @@ -1243,7 +1271,7 @@ _NODISCARD _FwdIt1 find_first_of(_ExPo&& _Exec, const _FwdIt1 _First1, const _Fw // FUNCTION TEMPLATE swap_ranges template -_FwdIt2 _Swap_ranges_unchecked(_FwdIt1 _First1, const _FwdIt1 _Last1, _FwdIt2 _First2) { +constexpr _FwdIt2 _Swap_ranges_unchecked(_FwdIt1 _First1, const _FwdIt1 _Last1, _FwdIt2 _First2) { // swap [_First1, _Last1) with [_First2, ...), no special optimization for (; _First1 != _Last1; ++_First1, (void) ++_First2) { _STD iter_swap(_First1, _First2); @@ -1254,15 +1282,26 @@ _FwdIt2 _Swap_ranges_unchecked(_FwdIt1 _First1, const _FwdIt1 _Last1, _FwdIt2 _F #if (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_CEE_PURE) && !defined(_M_HYBRID) template , int> = 0> -_Ty* _Swap_ranges_unchecked(_Ty* const _First1, _Ty* const _Last1, _Ty* const _First2) { +_CONSTEXPR20_ICE _Ty* _Swap_ranges_unchecked(_Ty* _First1, _Ty* const _Last1, _Ty* _First2) { // swap [_First1, _Last1) with [_First2, ...), trivially swappable optimization - __std_swap_ranges_trivially_swappable_noalias(_First1, _Last1, _First2); - return _First2 + (_Last1 - _First1); +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + for (; _First1 != _Last1; ++_First1, (void) ++_First2) { + _STD iter_swap(_First1, _First2); + } + + return _First2; + } else +#endif // __cpp_lib_is_constant_evaluated + { + __std_swap_ranges_trivially_swappable_noalias(_First1, _Last1, _First2); + return _First2 + (_Last1 - _First1); + } } #endif // (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_CEE_PURE) && !defined(_M_HYBRID) template -_FwdIt2 swap_ranges(const _FwdIt1 _First1, const _FwdIt1 _Last1, _FwdIt2 _First2) { +_CONSTEXPR20_ICE _FwdIt2 swap_ranges(const _FwdIt1 _First1, const _FwdIt1 _Last1, _FwdIt2 _First2) { // swap [_First1, _Last1) with [_First2, ...) _Adl_verify_range(_First1, _Last1); const auto _UFirst1 = _Get_unwrapped(_First1); @@ -1274,7 +1313,7 @@ _FwdIt2 swap_ranges(const _FwdIt1 _First1, const _FwdIt1 _Last1, _FwdIt2 _First2 #if _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_DestTy* swap_ranges(_FwdIt1 _First1, _FwdIt1 _Last1, _DestTy (&_Dest)[_DestSize]) { +_CONSTEXPR20_ICE _DestTy* swap_ranges(_FwdIt1 _First1, _FwdIt1 _Last1, _DestTy (&_Dest)[_DestSize]) { // swap [_First1, _Last1) with [_Dest, ...), array dest return _STD swap_ranges(_First1, _Last1, _Array_iterator<_DestTy, _DestSize>(_Dest))._Unwrapped(); } @@ -1300,7 +1339,7 @@ _DestTy* swap_ranges(_ExPo&&, _FwdIt1 _First1, _FwdIt1 _Last1, _DestTy (&_Dest)[ // FUNCTION TEMPLATE transform template -_OutIt transform(const _InIt _First, const _InIt _Last, _OutIt _Dest, _Fn _Func) { +_CONSTEXPR20 _OutIt transform(const _InIt _First, const _InIt _Last, _OutIt _Dest, _Fn _Func) { // transform [_First, _Last) with _Func _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); @@ -1316,7 +1355,7 @@ _OutIt transform(const _InIt _First, const _InIt _Last, _OutIt _Dest, _Fn _Func) #if _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_DestTy* transform(const _InIt _First, const _InIt _Last, _DestTy (&_Dest)[_DestSize], _Fn _Func) { +_CONSTEXPR20 _DestTy* transform(const _InIt _First, const _InIt _Last, _DestTy (&_Dest)[_DestSize], _Fn _Func) { // transform [_First, _Last) with _Func, array dest return _STD transform(_First, _Last, _Array_iterator<_DestTy, _DestSize>(_Dest), _Pass_fn(_Func))._Unwrapped(); } @@ -1341,7 +1380,8 @@ _DestTy* transform( #endif // _HAS_CXX17 template -_OutIt transform(const _InIt1 _First1, const _InIt1 _Last1, const _InIt2 _First2, _OutIt _Dest, _Fn _Func) { +_CONSTEXPR20 _OutIt transform( + const _InIt1 _First1, const _InIt1 _Last1, const _InIt2 _First2, _OutIt _Dest, _Fn _Func) { // transform [_First1, _Last1) and [_First2, ...) with _Func _Adl_verify_range(_First1, _Last1); auto _UFirst1 = _Get_unwrapped(_First1); @@ -1359,21 +1399,24 @@ _OutIt transform(const _InIt1 _First1, const _InIt1 _Last1, const _InIt2 _First2 #if _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_OutIt transform(const _InIt1 _First1, const _InIt1 _Last1, _RightTy (&_First2)[_RightSize], const _OutIt _Dest, - _Fn _Func) { // transform [_First1, _Last1) and [_First2, ...), array source +_CONSTEXPR20 _OutIt transform( + const _InIt1 _First1, const _InIt1 _Last1, _RightTy (&_First2)[_RightSize], const _OutIt _Dest, _Fn _Func) { + // transform [_First1, _Last1) and [_First2, ...), array source return _STD transform(_First1, _Last1, _Array_iterator<_RightTy, _RightSize>(_First2), _Dest, _Pass_fn(_Func)); } template -_DestTy* transform(const _InIt1 _First1, const _InIt1 _Last1, _InIt2 _First2, _DestTy (&_Dest)[_DestSize], - _Fn _Func) { // transform [_First1, _Last1) and [_First2, ...), array dest +_CONSTEXPR20 _DestTy* transform( + const _InIt1 _First1, const _InIt1 _Last1, _InIt2 _First2, _DestTy (&_Dest)[_DestSize], _Fn _Func) { + // transform [_First1, _Last1) and [_First2, ...), array dest return _STD transform(_First1, _Last1, _First2, _Array_iterator<_DestTy, _DestSize>(_Dest), _Pass_fn(_Func)) ._Unwrapped(); } template -_DestTy* transform(const _InIt1 _First1, const _InIt1 _Last1, _RightTy (&_First2)[_RightSize], - _DestTy (&_Dest)[_DestSize], _Fn _Func) { // transform [_First1, _Last1) and [_First2, ...), array source/dest +_CONSTEXPR20 _DestTy* transform(const _InIt1 _First1, const _InIt1 _Last1, _RightTy (&_First2)[_RightSize], + _DestTy (&_Dest)[_DestSize], _Fn _Func) { + // transform [_First1, _Last1) and [_First2, ...), array source/dest return _STD transform(_First1, _Last1, _Array_iterator<_RightTy, _RightSize>(_First2), _Array_iterator<_DestTy, _DestSize>(_Dest), _Pass_fn(_Func)) ._Unwrapped(); @@ -1419,7 +1462,7 @@ _DestTy* transform(_ExPo&& _Exec, const _FwdIt1 _First1, const _FwdIt1 _Last1, _ // FUNCTION TEMPLATE replace template -void replace(const _FwdIt _First, const _FwdIt _Last, const _Ty& _Oldval, const _Ty& _Newval) { +_CONSTEXPR20 void replace(const _FwdIt _First, const _FwdIt _Last, const _Ty& _Oldval, const _Ty& _Newval) { // replace each matching _Oldval with _Newval _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); @@ -1439,7 +1482,7 @@ void replace(_ExPo&& _Exec, const _FwdIt _First, const _FwdIt _Last, const _Ty& // FUNCTION TEMPLATE replace_if template -void replace_if(const _FwdIt _First, const _FwdIt _Last, _Pr _Pred, const _Ty& _Val) { +_CONSTEXPR20 void replace_if(const _FwdIt _First, const _FwdIt _Last, _Pr _Pred, const _Ty& _Val) { // replace each satisfying _Pred with _Val _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); @@ -1458,7 +1501,7 @@ void replace_if(_ExPo&& _Exec, _FwdIt _First, _FwdIt _Last, _Pr _Pred, const _Ty // FUNCTION TEMPLATE replace_copy template -_OutIt replace_copy(_InIt _First, _InIt _Last, _OutIt _Dest, const _Ty& _Oldval, const _Ty& _Newval) { +_CONSTEXPR20 _OutIt replace_copy(_InIt _First, _InIt _Last, _OutIt _Dest, const _Ty& _Oldval, const _Ty& _Newval) { // copy replacing each matching _Oldval with _Newval _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); @@ -1478,7 +1521,8 @@ _OutIt replace_copy(_InIt _First, _InIt _Last, _OutIt _Dest, const _Ty& _Oldval, #if _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_DestTy* replace_copy(_InIt _First, _InIt _Last, _DestTy (&_Dest)[_DestSize], const _Ty& _Oldval, const _Ty& _Newval) { +_CONSTEXPR20 _DestTy* replace_copy( + _InIt _First, _InIt _Last, _DestTy (&_Dest)[_DestSize], const _Ty& _Oldval, const _Ty& _Newval) { // copy replacing each matching _Oldval with _Newval, array dest return _STD replace_copy(_First, _Last, _Array_iterator<_DestTy, _DestSize>(_Dest), _Oldval, _Newval)._Unwrapped(); } @@ -1510,7 +1554,7 @@ _DestTy* replace_copy(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _DestTy (&_Dest)[_ // FUNCTION TEMPLATE replace_copy_if template -_OutIt replace_copy_if(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred, const _Ty& _Val) { +_CONSTEXPR20 _OutIt replace_copy_if(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred, const _Ty& _Val) { // copy replacing each satisfying _Pred with _Val _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); @@ -1530,7 +1574,8 @@ _OutIt replace_copy_if(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred, const #if _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_DestTy* replace_copy_if(_InIt _First, _InIt _Last, _DestTy (&_Dest)[_DestSize], _Pr _Pred, const _Ty& _Val) { +_CONSTEXPR20 _DestTy* replace_copy_if( + _InIt _First, _InIt _Last, _DestTy (&_Dest)[_DestSize], _Pr _Pred, const _Ty& _Val) { // copy replacing each satisfying _Pred with _Val, array dest return _STD replace_copy_if(_First, _Last, _Array_iterator<_DestTy, _DestSize>(_Dest), _Pass_fn(_Pred), _Val) ._Unwrapped(); @@ -1563,7 +1608,7 @@ _DestTy* replace_copy_if(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _DestTy (&_Dest // FUNCTION TEMPLATE generate template -void generate(_FwdIt _First, _FwdIt _Last, _Fn _Func) { // replace [_First, _Last) with _Func() +_CONSTEXPR20 void generate(_FwdIt _First, _FwdIt _Last, _Fn _Func) { // replace [_First, _Last) with _Func() _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); @@ -1583,7 +1628,8 @@ void generate(_ExPo&&, _FwdIt _First, _FwdIt _Last, _Fn _Func) noexcept /* termi // FUNCTION TEMPLATE generate_n template -_OutIt generate_n(_OutIt _Dest, const _Diff _Count_raw, _Fn _Func) { // replace [_Dest, _Dest + _Count) with _Func() +_CONSTEXPR20 _OutIt generate_n(_OutIt _Dest, const _Diff _Count_raw, _Fn _Func) { + // replace [_Dest, _Dest + _Count) with _Func() _Algorithm_int_t<_Diff> _Count = _Count_raw; if (0 < _Count) { auto _UDest = _Get_unwrapped_n(_Dest, _Count); @@ -1601,7 +1647,7 @@ _OutIt generate_n(_OutIt _Dest, const _Diff _Count_raw, _Fn _Func) { // replace #if _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_DestTy* generate_n(_DestTy (&_Dest)[_DestSize], const _Diff _Count_raw, _Fn _Func) { +_CONSTEXPR20 _DestTy* generate_n(_DestTy (&_Dest)[_DestSize], const _Diff _Count_raw, _Fn _Func) { // replace [_Dest, _Dest + _Count) with _Func(), array dest _Algorithm_int_t<_Diff> _Count = _Count_raw; _STL_VERIFY_ARRAY_SIZE(_Dest, _Count); @@ -1636,7 +1682,8 @@ _DestTy* generate_n(_ExPo&&, _DestTy (&_Dest)[_DestSize], const _Diff _Count_raw // FUNCTION TEMPLATE remove_copy template -_OutIt remove_copy(_InIt _First, _InIt _Last, _OutIt _Dest, const _Ty& _Val) { // copy omitting each matching _Val +_CONSTEXPR20 _OutIt remove_copy(_InIt _First, _InIt _Last, _OutIt _Dest, const _Ty& _Val) { + // copy omitting each matching _Val _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); @@ -1654,7 +1701,7 @@ _OutIt remove_copy(_InIt _First, _InIt _Last, _OutIt _Dest, const _Ty& _Val) { / #if _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_DestTy* remove_copy(_InIt _First, _InIt _Last, _DestTy (&_Dest)[_DestSize], const _Ty& _Val) { +_CONSTEXPR20 _DestTy* remove_copy(_InIt _First, _InIt _Last, _DestTy (&_Dest)[_DestSize], const _Ty& _Val) { // copy omitting each matching _Val, array dest return _STD remove_copy(_First, _Last, _Array_iterator<_DestTy, _DestSize>(_Dest), _Val)._Unwrapped(); } @@ -1685,7 +1732,7 @@ _DestTy* remove_copy( // FUNCTION TEMPLATE remove_copy_if template -_OutIt remove_copy_if(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred) { +_CONSTEXPR20 _OutIt remove_copy_if(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred) { // copy omitting each element satisfying _Pred _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); @@ -1704,7 +1751,7 @@ _OutIt remove_copy_if(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred) { #if _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_DestTy* remove_copy_if(_InIt _First, _InIt _Last, _DestTy (&_Dest)[_DestSize], _Pr _Pred) { +_CONSTEXPR20 _DestTy* remove_copy_if(_InIt _First, _InIt _Last, _DestTy (&_Dest)[_DestSize], _Pr _Pred) { // copy omitting each element satisfying _Pred, array dest return _STD remove_copy_if(_First, _Last, _Array_iterator<_DestTy, _DestSize>(_Dest), _Pass_fn(_Pred))._Unwrapped(); } @@ -1746,7 +1793,8 @@ _NODISCARD _FwdIt remove_if(_ExPo&& _Exec, _FwdIt _First, const _FwdIt _Last, _P // FUNCTION TEMPLATE unique template -_NODISCARD _FwdIt unique(_FwdIt _First, _FwdIt _Last, _Pr _Pred) { // remove each satisfying _Pred with previous +_NODISCARD _CONSTEXPR20 _FwdIt unique(_FwdIt _First, _FwdIt _Last, _Pr _Pred) { + // remove each satisfying _Pred with previous _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); @@ -1770,7 +1818,7 @@ _NODISCARD _FwdIt unique(_FwdIt _First, _FwdIt _Last, _Pr _Pred) { // remove eac } template -_NODISCARD _FwdIt unique(_FwdIt _First, _FwdIt _Last) { // remove each matching previous +_NODISCARD _CONSTEXPR20 _FwdIt unique(_FwdIt _First, _FwdIt _Last) { // remove each matching previous return _STD unique(_First, _Last, equal_to<>()); } @@ -1804,7 +1852,8 @@ _INLINE_VAR constexpr bool _Can_reread_dest = // clang-format on template -_OutIt unique_copy(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred) { // copy compressing pairs that match +_CONSTEXPR20 _OutIt unique_copy(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred) { + // copy compressing pairs that match _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); @@ -1937,20 +1986,20 @@ _OutIt unique_copy(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred) { // copy #if _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_DestTy* unique_copy(_InIt _First, _InIt _Last, _DestTy (&_Dest)[_DestSize], _Pr _Pred) { +_CONSTEXPR20 _DestTy* unique_copy(_InIt _First, _InIt _Last, _DestTy (&_Dest)[_DestSize], _Pr _Pred) { // copy compressing pairs that match, array dest return _STD unique_copy(_First, _Last, _Array_iterator<_DestTy, _DestSize>(_Dest), _Pass_fn(_Pred))._Unwrapped(); } #endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_OutIt unique_copy(_InIt _First, _InIt _Last, _OutIt _Dest) { // copy compressing pairs that match +_CONSTEXPR20 _OutIt unique_copy(_InIt _First, _InIt _Last, _OutIt _Dest) { // copy compressing pairs that match return _STD unique_copy(_First, _Last, _Dest, equal_to<>()); } #if _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_DestTy* unique_copy(_InIt _First, _InIt _Last, _DestTy (&_Dest)[_DestSize]) { +_CONSTEXPR20 _DestTy* unique_copy(_InIt _First, _InIt _Last, _DestTy (&_Dest)[_DestSize]) { // copy compressing pairs that match, array dest return _STD unique_copy(_First, _Last, _Dest, equal_to<>()); } @@ -2000,7 +2049,7 @@ _DestTy* unique_copy(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _DestTy (&_Dest)[_D // FUNCTION TEMPLATE reverse_copy template -_OutIt reverse_copy(_BidIt _First, _BidIt _Last, _OutIt _Dest) { +_CONSTEXPR20 _OutIt reverse_copy(_BidIt _First, _BidIt _Last, _OutIt _Dest) { // copy reversing elements in [_First, _Last) _Adl_verify_range(_First, _Last); const auto _UFirst = _Get_unwrapped(_First); @@ -2016,7 +2065,7 @@ _OutIt reverse_copy(_BidIt _First, _BidIt _Last, _OutIt _Dest) { #if _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_DestTy* reverse_copy(_BidIt _First, _BidIt _Last, _DestTy (&_Dest)[_DestSize]) { +_CONSTEXPR20 _DestTy* reverse_copy(_BidIt _First, _BidIt _Last, _DestTy (&_Dest)[_DestSize]) { // copy reversing elements in [_First, _Last), array dest return _STD reverse_copy(_First, _Last, _Array_iterator<_DestTy, _DestSize>(_Dest))._Unwrapped(); } @@ -2043,7 +2092,8 @@ _DestTy* reverse_copy(_ExPo&&, _BidIt _First, _BidIt _Last, _DestTy (&_Dest)[_De // FUNCTION TEMPLATE rotate_copy template -_OutIt rotate_copy(_FwdIt _First, _FwdIt _Mid, _FwdIt _Last, _OutIt _Dest) { // copy rotating [_First, _Last) +_CONSTEXPR20_ICE _OutIt rotate_copy(_FwdIt _First, _FwdIt _Mid, _FwdIt _Last, _OutIt _Dest) { + // copy rotating [_First, _Last) _Adl_verify_range(_First, _Mid); _Adl_verify_range(_Mid, _Last); const auto _UFirst = _Get_unwrapped(_First); @@ -2346,7 +2396,7 @@ _FwdIt shift_right(_ExPo&&, _FwdIt _First, _FwdIt _Last, _Iter_diff_t<_FwdIt> _P // FUNCTION TEMPLATE partition #if _HAS_IF_CONSTEXPR template -_FwdIt partition(_FwdIt _First, const _FwdIt _Last, _Pr _Pred) { +_CONSTEXPR20 _FwdIt partition(_FwdIt _First, const _FwdIt _Last, _Pr _Pred) { // move elements satisfying _Pred to beginning of sequence _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); @@ -2644,7 +2694,8 @@ _BidIt stable_partition(_ExPo&&, _BidIt _First, _BidIt _Last, _Pr _Pred) noexcep // FUNCTION TEMPLATE push_heap template -void _Push_heap_by_index(_RanIt _First, _Iter_diff_t<_RanIt> _Hole, _Iter_diff_t<_RanIt> _Top, _Ty&& _Val, _Pr _Pred) { +_CONSTEXPR20 void _Push_heap_by_index( + _RanIt _First, _Iter_diff_t<_RanIt> _Hole, _Iter_diff_t<_RanIt> _Top, _Ty&& _Val, _Pr _Pred) { // percolate _Hole to _Top or where _Val belongs, using _Pred using _Diff = _Iter_diff_t<_RanIt>; for (_Diff _Idx = (_Hole - 1) >> 1; // shift for codegen @@ -2659,7 +2710,7 @@ void _Push_heap_by_index(_RanIt _First, _Iter_diff_t<_RanIt> _Hole, _Iter_diff_t } template -void push_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) { +_CONSTEXPR20 void push_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) { // push *(_Last - 1) onto heap at [_First, _Last - 1), using _Pred _Adl_verify_range(_First, _Last); const auto _UFirst = _Get_unwrapped(_First); @@ -2673,15 +2724,17 @@ void push_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) { } template -void push_heap(_RanIt _First, _RanIt _Last) { // push *(_Last - 1) onto heap at [_First, _Last - 1), using operator< +_CONSTEXPR20 void push_heap(_RanIt _First, _RanIt _Last) { + // push *(_Last - 1) onto heap at [_First, _Last - 1), using operator< _STD push_heap(_First, _Last, less<>()); } // FUNCTION TEMPLATE pop_heap template -void _Pop_heap_hole_by_index(_RanIt _First, _Iter_diff_t<_RanIt> _Hole, _Iter_diff_t<_RanIt> _Bottom, _Ty&& _Val, - _Pr _Pred) { // percolate _Hole to _Bottom, then push _Val, using _Pred - // precondition: _Bottom != 0 +_CONSTEXPR20 void _Pop_heap_hole_by_index( + _RanIt _First, _Iter_diff_t<_RanIt> _Hole, _Iter_diff_t<_RanIt> _Bottom, _Ty&& _Val, _Pr _Pred) { + // percolate _Hole to _Bottom, then push _Val, using _Pred + _STL_INTERNAL_CHECK(_Bottom != 0); using _Diff = _Iter_diff_t<_RanIt>; const _Diff _Top = _Hole; _Diff _Idx = _Hole; @@ -2707,7 +2760,7 @@ void _Pop_heap_hole_by_index(_RanIt _First, _Iter_diff_t<_RanIt> _Hole, _Iter_di } template -void _Pop_heap_hole_unchecked(_RanIt _First, _RanIt _Last, _RanIt _Dest, _Ty&& _Val, _Pr _Pred) { +_CONSTEXPR20 void _Pop_heap_hole_unchecked(_RanIt _First, _RanIt _Last, _RanIt _Dest, _Ty&& _Val, _Pr _Pred) { // pop *_First to *_Dest and reheap, using _Pred // precondition: _First != _Last // precondition: _First != _Dest @@ -2717,7 +2770,7 @@ void _Pop_heap_hole_unchecked(_RanIt _First, _RanIt _Last, _RanIt _Dest, _Ty&& _ } template -void _Pop_heap_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) { +_CONSTEXPR20 void _Pop_heap_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) { // pop *_First to *(_Last - 1) and reheap, using _Pred if (2 <= _Last - _First) { --_Last; @@ -2727,19 +2780,21 @@ void _Pop_heap_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) { } template -void pop_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) { // pop *_First to *(_Last - 1) and reheap, using _Pred +_CONSTEXPR20 void pop_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) { + // pop *_First to *(_Last - 1) and reheap, using _Pred _Adl_verify_range(_First, _Last); _Pop_heap_unchecked(_Get_unwrapped(_First), _Get_unwrapped(_Last), _Pass_fn(_Pred)); } template -void pop_heap(_RanIt _First, _RanIt _Last) { // pop *_First to *(_Last - 1) and reheap, using operator< +_CONSTEXPR20 void pop_heap(_RanIt _First, _RanIt _Last) { + // pop *_First to *(_Last - 1) and reheap, using operator< _STD pop_heap(_First, _Last, less<>()); } // FUNCTION TEMPLATE make_heap template -void _Make_heap_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) { +_CONSTEXPR20 void _Make_heap_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) { // make nontrivial [_First, _Last) into a heap, using _Pred using _Diff = _Iter_diff_t<_RanIt>; _Diff _Bottom = _Last - _First; @@ -2752,19 +2807,19 @@ void _Make_heap_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) { } template -void make_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) { // make [_First, _Last) into a heap, using _Pred +_CONSTEXPR20 void make_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) { // make [_First, _Last) into a heap, using _Pred _Adl_verify_range(_First, _Last); _Make_heap_unchecked(_Get_unwrapped(_First), _Get_unwrapped(_Last), _Pass_fn(_Pred)); } template -void make_heap(_RanIt _First, _RanIt _Last) { // make [_First, _Last) into a heap, using operator< +_CONSTEXPR20 void make_heap(_RanIt _First, _RanIt _Last) { // make [_First, _Last) into a heap, using operator< _STD make_heap(_First, _Last, less<>()); } // FUNCTION TEMPLATES is_heap AND is_heap_until template -_RanIt _Is_heap_until_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) { +_CONSTEXPR20 _RanIt _Is_heap_until_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) { // find extent of range that is a heap ordered by _Pred using _Diff = _Iter_diff_t<_RanIt>; const _Diff _Size = _Last - _First; @@ -2778,7 +2833,7 @@ _RanIt _Is_heap_until_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) { } template -_NODISCARD _RanIt is_heap_until(_RanIt _First, _RanIt _Last, _Pr _Pred) { +_NODISCARD _CONSTEXPR20 _RanIt is_heap_until(_RanIt _First, _RanIt _Last, _Pr _Pred) { // find extent of range that is a heap ordered by _Pred _Adl_verify_range(_First, _Last); _Seek_wrapped(_First, _Is_heap_until_unchecked(_Get_unwrapped(_First), _Get_unwrapped(_Last), _Pass_fn(_Pred))); @@ -2786,7 +2841,8 @@ _NODISCARD _RanIt is_heap_until(_RanIt _First, _RanIt _Last, _Pr _Pred) { } template -_NODISCARD bool is_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) { // test if range is a heap ordered by _Pred +_NODISCARD _CONSTEXPR20 bool is_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) { + // test if range is a heap ordered by _Pred _Adl_verify_range(_First, _Last); const auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); @@ -2794,13 +2850,13 @@ _NODISCARD bool is_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) { // test if ran } template -_NODISCARD _RanIt is_heap_until(_RanIt _First, _RanIt _Last) { +_NODISCARD _CONSTEXPR20 _RanIt is_heap_until(_RanIt _First, _RanIt _Last) { // find extent of range that is a heap ordered by operator< return _STD is_heap_until(_First, _Last, less<>()); } template -_NODISCARD bool is_heap(_RanIt _First, _RanIt _Last) { // test if range is a heap ordered by operator< +_NODISCARD _CONSTEXPR20 bool is_heap(_RanIt _First, _RanIt _Last) { // test if range is a heap ordered by operator< return _STD is_heap(_First, _Last, less<>()); } @@ -2829,14 +2885,15 @@ _NODISCARD bool is_heap(_ExPo&& _Exec, _RanIt _First, _RanIt _Last) noexcept /* // FUNCTION TEMPLATE sort_heap template -void _Sort_heap_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) { // order heap by repeatedly popping, using _Pred +_CONSTEXPR20 void _Sort_heap_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) { + // order heap by repeatedly popping, using _Pred for (; 2 <= _Last - _First; --_Last) { _Pop_heap_unchecked(_First, _Last, _Pred); } } template -void sort_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) { // order heap by repeatedly popping, using _Pred +_CONSTEXPR20 void sort_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) { // order heap by repeatedly popping, using _Pred _Adl_verify_range(_First, _Last); const auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); @@ -2850,20 +2907,13 @@ void sort_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) { // order heap by repeat } template -void sort_heap(_RanIt _First, _RanIt _Last) { // order heap by repeatedly popping, using operator< +_CONSTEXPR20 void sort_heap(_RanIt _First, _RanIt _Last) { // order heap by repeatedly popping, using operator< _STD sort_heap(_First, _Last, less<>()); } -// FUNCTION TEMPLATE lower_bound -template -_NODISCARD _FwdIt lower_bound(_FwdIt _First, _FwdIt _Last, const _Ty& _Val) { - // find first element not before _Val, using operator< - return _STD lower_bound(_First, _Last, _Val, less<>()); -} - // FUNCTION TEMPLATE upper_bound template -_NODISCARD _FwdIt upper_bound(_FwdIt _First, _FwdIt _Last, const _Ty& _Val, _Pr _Pred) { +_NODISCARD _CONSTEXPR20 _FwdIt upper_bound(_FwdIt _First, _FwdIt _Last, const _Ty& _Val, _Pr _Pred) { // find first element that _Val is before, using _Pred _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); @@ -2885,14 +2935,14 @@ _NODISCARD _FwdIt upper_bound(_FwdIt _First, _FwdIt _Last, const _Ty& _Val, _Pr } template -_NODISCARD _FwdIt upper_bound(_FwdIt _First, _FwdIt _Last, const _Ty& _Val) { +_NODISCARD _CONSTEXPR20 _FwdIt upper_bound(_FwdIt _First, _FwdIt _Last, const _Ty& _Val) { // find first element that _Val is before, using operator< return _STD upper_bound(_First, _Last, _Val, less<>()); } // FUNCTION TEMPLATE equal_range template -_NODISCARD pair<_FwdIt, _FwdIt> equal_range(_FwdIt _First, _FwdIt _Last, const _Ty& _Val, _Pr _Pred) { +_NODISCARD _CONSTEXPR20 pair<_FwdIt, _FwdIt> equal_range(_FwdIt _First, _FwdIt _Last, const _Ty& _Val, _Pr _Pred) { // find range equivalent to _Val, using _Pred _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); @@ -2929,14 +2979,14 @@ _NODISCARD pair<_FwdIt, _FwdIt> equal_range(_FwdIt _First, _FwdIt _Last, const _ } template -_NODISCARD pair<_FwdIt, _FwdIt> equal_range(_FwdIt _First, _FwdIt _Last, const _Ty& _Val) { +_NODISCARD _CONSTEXPR20 pair<_FwdIt, _FwdIt> equal_range(_FwdIt _First, _FwdIt _Last, const _Ty& _Val) { // find range equivalent to _Val, using operator< return _STD equal_range(_First, _Last, _Val, less<>()); } // FUNCTION TEMPLATE binary_search template -_NODISCARD bool binary_search(_FwdIt _First, _FwdIt _Last, const _Ty& _Val, _Pr _Pred) { +_NODISCARD _CONSTEXPR20 bool binary_search(_FwdIt _First, _FwdIt _Last, const _Ty& _Val, _Pr _Pred) { // test if _Val equivalent to some element, using _Pred _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); @@ -2946,34 +2996,34 @@ _NODISCARD bool binary_search(_FwdIt _First, _FwdIt _Last, const _Ty& _Val, _Pr } template -_NODISCARD bool binary_search(_FwdIt _First, _FwdIt _Last, const _Ty& _Val) { +_NODISCARD _CONSTEXPR20 bool binary_search(_FwdIt _First, _FwdIt _Last, const _Ty& _Val) { // test if _Val equivalent to some element, using operator< return _STD binary_search(_First, _Last, _Val, less<>()); } // FUNCTION TEMPLATE merge -inline _Distance_unknown _Idl_dist_add(_Distance_unknown, _Distance_unknown) { +constexpr _Distance_unknown _Idl_dist_add(_Distance_unknown, _Distance_unknown) { // combine _Idl_distance results (both unknown) return {}; } template -_Distance_unknown _Idl_dist_add(_Diff1, _Distance_unknown) { // combine _Idl_distance results (right unknown) +constexpr _Distance_unknown _Idl_dist_add(_Diff1, _Distance_unknown) { // combine _Idl_distance results (right unknown) return {}; } template -_Distance_unknown _Idl_dist_add(_Distance_unknown, _Diff2) { // combine _Idl_distance results (left unknown) +constexpr _Distance_unknown _Idl_dist_add(_Distance_unknown, _Diff2) { // combine _Idl_distance results (left unknown) return {}; } template -auto _Idl_dist_add(_Diff1 _Lhs, _Diff2 _Rhs) { // combine _Idl_distance results (both known) +constexpr auto _Idl_dist_add(_Diff1 _Lhs, _Diff2 _Rhs) { // combine _Idl_distance results (both known) return _Lhs + _Rhs; } template -_OutIt merge(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest, _Pr _Pred) { +_CONSTEXPR20_ICE _OutIt merge(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest, _Pr _Pred) { // copy merging ranges, both using _Pred _Adl_verify_range(_First1, _Last1); _Adl_verify_range(_First2, _Last2); @@ -3015,7 +3065,8 @@ _OutIt merge(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutI #if _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_DestTy* merge(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _DestTy (&_Dest)[_DestSize], _Pr _Pred) { +_CONSTEXPR20_ICE _DestTy* merge( + _InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _DestTy (&_Dest)[_DestSize], _Pr _Pred) { // copy merging ranges, both using _Pred, array dest return _STD merge(_First1, _Last1, _First2, _Last2, _Array_iterator<_DestTy, _DestSize>(_Dest), _Pass_fn(_Pred)) ._Unwrapped(); @@ -3023,14 +3074,15 @@ _DestTy* merge(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _De #endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_OutIt merge(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest) { +_CONSTEXPR20_ICE _OutIt merge(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest) { // copy merging ranges, both using operator< return _STD merge(_First1, _Last1, _First2, _Last2, _Dest, less<>()); } #if _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_DestTy* merge(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _DestTy (&_Dest)[_DestSize]) { +_CONSTEXPR20_ICE _DestTy* merge( + _InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _DestTy (&_Dest)[_DestSize]) { // copy merging ranges, both using operator<, array dest return _STD merge(_First1, _Last1, _First2, _Last2, _Dest, less<>()); } @@ -3351,7 +3403,7 @@ void inplace_merge(_ExPo&&, _BidIt _First, _BidIt _Mid, _BidIt _Last) noexcept / // FUNCTION TEMPLATE sort template -_BidIt _Insertion_sort_unchecked(_BidIt _First, const _BidIt _Last, _Pr _Pred) { +_CONSTEXPR20_ICE _BidIt _Insertion_sort_unchecked(_BidIt _First, const _BidIt _Last, _Pr _Pred) { // insertion sort [_First, _Last), using _Pred if (_First != _Last) { for (_BidIt _Next = _First; ++_Next != _Last;) { // order next element @@ -3375,7 +3427,8 @@ _BidIt _Insertion_sort_unchecked(_BidIt _First, const _BidIt _Last, _Pr _Pred) { } template -void _Med3_unchecked(_RanIt _First, _RanIt _Mid, _RanIt _Last, _Pr _Pred) { // sort median of three elements to middle +_CONSTEXPR20 void _Med3_unchecked(_RanIt _First, _RanIt _Mid, _RanIt _Last, _Pr _Pred) { + // sort median of three elements to middle if (_DEBUG_LT_PRED(_Pred, *_Mid, *_First)) { _STD iter_swap(_Mid, _First); } @@ -3390,7 +3443,8 @@ void _Med3_unchecked(_RanIt _First, _RanIt _Mid, _RanIt _Last, _Pr _Pred) { // s } template -void _Guess_median_unchecked(_RanIt _First, _RanIt _Mid, _RanIt _Last, _Pr _Pred) { // sort median element to middle +_CONSTEXPR20 void _Guess_median_unchecked(_RanIt _First, _RanIt _Mid, _RanIt _Last, _Pr _Pred) { + // sort median element to middle using _Diff = _Iter_diff_t<_RanIt>; const _Diff _Count = _Last - _First; if (40 < _Count) { // Tukey's ninther @@ -3406,7 +3460,7 @@ void _Guess_median_unchecked(_RanIt _First, _RanIt _Mid, _RanIt _Last, _Pr _Pred } template -pair<_RanIt, _RanIt> _Partition_by_median_guess_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) { +_CONSTEXPR20 pair<_RanIt, _RanIt> _Partition_by_median_guess_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) { // partition [_First, _Last), using _Pred _RanIt _Mid = _First + ((_Last - _First) >> 1); // shift for codegen _Guess_median_unchecked(_First, _Mid, _Last - 1, _Pred); @@ -3473,9 +3527,9 @@ pair<_RanIt, _RanIt> _Partition_by_median_guess_unchecked(_RanIt _First, _RanIt } template -void _Sort_unchecked(_RanIt _First, _RanIt _Last, _Iter_diff_t<_RanIt> _Ideal, _Pr _Pred) { +_CONSTEXPR20_ICE void _Sort_unchecked(_RanIt _First, _RanIt _Last, _Iter_diff_t<_RanIt> _Ideal, _Pr _Pred) { // order [_First, _Last), using _Pred - _Iter_diff_t<_RanIt> _Count; + _Iter_diff_t<_RanIt> _Count = 0; while (_ISORT_MAX < (_Count = _Last - _First) && 0 < _Ideal) { // divide and conquer by quicksort auto _Mid = _Partition_by_median_guess_unchecked(_First, _Last, _Pred); @@ -3499,7 +3553,7 @@ void _Sort_unchecked(_RanIt _First, _RanIt _Last, _Iter_diff_t<_RanIt> _Ideal, _ } template -void sort(const _RanIt _First, const _RanIt _Last, _Pr _Pred) { // order [_First, _Last), using _Pred +_CONSTEXPR20_ICE void sort(const _RanIt _First, const _RanIt _Last, _Pr _Pred) { // order [_First, _Last), using _Pred _Adl_verify_range(_First, _Last); const auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); @@ -3507,7 +3561,7 @@ void sort(const _RanIt _First, const _RanIt _Last, _Pr _Pred) { // order [_First } template -void sort(const _RanIt _First, const _RanIt _Last) { // order [_First, _Last), using operator< +_CONSTEXPR20_ICE void sort(const _RanIt _First, const _RanIt _Last) { // order [_First, _Last), using operator< _STD sort(_First, _Last, less<>()); } @@ -3722,7 +3776,7 @@ void stable_sort(_ExPo&& _Exec, _BidIt _First, _BidIt _Last) noexcept /* termina // FUNCTION TEMPLATE partial_sort template -void partial_sort(_RanIt _First, _RanIt _Mid, _RanIt _Last, _Pr _Pred) { +_CONSTEXPR20 void partial_sort(_RanIt _First, _RanIt _Mid, _RanIt _Last, _Pr _Pred) { // order [_First, _Last) up to _Mid, using _Pred _Adl_verify_range(_First, _Mid); _Adl_verify_range(_Mid, _Last); @@ -3746,7 +3800,8 @@ void partial_sort(_RanIt _First, _RanIt _Mid, _RanIt _Last, _Pr _Pred) { } template -void partial_sort(_RanIt _First, _RanIt _Mid, _RanIt _Last) { // order [_First, _Last) up to _Mid, using operator< +_CONSTEXPR20 void partial_sort(_RanIt _First, _RanIt _Mid, _RanIt _Last) { + // order [_First, _Last) up to _Mid, using operator< _STD partial_sort(_First, _Mid, _Last, less<>()); } @@ -3768,7 +3823,7 @@ void partial_sort(_ExPo&&, _RanIt _First, _RanIt _Mid, _RanIt _Last) noexcept /* // FUNCTION TEMPLATE partial_sort_copy template -_RanIt partial_sort_copy(_InIt _First1, _InIt _Last1, _RanIt _First2, _RanIt _Last2, _Pr _Pred) { +_CONSTEXPR20 _RanIt partial_sort_copy(_InIt _First1, _InIt _Last1, _RanIt _First2, _RanIt _Last2, _Pr _Pred) { // copy [_First1, _Last1) into [_First2, _Last2) using _Pred _Adl_verify_range(_First1, _Last1); _Adl_verify_range(_First2, _Last2); @@ -3800,7 +3855,7 @@ _RanIt partial_sort_copy(_InIt _First1, _InIt _Last1, _RanIt _First2, _RanIt _La } template -_RanIt partial_sort_copy(_InIt _First1, _InIt _Last1, _RanIt _First2, _RanIt _Last2) { +_CONSTEXPR20 _RanIt partial_sort_copy(_InIt _First1, _InIt _Last1, _RanIt _First2, _RanIt _Last2) { // copy [_First1, _Last1) into [_First2, _Last2), using operator< return _STD partial_sort_copy(_First1, _Last1, _First2, _Last2, less<>()); } @@ -3827,7 +3882,8 @@ _RanIt partial_sort_copy( // FUNCTION TEMPLATE nth_element template -void nth_element(_RanIt _First, _RanIt _Nth, _RanIt _Last, _Pr _Pred) { // order Nth element, using _Pred +_CONSTEXPR20_ICE void nth_element(_RanIt _First, _RanIt _Nth, _RanIt _Last, _Pr _Pred) { + // order Nth element, using _Pred _Adl_verify_range(_First, _Nth); _Adl_verify_range(_Nth, _Last); auto _UFirst = _Get_unwrapped(_First); @@ -3853,7 +3909,7 @@ void nth_element(_RanIt _First, _RanIt _Nth, _RanIt _Last, _Pr _Pred) { // order } template -void nth_element(_RanIt _First, _RanIt _Nth, _RanIt _Last) { // order Nth element, using operator< +_CONSTEXPR20_ICE void nth_element(_RanIt _First, _RanIt _Nth, _RanIt _Last) { // order Nth element, using operator< _STD nth_element(_First, _Nth, _Last, less<>()); } @@ -3875,7 +3931,7 @@ void nth_element(_ExPo&&, _RanIt _First, _RanIt _Nth, _RanIt _Last) noexcept /* // FUNCTION TEMPLATE includes template -_NODISCARD bool includes(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _Pr _Pred) { +_NODISCARD _CONSTEXPR20 bool includes(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _Pr _Pred) { // test if every element in sorted [_First2, _Last2) is in sorted [_First1, _Last1), using _Pred _Adl_verify_range(_First1, _Last1); _Adl_verify_range(_First2, _Last2); @@ -3899,7 +3955,7 @@ _NODISCARD bool includes(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _ } template -_NODISCARD bool includes(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2) { +_NODISCARD _CONSTEXPR20 bool includes(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2) { // test if every element in sorted [_First2, _Last2) is in sorted [_First1, _Last1), using operator< return _STD includes(_First1, _Last1, _First2, _Last2, less<>()); } @@ -3929,7 +3985,8 @@ _NODISCARD bool includes( // FUNCTION TEMPLATE set_union template -_OutIt set_union(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest, _Pr _Pred) { +_CONSTEXPR20_ICE _OutIt set_union( + _InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest, _Pr _Pred) { // OR sets [_First1, _Last1) and [_First2, _Last2), using _Pred _Adl_verify_range(_First1, _Last1); _Adl_verify_range(_First2, _Last2); @@ -3961,7 +4018,7 @@ _OutIt set_union(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _ #if _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_DestTy* set_union( +_CONSTEXPR20_ICE _DestTy* set_union( _InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _DestTy (&_Dest)[_DestSize], _Pr _Pred) { // OR sets [_First1, _Last1) and [_First2, _Last2), array dest return _STD set_union(_First1, _Last1, _First2, _Last2, _Array_iterator<_DestTy, _DestSize>(_Dest), _Pass_fn(_Pred)) @@ -3970,14 +4027,15 @@ _DestTy* set_union( #endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_OutIt set_union(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest) { +_CONSTEXPR20_ICE _OutIt set_union(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest) { // OR sets [_First1, _Last1) and [_First2, _Last2), using operator< return _STD set_union(_First1, _Last1, _First2, _Last2, _Dest, less<>()); } #if _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_DestTy* set_union(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _DestTy (&_Dest)[_DestSize]) { +_CONSTEXPR20_ICE _DestTy* set_union( + _InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _DestTy (&_Dest)[_DestSize]) { // OR sets [_First1, _Last1) and [_First2, _Last2), array dest return _STD set_union(_First1, _Last1, _First2, _Last2, _Dest, less<>()); } @@ -4035,7 +4093,8 @@ _DestTy* set_union(_ExPo&&, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _F // FUNCTION TEMPLATE set_intersection template -_OutIt set_intersection(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest, _Pr _Pred) { +_CONSTEXPR20 _OutIt set_intersection( + _InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest, _Pr _Pred) { // AND sets [_First1, _Last1) and [_First2, _Last2), using _Pred _Adl_verify_range(_First1, _Last1); _Adl_verify_range(_First2, _Last2); @@ -4065,7 +4124,7 @@ _OutIt set_intersection(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _L #if _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_DestTy* set_intersection( +_CONSTEXPR20 _DestTy* set_intersection( _InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _DestTy (&_Dest)[_DestSize], _Pr _Pred) { // AND sets [_First1, _Last1) and [_First2, _Last2), array dest return _STD set_intersection( @@ -4075,14 +4134,15 @@ _DestTy* set_intersection( #endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_OutIt set_intersection(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest) { +_CONSTEXPR20 _OutIt set_intersection(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest) { // AND sets [_First1, _Last1) and [_First2, _Last2), using operator< return _STD set_intersection(_First1, _Last1, _First2, _Last2, _Dest, less<>()); } #if _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_DestTy* set_intersection(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _DestTy (&_Dest)[_DestSize]) { +_CONSTEXPR20 _DestTy* set_intersection( + _InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _DestTy (&_Dest)[_DestSize]) { // AND sets [_First1, _Last1) and [_First2, _Last2), array dest return _STD set_intersection(_First1, _Last1, _First2, _Last2, _Dest, less<>()); } @@ -4125,7 +4185,8 @@ _DestTy* set_intersection(_ExPo&& _Exec, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt // FUNCTION TEMPLATE set_difference template -_OutIt set_difference(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest, _Pr _Pred) { +_CONSTEXPR20_ICE _OutIt set_difference( + _InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest, _Pr _Pred) { // take set [_First2, _Last2) from [_First1, _Last1), using _Pred _Adl_verify_range(_First1, _Last1); _Adl_verify_range(_First2, _Last2); @@ -4156,7 +4217,7 @@ _OutIt set_difference(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Las #if _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_DestTy* set_difference( +_CONSTEXPR20_ICE _DestTy* set_difference( _InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _DestTy (&_Dest)[_DestSize], _Pr _Pred) { // take set [_First2, _Last2) from [_First1, _Last1), array dest return _STD set_difference( @@ -4166,14 +4227,15 @@ _DestTy* set_difference( #endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_OutIt set_difference(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest) { +_CONSTEXPR20_ICE _OutIt set_difference(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest) { // take set [_First2, _Last2) from [_First1, _Last1), using operator< return _STD set_difference(_First1, _Last1, _First2, _Last2, _Dest, less<>()); } #if _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_DestTy* set_difference(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _DestTy (&_Dest)[_DestSize]) { +_CONSTEXPR20_ICE _DestTy* set_difference( + _InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _DestTy (&_Dest)[_DestSize]) { // take set [_First2, _Last2) from [_First1, _Last1), array dest return _STD set_difference(_First1, _Last1, _First2, _Last2, _Dest, less<>()); } @@ -4216,7 +4278,8 @@ _DestTy* set_difference(_ExPo&& _Exec, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 // FUNCTION TEMPLATE set_symmetric_difference template -_OutIt set_symmetric_difference(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest, _Pr _Pred) { +_CONSTEXPR20_ICE _OutIt set_symmetric_difference( + _InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest, _Pr _Pred) { // XOR sets [_First1, _Last1) and [_First2, _Last2), using _Pred _Adl_verify_range(_First1, _Last1); _Adl_verify_range(_First2, _Last2); @@ -4249,7 +4312,7 @@ _OutIt set_symmetric_difference(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _ #if _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_DestTy* set_symmetric_difference( +_CONSTEXPR20_ICE _DestTy* set_symmetric_difference( _InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _DestTy (&_Dest)[_DestSize], _Pr _Pred) { // XOR sets [_First1, _Last1) and [_First2, _Last2), array dest return _STD set_symmetric_difference( @@ -4259,14 +4322,15 @@ _DestTy* set_symmetric_difference( #endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_OutIt set_symmetric_difference(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest) { +_CONSTEXPR20_ICE _OutIt set_symmetric_difference( + _InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest) { // XOR sets [_First1, _Last1) and [_First2, _Last2), using operator< return _STD set_symmetric_difference(_First1, _Last1, _First2, _Last2, _Dest, less<>()); } #if _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_DestTy* set_symmetric_difference( +_CONSTEXPR20_ICE _DestTy* set_symmetric_difference( _InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _DestTy (&_Dest)[_DestSize]) { // XOR sets [_First1, _Last1) and [_First2, _Last2), array dest return _STD set_symmetric_difference(_First1, _Last1, _First2, _Last2, _Dest, less<>()); @@ -4592,7 +4656,8 @@ _NODISCARD constexpr pair<_Ty, _Ty> minmax(initializer_list<_Ty> _Ilist) { // FUNCTION TEMPLATE next_permutation template -bool next_permutation(_BidIt _First, _BidIt _Last, _Pr _Pred) { // permute and test for pure ascending, using _Pred +_CONSTEXPR20 bool next_permutation(_BidIt _First, _BidIt _Last, _Pr _Pred) { + // permute and test for pure ascending, using _Pred _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); @@ -4622,13 +4687,14 @@ bool next_permutation(_BidIt _First, _BidIt _Last, _Pr _Pred) { // permute and t } template -bool next_permutation(_BidIt _First, _BidIt _Last) { // permute and test for pure ascending, using operator< +_CONSTEXPR20 bool next_permutation(_BidIt _First, _BidIt _Last) { + // permute and test for pure ascending, using operator< return _STD next_permutation(_First, _Last, less<>()); } // FUNCTION TEMPLATE prev_permutation template -bool prev_permutation(_BidIt _First, _BidIt _Last, _Pr _Pred) { +_CONSTEXPR20 bool prev_permutation(_BidIt _First, _BidIt _Last, _Pr _Pred) { // reverse permute and test for pure descending, using _Pred _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); @@ -4659,13 +4725,14 @@ bool prev_permutation(_BidIt _First, _BidIt _Last, _Pr _Pred) { } template -bool prev_permutation(_BidIt _First, _BidIt _Last) { // reverse permute and test for pure descending, using operator< +_CONSTEXPR20 bool prev_permutation(_BidIt _First, _BidIt _Last) { + // reverse permute and test for pure descending, using operator< return _STD prev_permutation(_First, _Last, less<>()); } // FUNCTION TEMPLATES is_sorted AND is_sorted_until template -_NODISCARD _FwdIt is_sorted_until(const _FwdIt _First, _FwdIt _Last, _Pr _Pred) { +_NODISCARD _CONSTEXPR20 _FwdIt is_sorted_until(const _FwdIt _First, _FwdIt _Last, _Pr _Pred) { // find extent of range that is ordered by predicate _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); @@ -4684,7 +4751,8 @@ _NODISCARD _FwdIt is_sorted_until(const _FwdIt _First, _FwdIt _Last, _Pr _Pred) } template -_NODISCARD bool is_sorted(_FwdIt _First, _FwdIt _Last, _Pr _Pred) { // test if range is ordered by predicate +_NODISCARD _CONSTEXPR20 bool is_sorted(_FwdIt _First, _FwdIt _Last, _Pr _Pred) { + // test if range is ordered by predicate _Adl_verify_range(_First, _Last); const auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); @@ -4692,12 +4760,13 @@ _NODISCARD bool is_sorted(_FwdIt _First, _FwdIt _Last, _Pr _Pred) { // test if r } template -_NODISCARD _FwdIt is_sorted_until(_FwdIt _First, _FwdIt _Last) { // find extent of range that is ordered by operator< +_NODISCARD _CONSTEXPR20 _FwdIt is_sorted_until(_FwdIt _First, _FwdIt _Last) { + // find extent of range that is ordered by operator< return _STD is_sorted_until(_First, _Last, less<>()); } template -_NODISCARD bool is_sorted(_FwdIt _First, _FwdIt _Last) { // test if range is ordered by operator< +_NODISCARD _CONSTEXPR20 bool is_sorted(_FwdIt _First, _FwdIt _Last) { // test if range is ordered by operator< return _STD is_sorted(_First, _Last, less<>()); } diff --git a/stl/inc/numeric b/stl/inc/numeric index 7035c7e65f3..6e9cccb0df8 100644 --- a/stl/inc/numeric +++ b/stl/inc/numeric @@ -75,25 +75,26 @@ _NODISCARD _CONSTEXPR20_ICE _Ty reduce(const _InIt _First, const _InIt _Last, _T _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); + if constexpr (_Plus_on_arithmetic_ranges_reduction_v<_Unwrapped_t, _Ty, _BinOp>) { #ifdef __cpp_lib_is_constant_evaluated - // TRANSITION, DevCom-878972 - if (_STD is_constant_evaluated()) { - for (; _UFirst != _ULast; ++_UFirst) { - _Val = _Reduce_op(_STD move(_Val), *_UFirst); // Requirement missing from N4713 - } - return _Val; - } else -#endif // __cpp_lib_is_constant_evaluated - { - if constexpr (_Plus_on_arithmetic_ranges_reduction_v<_Unwrapped_t, _Ty, _BinOp>) { - (void) _Reduce_op; // TRANSITION, VSO-486357 - return _Reduce_plus_arithmetic_ranges(_UFirst, _ULast, _Val); - } else { + if (_STD is_constant_evaluated()) { for (; _UFirst != _ULast; ++_UFirst) { _Val = _Reduce_op(_STD move(_Val), *_UFirst); // Requirement missing from N4713 } + return _Val; + } else +#endif + { + (void) _Reduce_op; // TRANSITION, VSO-486357 + return _Reduce_plus_arithmetic_ranges(_UFirst, _ULast, _Val); } + } else { + for (; _UFirst != _ULast; ++_UFirst) { + _Val = _Reduce_op(_STD move(_Val), *_UFirst); // Requirement missing from N4713 + } + + return _Val; } } @@ -211,28 +212,28 @@ _NODISCARD _CONSTEXPR20_ICE _Ty transform_reduce( auto _UFirst1 = _Get_unwrapped(_First1); const auto _ULast1 = _Get_unwrapped(_Last1); auto _UFirst2 = _Get_unwrapped_n(_First2, _Idl_distance<_InIt1>(_UFirst1, _ULast1)); + if constexpr (_Default_ops_transform_reduce_v<_Unwrapped_t, _Unwrapped_t, _Ty, + _BinOp1, _BinOp2>) { #ifdef __cpp_lib_is_constant_evaluated - // TRANSITION, DevCom-878972 - if (_STD is_constant_evaluated()) { - for (; _UFirst1 != _ULast1; ++_UFirst1, (void) ++_UFirst2) { - _Val = _Reduce_op(_STD move(_Val), _Transform_op(*_UFirst1, *_UFirst2)); // Requirement missing from N4713 - } - return _Val; - } else -#endif // __cpp_lib_is_constant_evaluated - { - if constexpr (_Default_ops_transform_reduce_v<_Unwrapped_t, _Unwrapped_t, _Ty, - _BinOp1, _BinOp2>) { - (void) _Reduce_op; // TRANSITION, VSO-486357 - (void) _Transform_op; // TRANSITION, VSO-486357 - return _Transform_reduce_arithmetic_defaults(_UFirst1, _ULast1, _UFirst2, _STD move(_Val)); - } else { + // TRANSITION, DevCom-878972 + if (_STD is_constant_evaluated()) { for (; _UFirst1 != _ULast1; ++_UFirst1, (void) ++_UFirst2) { _Val = _Reduce_op(_STD move(_Val), _Transform_op(*_UFirst1, *_UFirst2)); // Requirement missing from N4713 } return _Val; + } else +#endif // __cpp_lib_is_constant_evaluated + { + (void) _Reduce_op; // TRANSITION, VSO-486357 + (void) _Transform_op; // TRANSITION, VSO-486357 + return _Transform_reduce_arithmetic_defaults(_UFirst1, _ULast1, _UFirst2, _STD move(_Val)); + } + } else { + for (; _UFirst1 != _ULast1; ++_UFirst1, (void) ++_UFirst2) { + _Val = _Reduce_op(_STD move(_Val), _Transform_op(*_UFirst1, *_UFirst2)); // Requirement missing from N4713 } + return _Val; } } diff --git a/stl/inc/type_traits b/stl/inc/type_traits index 93d59e1559d..0826981d501 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -1949,10 +1949,10 @@ template && is_move_assigna #else // ^^^ _HAS_CXX17 / !_HAS_CXX17 vvv template #endif // _HAS_CXX17 -void swap(_Ty&, _Ty&) noexcept(is_nothrow_move_constructible_v<_Ty>&& is_nothrow_move_assignable_v<_Ty>); +_CONSTEXPR20 void swap(_Ty&, _Ty&) noexcept(is_nothrow_move_constructible_v<_Ty>&& is_nothrow_move_assignable_v<_Ty>); template ::value, int> = 0> -void swap(_Ty (&)[_Size], _Ty (&)[_Size]) noexcept(_Is_nothrow_swappable<_Ty>::value); +_CONSTEXPR20 void swap(_Ty (&)[_Size], _Ty (&)[_Size]) noexcept(_Is_nothrow_swappable<_Ty>::value); // STRUCT TEMPLATE _Swappable_with_helper template diff --git a/stl/inc/utility b/stl/inc/utility index 876ec0353c4..70bf9094009 100644 --- a/stl/inc/utility +++ b/stl/inc/utility @@ -39,13 +39,13 @@ _Post_equal_to_(_Left < _Right ? _Right : _Left) constexpr const _Ty& _Max_value // FUNCTION TEMPLATE iter_swap (from ) template -void iter_swap(_FwdIt1 _Left, _FwdIt2 _Right) { // swap *_Left and *_Right +_CONSTEXPR20 void iter_swap(_FwdIt1 _Left, _FwdIt2 _Right) { // swap *_Left and *_Right swap(*_Left, *_Right); } // FUNCTION TEMPLATE swap template ::value, int> _Enabled> -void swap(_Ty (&_Left)[_Size], _Ty (&_Right)[_Size]) noexcept(_Is_nothrow_swappable<_Ty>::value) { +_CONSTEXPR20 void swap(_Ty (&_Left)[_Size], _Ty (&_Right)[_Size]) noexcept(_Is_nothrow_swappable<_Ty>::value) { if (&_Left != &_Right) { _Ty* _First1 = _Left; _Ty* _Last1 = _First1 + _Size; @@ -61,7 +61,8 @@ template && is_move_assigna #else // ^^^ _HAS_CXX17 / !_HAS_CXX17 vvv template #endif // _HAS_CXX17 -void swap(_Ty& _Left, _Ty& _Right) noexcept(is_nothrow_move_constructible_v<_Ty>&& is_nothrow_move_assignable_v<_Ty>) { +_CONSTEXPR20 void swap(_Ty& _Left, _Ty& _Right) noexcept( + is_nothrow_move_constructible_v<_Ty>&& is_nothrow_move_assignable_v<_Ty>) { _Ty _Tmp = _STD move(_Left); _Left = _STD move(_Right); _Right = _STD move(_Tmp); @@ -69,7 +70,7 @@ void swap(_Ty& _Left, _Ty& _Right) noexcept(is_nothrow_move_constructible_v<_Ty> // FUNCTION TEMPLATE _Swap_adl template -void _Swap_adl(_Ty& _Left, _Ty& _Right) noexcept(_Is_nothrow_swappable<_Ty>::value) { +_CONSTEXPR20 void _Swap_adl(_Ty& _Left, _Ty& _Right) noexcept(_Is_nothrow_swappable<_Ty>::value) { swap(_Left, _Right); } @@ -566,7 +567,7 @@ _NODISCARD constexpr const _Ty2&& get( // FUNCTION TEMPLATE exchange template -_Ty exchange(_Ty& _Val, _Other&& _New_val) noexcept( +_CONSTEXPR20 _Ty exchange(_Ty& _Val, _Other&& _New_val) noexcept( conjunction_v, is_nothrow_assignable<_Ty&, _Other>>) /* strengthened */ { // assign _New_val to _Val, return previous _Val _Ty _Old_val = static_cast<_Ty&&>(_Val); diff --git a/stl/inc/xmemory b/stl/inc/xmemory index e2065d559f9..8fe7667678d 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1997,7 +1997,8 @@ struct _Alloc_temporary { // FUNCTION TEMPLATE remove template -_NODISCARD _FwdIt remove(_FwdIt _First, const _FwdIt _Last, const _Ty& _Val) { // remove each matching _Val +_NODISCARD _CONSTEXPR20 _FwdIt remove(_FwdIt _First, const _FwdIt _Last, const _Ty& _Val) { + // remove each matching _Val _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); @@ -2018,7 +2019,8 @@ _NODISCARD _FwdIt remove(_FwdIt _First, const _FwdIt _Last, const _Ty& _Val) { / // FUNCTION TEMPLATE remove_if template -_NODISCARD _FwdIt remove_if(_FwdIt _First, const _FwdIt _Last, _Pr _Pred) { // remove each satisfying _Pred +_NODISCARD _CONSTEXPR20 _FwdIt remove_if(_FwdIt _First, const _FwdIt _Last, _Pr _Pred) { + // remove each satisfying _Pred _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); diff --git a/stl/inc/xutility b/stl/inc/xutility index 8fbe63e5bee..6b02cf5b87d 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -1377,78 +1377,6 @@ struct _Unwrap_enum<_Elem, false> { // passthrough non-enum type template using _Unwrap_enum_t = typename _Unwrap_enum<_Elem>::type; -// ALGORITHM DISPATCH TRAITS -template -class move_iterator; - -template -struct _Ptr_cat_helper { // determines _Ptr_cat's result in the most general case - using _USource = _Unwrap_enum_t<_Source>; - using _UDest = _Unwrap_enum_t<_Dest>; - static constexpr bool _Really_trivial = conjunction_v< - bool_constant == is_same_v>, - is_integral<_USource>, is_integral<_UDest>>; - static constexpr bool _Trivially_copyable = _Really_trivial; -}; - -template -struct _Ptr_cat_helper<_Elem, _Elem> { // determines _Ptr_cat's result when the types are the same - static constexpr bool _Really_trivial = is_trivial_v<_Elem>; - static constexpr bool _Trivially_copyable = is_trivially_copyable_v<_Elem>; -}; - -template -struct _Ptr_cat_helper<_Anything*, const _Anything*> { - // determines _Ptr_cat's result when all we do is add const to a pointer - static constexpr bool _Really_trivial = true; - static constexpr bool _Trivially_copyable = true; -}; - -template -struct _Ptr_cat_helper<_Anything*, volatile _Anything*> { - // determines _Ptr_cat's result when all we do is add volatile to a pointer - static constexpr bool _Really_trivial = true; - static constexpr bool _Trivially_copyable = true; -}; - -template -struct _Ptr_cat_helper<_Anything*, const volatile _Anything*> { - // determines _Ptr_cat's result when all we do is add cv to a pointer - static constexpr bool _Really_trivial = true; - static constexpr bool _Trivially_copyable = true; -}; - -struct _False_copy_cat { - static constexpr bool _Really_trivial = false; - static constexpr bool _Trivially_copyable = false; -}; - -template -struct _Ptr_copy_cat : _False_copy_cat {}; // return pointer copy optimization category for arbitrary iterators - -template -struct _Ptr_copy_cat<_Source*, _Dest*> - : conditional_t, - _Ptr_cat_helper, remove_cv_t<_Dest>>, _False_copy_cat> { -}; // return pointer copy optimization category for pointers - -template -struct _Ptr_copy_cat, _Dest*> : _Ptr_copy_cat<_Source*, _Dest*> { -}; // return pointer copy optimization category for move iterators - -template -struct _Ptr_move_cat : _False_copy_cat {}; // return pointer move optimization category for arbitrary iterators - -template -struct _Ptr_move_cat<_Source*, _Dest*> - : conditional_t, - _Ptr_cat_helper, remove_cv_t<_Dest>>, _False_copy_cat> { -}; // return pointer move optimization category for pointers - -template -struct _Ptr_move_cat, _Dest*> : _Ptr_move_cat<_Source*, _Dest*> { -}; // return pointer move optimization category for move iterators - // DEBUG TESTING MACROS #if _ITERATOR_DEBUG_LEVEL < 2 @@ -1486,7 +1414,7 @@ constexpr bool _Debug_lt_pred(_Pr&& _Pred, _Ty1&& _Left, _Ty2&& _Right) noexcept // FUNCTION TEMPLATE _Debug_order_unchecked #if _HAS_IF_CONSTEXPR template -void _Debug_order_unchecked(_InIt _First, _Sentinel _Last, _Pr&& _Pred) { +constexpr void _Debug_order_unchecked(_InIt _First, _Sentinel _Last, _Pr&& _Pred) { // test if range is ordered by predicate if constexpr (_Is_fwd_iter_v<_InIt>) { if (_First != _Last) { @@ -1502,12 +1430,12 @@ void _Debug_order_unchecked(_InIt _First, _Sentinel _Last, _Pr&& _Pred) { } #else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv template -void _Debug_order_unchecked2(_InIt, _Sentinel, _Pr&, input_iterator_tag) { +constexpr void _Debug_order_unchecked2(_InIt, _Sentinel, _Pr&, input_iterator_tag) { // (don't) test if range is ordered by predicate, input iterators } template -void _Debug_order_unchecked2(_FwdIt _First, _Sentinel _Last, _Pr& _Pred, forward_iterator_tag) { +constexpr void _Debug_order_unchecked2(_FwdIt _First, _Sentinel _Last, _Pr& _Pred, forward_iterator_tag) { // test if range is ordered by predicate, forward iterators if (_First != _Last) { for (_FwdIt _Next = _First; ++_Next != _Last; _First = _Next) { @@ -1517,7 +1445,7 @@ void _Debug_order_unchecked2(_FwdIt _First, _Sentinel _Last, _Pr& _Pred, forward } template -void _Debug_order_unchecked(_InIt _First, _Sentinel _Last, _Pr&& _Pred) { +constexpr void _Debug_order_unchecked(_InIt _First, _Sentinel _Last, _Pr&& _Pred) { // test if range is ordered by predicate _Debug_order_unchecked2(_First, _Last, _Pred, _Iter_cat_t<_InIt>()); } @@ -1526,7 +1454,7 @@ void _Debug_order_unchecked(_InIt _First, _Sentinel _Last, _Pr&& _Pred) { // FUNCTION TEMPLATE _Debug_order_set_unchecked #if _HAS_IF_CONSTEXPR template -void _Debug_order_set_unchecked(_InIt _First, _InIt _Last, _Pr&& _Pred) { +constexpr void _Debug_order_set_unchecked(_InIt _First, _InIt _Last, _Pr&& _Pred) { // test if range is ordered by predicate if constexpr (is_same_v<_Iter_value_t<_OtherIt>, _Iter_value_t<_InIt>> && _Is_fwd_iter_v<_InIt>) { _Debug_order_unchecked(_First, _Last, _Pred); @@ -1551,13 +1479,14 @@ void _Debug_order_set_unchecked2(_InIt, _InIt, _Pr&, input_iterator_tag, } template -void _Debug_order_set_unchecked2(_FwdIt _First, _FwdIt _Last, _Pr& _Pred, forward_iterator_tag, _Priority_tag<1>) { +constexpr void _Debug_order_set_unchecked2( + _FwdIt _First, _FwdIt _Last, _Pr& _Pred, forward_iterator_tag, _Priority_tag<1>) { // test if range is ordered by predicate, forward iterators and same types _Debug_order_unchecked2(_First, _Last, _Pred, forward_iterator_tag{}); } template -void _Debug_order_set_unchecked(_InIt _First, _InIt _Last, _Pr&& _Pred) { +constexpr void _Debug_order_set_unchecked(_InIt _First, _InIt _Last, _Pr&& _Pred) { // test if range is ordered by predicate _Debug_order_set_unchecked2(_First, _Last, _Pred, _Iter_cat_t<_InIt>(), _Priority_tag, _Iter_value_t<_InIt>>>()); @@ -3569,8 +3498,72 @@ inline constexpr unreachable_sentinel_t unreachable_sentinel{}; #endif // __cpp_lib_concepts // FUNCTION TEMPLATE copy +template +struct _Ptr_cat_helper { + using _USource = _Unwrap_enum_t<_Source>; + using _UDest = _Unwrap_enum_t<_Dest>; + static constexpr bool _Really_trivial = conjunction_v< + bool_constant == is_same_v>, + is_integral<_USource>, is_integral<_UDest>>; + static constexpr bool _Trivially_copyable = _Really_trivial; +}; + +template +struct _Ptr_cat_helper<_Elem, _Elem> { // determines _Ptr_cat's result when the types are the same + static constexpr bool _Really_trivial = is_trivial_v<_Elem>; + static constexpr bool _Trivially_copyable = is_trivially_copyable_v<_Elem>; +}; + +template +struct _Ptr_cat_helper<_Anything*, const _Anything*> { + // determines _Ptr_cat's result when all we do is add const to a pointer + static constexpr bool _Really_trivial = true; + static constexpr bool _Trivially_copyable = true; +}; + +template +struct _Ptr_cat_helper<_Anything*, volatile _Anything*> { + // determines _Ptr_cat's result when all we do is add volatile to a pointer + static constexpr bool _Really_trivial = true; + static constexpr bool _Trivially_copyable = true; +}; + +template +struct _Ptr_cat_helper<_Anything*, const volatile _Anything*> { + // determines _Ptr_cat's result when all we do is add cv to a pointer + static constexpr bool _Really_trivial = true; + static constexpr bool _Trivially_copyable = true; +}; + +struct _False_copy_cat { + static constexpr bool _Really_trivial = false; + static constexpr bool _Trivially_copyable = false; +}; + +template +struct _Ptr_copy_cat : _False_copy_cat {}; // unwrap the pointer-like type and dispatch to _Ptr_cat_helper for copy + +template +struct _Ptr_copy_cat<_Source*, _Dest*> + : conditional_t, + _Ptr_cat_helper, remove_cv_t<_Dest>>, _False_copy_cat> {}; + +template +struct _Ptr_copy_cat, _Dest*> : _Ptr_copy_cat<_Source*, _Dest*> {}; + +template +struct _Ptr_move_cat : _False_copy_cat {}; // unwrap the pointer-like type and dispatch to _Ptr_cat_helper for move + +template +struct _Ptr_move_cat<_Source*, _Dest*> + : conditional_t, + _Ptr_cat_helper, remove_cv_t<_Dest>>, _False_copy_cat> {}; + +template +struct _Ptr_move_cat, _Dest*> : _Ptr_move_cat<_Source*, _Dest*> {}; + template -_OutIt _Copy_memmove(_InIt _First, _InIt _Last, _OutIt _Dest) { // implement copy-like function as memmove +_OutIt _Copy_memmove(_InIt _First, _InIt _Last, _OutIt _Dest) { const char* const _First_ch = const_cast(reinterpret_cast(_First)); const char* const _Last_ch = const_cast(reinterpret_cast(_Last)); char* const _Dest_ch = const_cast(reinterpret_cast(_Dest)); @@ -3586,11 +3579,22 @@ _OutIt _Copy_memmove(move_iterator<_InIt> _First, move_iterator<_InIt> _Last, _O #if _HAS_IF_CONSTEXPR template -_OutIt _Copy_unchecked(_InIt _First, _InIt _Last, _OutIt _Dest) { +_CONSTEXPR20_ICE _OutIt _Copy_unchecked(_InIt _First, _InIt _Last, _OutIt _Dest) { // copy [_First, _Last) to [_Dest, ...) - // note: _Copy_unchecked is called directly from elsewhere in the STL + // note: _Copy_unchecked has callers other than the copy family if constexpr (_Ptr_copy_cat<_InIt, _OutIt>::_Trivially_copyable) { - return _Copy_memmove(_First, _Last, _Dest); +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + for (; _First != _Last; ++_Dest, (void) ++_First) { + *_Dest = *_First; + } + + return _Dest; + } else +#endif // __cpp_lib_is_constant_evaluated + { + return _Copy_memmove(_First, _Last, _Dest); + } } else { for (; _First != _Last; ++_Dest, (void) ++_First) { *_Dest = *_First; @@ -3619,13 +3623,13 @@ _OutIt _Copy_unchecked1(_InIt _First, _InIt _Last, _OutIt _Dest, true_type) { template _OutIt _Copy_unchecked(_InIt _First, _InIt _Last, _OutIt _Dest) { // copy [_First, _Last) to [_Dest, ...) - // note: _Copy_unchecked is called directly from elsewhere in the STL + // note: _Copy_unchecked has callers other than the copy family return _Copy_unchecked1(_First, _Last, _Dest, bool_constant<_Ptr_copy_cat<_InIt, _OutIt>::_Trivially_copyable>{}); } #endif // _HAS_IF_CONSTEXPR template -_OutIt copy(_InIt _First, _InIt _Last, _OutIt _Dest) { // copy [_First, _Last) to [_Dest, ...) +_CONSTEXPR20_ICE _OutIt copy(_InIt _First, _InIt _Last, _OutIt _Dest) { // copy [_First, _Last) to [_Dest, ...) _Adl_verify_range(_First, _Last); const auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); @@ -3636,7 +3640,8 @@ _OutIt copy(_InIt _First, _InIt _Last, _OutIt _Dest) { // copy [_First, _Last) t #if _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_DestTy* copy(_InIt _First, _InIt _Last, _DestTy (&_Dest)[_DestSize]) { // copy [_First, _Last) to [_Dest, ...) +_CONSTEXPR20_ICE _DestTy* copy(_InIt _First, _InIt _Last, _DestTy (&_Dest)[_DestSize]) { + // copy [_First, _Last) to [_Dest, ...) return _STD copy(_First, _Last, _Array_iterator<_DestTy, _DestSize>(_Dest))._Unwrapped(); } #endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS @@ -3663,27 +3668,40 @@ _DestTy* copy(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _DestTy (&_Dest)[_DestSize #endif // _HAS_CXX17 // FUNCTION TEMPLATE copy_n +template +constexpr _OutIt _Copy_n_core(_InIt _First, _Diff _Count, _OutIt _Dest) { + for (;;) { + *_Dest = *_First; + ++_Dest; + --_Count; + if (_Count == 0) { // note that we avoid an extra ++_First here to allow istream_iterator to work, + // see LWG-2471 + return _Dest; + } + + ++_First; + } +} + #if _HAS_IF_CONSTEXPR template -_OutIt copy_n(_InIt _First, _Diff _Count_raw, _OutIt _Dest) { // copy [_First, _First + _Count) to [_Dest, ...) +_CONSTEXPR20_ICE _OutIt copy_n(_InIt _First, _Diff _Count_raw, _OutIt _Dest) { + // copy [_First, _First + _Count) to [_Dest, ...) _Algorithm_int_t<_Diff> _Count = _Count_raw; if (0 < _Count) { auto _UFirst = _Get_unwrapped_n(_First, _Count); auto _UDest = _Get_unwrapped_n(_Dest, _Count); if constexpr (_Ptr_copy_cat::_Trivially_copyable) { - _UDest = _Copy_memmove(_UFirst, _UFirst + _Count, _UDest); - } else { - for (;;) { - *_UDest = *_UFirst; - ++_UDest; - --_Count; - if (_Count == 0) { // note that we avoid an extra ++_First here to allow istream_iterator to work, - // see LWG-2471 - break; - } - - ++_UFirst; +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + _UDest = _Copy_n_core(_UFirst, _Count, _UDest); + } else +#endif // __cpp_lib_is_constant_evaluated + { + _UDest = _Copy_memmove(_UFirst, _UFirst + _Count, _UDest); } + } else { + _UDest = _Copy_n_core(_UFirst, _Count, _UDest); } _Seek_wrapped(_Dest, _UDest); @@ -3697,17 +3715,7 @@ template _OutIt _Copy_n_unchecked4(_InIt _First, _Diff _Count, _OutIt _Dest, false_type) { // copy [_First, _First + _Count) to [_Dest, ...), no special optimization // pre: 0 < _Count - for (;;) { - *_Dest = *_First; - ++_Dest; - --_Count; - if (_Count == 0) { // note that we avoid an extra ++_First here to allow istream_iterator to work, - // see LWG-2471 - return _Dest; - } - - ++_First; - } + return _Copy_n_core(_First, _Count, _Dest); } template @@ -3734,7 +3742,7 @@ _OutIt copy_n(_InIt _First, _Diff _Count_raw, _OutIt _Dest) { // copy [_First, _ #if _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_OutIt copy_n(_SourceTy (&_First)[_SourceSize], _Diff _Count_raw, _OutIt _Dest) { +_CONSTEXPR20_ICE _OutIt copy_n(_SourceTy (&_First)[_SourceSize], _Diff _Count_raw, _OutIt _Dest) { // copy [_First, _First + _Count) to [_Dest, ...), array source const _Algorithm_int_t<_Diff> _Count = _Count_raw; if (0 < _Count) { @@ -3746,7 +3754,7 @@ _OutIt copy_n(_SourceTy (&_First)[_SourceSize], _Diff _Count_raw, _OutIt _Dest) } template -_DestTy* copy_n(_InIt _First, _Diff _Count_raw, _DestTy (&_Dest)[_DestSize]) { +_CONSTEXPR20_ICE _DestTy* copy_n(_InIt _First, _Diff _Count_raw, _DestTy (&_Dest)[_DestSize]) { // copy [_First, _First + _Count) to [_Dest, ...), array dest const _Algorithm_int_t<_Diff> _Count = _Count_raw; if (0 < _Count) { @@ -3758,7 +3766,7 @@ _DestTy* copy_n(_InIt _First, _Diff _Count_raw, _DestTy (&_Dest)[_DestSize]) { } template -_DestTy* copy_n(_SourceTy (&_First)[_SourceSize], _Diff _Count_raw, _DestTy (&_Dest)[_DestSize]) { +_CONSTEXPR20_ICE _DestTy* copy_n(_SourceTy (&_First)[_SourceSize], _Diff _Count_raw, _DestTy (&_Dest)[_DestSize]) { // copy [_First, _First + _Count) to [_Dest, ...), array source/dest const _Algorithm_int_t<_Diff> _Count = _Count_raw; if (0 < _Count) { @@ -3829,14 +3837,23 @@ _BidIt2 _Copy_backward_memmove(move_iterator<_BidIt1> _First, move_iterator<_Bid #if _HAS_IF_CONSTEXPR template -_BidIt2 copy_backward(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest) { +_CONSTEXPR20_ICE _BidIt2 copy_backward(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest) { // copy [_First, _Last) backwards to [..., _Dest) _Adl_verify_range(_First, _Last); const auto _UFirst = _Get_unwrapped(_First); auto _ULast = _Get_unwrapped(_Last); auto _UDest = _Get_unwrapped_n(_Dest, -_Idl_distance<_BidIt1>(_UFirst, _ULast)); if constexpr (_Ptr_copy_cat::_Trivially_copyable) { - _UDest = _Copy_backward_memmove(_UFirst, _ULast, _UDest); +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + while (_UFirst != _ULast) { + *--_UDest = *--_ULast; + } + } else +#endif // __cpp_lib_is_constant_evaluated + { + _UDest = _Copy_backward_memmove(_UFirst, _ULast, _UDest); + } } else { while (_UFirst != _ULast) { *--_UDest = *--_ULast; @@ -3887,11 +3904,22 @@ _BidIt2 copy_backward(_ExPo&&, _BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest) noe // FUNCTION TEMPLATE move #if _HAS_IF_CONSTEXPR template -_OutIt _Move_unchecked(_InIt _First, _InIt _Last, _OutIt _Dest) { +_CONSTEXPR20_ICE _OutIt _Move_unchecked(_InIt _First, _InIt _Last, _OutIt _Dest) { // move [_First, _Last) to [_Dest, ...) - // note: _Move_unchecked is called directly from elsewhere in the STL + // note: _Move_unchecked has callers other than the move family if constexpr (_Ptr_move_cat<_InIt, _OutIt>::_Trivially_copyable) { - return _Copy_memmove(_First, _Last, _Dest); +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + for (; _First != _Last; ++_Dest, (void) ++_First) { + *_Dest = _STD move(*_First); + } + + return _Dest; + } else +#endif // __cpp_lib_is_constant_evaluated + { + return _Copy_memmove(_First, _Last, _Dest); + } } else { for (; _First != _Last; ++_Dest, (void) ++_First) { *_Dest = _STD move(*_First); @@ -3920,13 +3948,13 @@ _OutIt _Move_unchecked1(_InIt _First, _InIt _Last, _OutIt _Dest, true_type) { template _OutIt _Move_unchecked(_InIt _First, _InIt _Last, _OutIt _Dest) { // move [_First, _Last) to [_Dest, ...), choose optimization - // note: _Move_unchecked is called directly from elsewhere in the STL + // note: _Move_unchecked has callers other than the move family return _Move_unchecked1(_First, _Last, _Dest, bool_constant<_Ptr_move_cat<_InIt, _OutIt>::_Trivially_copyable>{}); } #endif // _HAS_IF_CONSTEXPR template -_OutIt move(_InIt _First, _InIt _Last, _OutIt _Dest) { +_CONSTEXPR20_ICE _OutIt move(_InIt _First, _InIt _Last, _OutIt _Dest) { // move [_First, _Last) to [_Dest, ...) _Adl_verify_range(_First, _Last); const auto _UFirst = _Get_unwrapped(_First); @@ -3967,11 +3995,22 @@ _DestTy* move(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _DestTy (&_Dest)[_DestSize // FUNCTION TEMPLATE move_backward #if _HAS_IF_CONSTEXPR template -_BidIt2 _Move_backward_unchecked(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest) { +_CONSTEXPR20_ICE _BidIt2 _Move_backward_unchecked(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest) { // move [_First, _Last) backwards to [..., _Dest) - // note: _Move_backward_unchecked is called directly from elsewhere in the STL + // note: _Move_backward_unchecked has callers other than the move_backward family if constexpr (_Ptr_move_cat<_BidIt1, _BidIt2>::_Trivially_copyable) { - return _Copy_backward_memmove(_First, _Last, _Dest); +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + while (_First != _Last) { + *--_Dest = _STD move(*--_Last); + } + + return _Dest; + } else +#endif // __cpp_lib_is_constant_evaluated + { + return _Copy_backward_memmove(_First, _Last, _Dest); + } } else { while (_First != _Last) { *--_Dest = _STD move(*--_Last); @@ -4000,14 +4039,15 @@ _BidIt2 _Move_backward_unchecked1(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest, template _BidIt2 _Move_backward_unchecked(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest) { // move [_First, _Last) backwards to [..., _Dest), choose optimization - // note: _Move_backward_unchecked is called directly from elsewhere in the STL + // note: _Move_backward_unchecked has callers other than the move_backward family return _Move_backward_unchecked1( _First, _Last, _Dest, bool_constant<_Ptr_move_cat<_BidIt1, _BidIt2>::_Trivially_copyable>{}); } #endif // _HAS_IF_CONSTEXPR template -_BidIt2 move_backward(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest) { // move [_First, _Last) backwards to [..., _Dest) +_CONSTEXPR20_ICE _BidIt2 move_backward(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest) { + // move [_First, _Last) backwards to [..., _Dest) _Adl_verify_range(_First, _Last); const auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); @@ -4067,12 +4107,22 @@ _INLINE_VAR constexpr bool _Fill_memset_is_safe<_FwdIt, _Ty, false> = false; #if _HAS_IF_CONSTEXPR template -void fill(const _FwdIt _First, const _FwdIt _Last, const _Ty& _Val) { // copy _Val through [_First, _Last) +_CONSTEXPR20_ICE void fill(const _FwdIt _First, const _FwdIt _Last, const _Ty& _Val) { + // copy _Val through [_First, _Last) _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); if constexpr (_Fill_memset_is_safe) { - _CSTD memset(_UFirst, static_cast(_Val), static_cast(_ULast - _UFirst)); +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + for (; _UFirst != _ULast; ++_UFirst) { + *_UFirst = _Val; + } + } else +#endif // __cpp_lib_is_constant_evaluated + { + _CSTD memset(_UFirst, static_cast(_Val), static_cast(_ULast - _UFirst)); + } } else { for (; _UFirst != _ULast; ++_UFirst) { *_UFirst = _Val; @@ -4115,14 +4165,23 @@ void fill(_ExPo&&, _FwdIt _First, _FwdIt _Last, const _Ty& _Val) noexcept /* ter // FUNCTION TEMPLATE fill_n #if _HAS_IF_CONSTEXPR template -_OutIt fill_n(_OutIt _Dest, const _Diff _Count_raw, const _Ty& _Val) { +_CONSTEXPR20_ICE _OutIt fill_n(_OutIt _Dest, const _Diff _Count_raw, const _Ty& _Val) { // copy _Val _Count times through [_Dest, ...) _Algorithm_int_t<_Diff> _Count = _Count_raw; if (0 < _Count) { auto _UDest = _Get_unwrapped_n(_Dest, _Count); if constexpr (_Fill_memset_is_safe) { - _CSTD memset(_UDest, static_cast(_Val), static_cast(_Count)); - _UDest += _Count; +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + for (; 0 < _Count; --_Count, (void) ++_UDest) { + *_UDest = _Val; + } + } else +#endif // __cpp_lib_is_constant_evaluated + { + _CSTD memset(_UDest, static_cast(_Val), static_cast(_Count)); + _UDest += _Count; + } } else { for (; 0 < _Count; --_Count, (void) ++_UDest) { *_UDest = _Val; @@ -4230,17 +4289,30 @@ typename _Equal_memcmp_is_safe_helper, remove_const_t<_Obj #if _HAS_IF_CONSTEXPR template -_NODISCARD bool equal(const _InIt1 _First1, const _InIt1 _Last1, const _InIt2 _First2, _Pr _Pred) { +_NODISCARD _CONSTEXPR20_ICE bool equal(const _InIt1 _First1, const _InIt1 _Last1, const _InIt2 _First2, _Pr _Pred) { // compare [_First1, _Last1) to [_First2, ...) using _Pred _Adl_verify_range(_First1, _Last1); auto _UFirst1 = _Get_unwrapped(_First1); const auto _ULast1 = _Get_unwrapped(_Last1); auto _UFirst2 = _Get_unwrapped_n(_First2, _Idl_distance<_InIt1>(_UFirst1, _ULast1)); if constexpr (decltype(_Equal_memcmp_is_safe(_UFirst1, _UFirst2, _Pred))::value) { - const auto _First1_ch = reinterpret_cast(_UFirst1); - const auto _First2_ch = reinterpret_cast(_UFirst2); - const auto _Count = static_cast(reinterpret_cast(_ULast1) - _First1_ch); - return _CSTD memcmp(_First1_ch, _First2_ch, _Count) == 0; +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + for (; _UFirst1 != _ULast1; ++_UFirst1, (void) ++_UFirst2) { + if (!_Pred(*_UFirst1, *_UFirst2)) { + return false; + } + } + + return true; + } else +#endif // __cpp_lib_is_constant_evaluated + { + const auto _First1_ch = reinterpret_cast(_UFirst1); + const auto _First2_ch = reinterpret_cast(_UFirst2); + const auto _Count = static_cast(reinterpret_cast(_ULast1) - _First1_ch); + return _CSTD memcmp(_First1_ch, _First2_ch, _Count) == 0; + } } else { for (; _UFirst1 != _ULast1; ++_UFirst1, (void) ++_UFirst2) { if (!_Pred(*_UFirst1, *_UFirst2)) { @@ -4292,7 +4364,8 @@ _NODISCARD bool equal(const _InIt1 _First1, const _InIt1 _Last1, const _InIt2 _F #if _ITERATOR_DEBUG_ARRAY_OVERLOADS template , int> = 0> -_NODISCARD bool equal(const _InIt1 _First1, const _InIt1 _Last1, _RightTy (&_First2)[_RightSize], _Pr _Pred) { +_NODISCARD _CONSTEXPR20_ICE bool equal( + const _InIt1 _First1, const _InIt1 _Last1, _RightTy (&_First2)[_RightSize], _Pr _Pred) { // compare [_First1, _Last1) to [_First2, ...) using _Pred return _STD equal(_First1, _Last1, _Array_iterator<_RightTy, _RightSize>(_First2), _Pass_fn(_Pred)); } @@ -4318,14 +4391,14 @@ _NODISCARD bool equal(_ExPo&& _Exec, _FwdIt1 _First1, _FwdIt1 _Last1, _RightTy ( #endif // _HAS_CXX17 template -_NODISCARD bool equal(const _InIt1 _First1, const _InIt1 _Last1, const _InIt2 _First2) { +_NODISCARD _CONSTEXPR20_ICE bool equal(const _InIt1 _First1, const _InIt1 _Last1, const _InIt2 _First2) { // compare [_First1, _Last1) to [_First2, ...) return _STD equal(_First1, _Last1, _First2, equal_to<>()); } #if _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_NODISCARD bool equal(const _InIt1 _First1, const _InIt1 _Last1, _RightTy (&_First2)[_RightSize]) { +_NODISCARD _CONSTEXPR20_ICE bool equal(const _InIt1 _First1, const _InIt1 _Last1, _RightTy (&_First2)[_RightSize]) { // compare [_First1, _Last1) to [_First2, ...) return _STD equal(_First1, _Last1, _First2, equal_to<>()); } @@ -4351,7 +4424,8 @@ _NODISCARD bool equal(_ExPo&& _Exec, const _FwdIt1 _First1, const _FwdIt1 _Last1 #if _HAS_IF_CONSTEXPR template -_NODISCARD bool equal(const _InIt1 _First1, const _InIt1 _Last1, const _InIt2 _First2, const _InIt2 _Last2, _Pr _Pred) { +_NODISCARD _CONSTEXPR20_ICE bool equal( + const _InIt1 _First1, const _InIt1 _Last1, const _InIt2 _First2, const _InIt2 _Last2, _Pr _Pred) { // compare [_First1, _Last1) to [_First2, _Last2) using _Pred _Adl_verify_range(_First1, _Last1); _Adl_verify_range(_First2, _Last2); @@ -4435,7 +4509,8 @@ _NODISCARD bool equal(_ExPo&& _Exec, const _FwdIt1 _First1, const _FwdIt1 _Last1 #endif // _HAS_CXX17 template -_NODISCARD bool equal(const _InIt1 _First1, const _InIt1 _Last1, const _InIt2 _First2, const _InIt2 _Last2) { +_NODISCARD _CONSTEXPR20_ICE bool equal( + const _InIt1 _First1, const _InIt1 _Last1, const _InIt2 _First2, const _InIt2 _Last2) { // compare [_First1, _Last1) to [_First2, _Last2) return _STD equal(_First1, _Last1, _First2, _Last2, equal_to<>()); } @@ -4485,27 +4560,27 @@ using _Lex_compare_check_element_types = _Lex_compare_optimize>; // checks the lex_compare element types for memcmp safety template -_Lex_compare_optimize _Lex_compare_memcmp_classify(const _InIt1&, const _InIt2&, const _Pr&) { +constexpr _Lex_compare_optimize _Lex_compare_memcmp_classify(const _InIt1&, const _InIt2&, const _Pr&) { // return lex_compare optimization category for arbitrary iterators return {}; } template -_Lex_compare_check_element_types, _Obj1, _Obj2, _FTy> _Lex_compare_memcmp_classify( +constexpr _Lex_compare_check_element_types, _Obj1, _Obj2, _FTy> _Lex_compare_memcmp_classify( _Obj1* const&, _Obj2* const&, const less<_FTy>&) { // return lex_compare optimization category for pointer iterators and less<_FTy> return {}; } template -_Lex_compare_check_element_types, _Obj1, _Obj2, _FTy> _Lex_compare_memcmp_classify( +constexpr _Lex_compare_check_element_types, _Obj1, _Obj2, _FTy> _Lex_compare_memcmp_classify( _Obj1* const&, _Obj2* const&, const greater<_FTy>&) { // return lex_compare optimization category for pointer iterators and greater<_FTy> return {}; } template -bool _Lex_compare_unchecked( +_NODISCARD constexpr bool _Lex_compare_unchecked( _InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _Pr _Pred, _Lex_compare_optimize) { // order [_First1, _Last1) vs. [_First2, _Last2) using _Pred, no special optimization for (; _First1 != _Last1 && _First2 != _Last2; ++_First1, (void) ++_First2) { // something to compare, do it @@ -4520,17 +4595,26 @@ bool _Lex_compare_unchecked( } template -bool _Lex_compare_unchecked( - _InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _Pr, _Lex_compare_optimize<_Memcmp_pr>) { +_NODISCARD _CONSTEXPR20_ICE bool _Lex_compare_unchecked( + _InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _Pr _Pred, _Lex_compare_optimize<_Memcmp_pr>) { // order [_First1, _Last1) vs. [_First2, _Last2) memcmp optimization - const auto _Num1 = static_cast(_Last1 - _First1); - const auto _Num2 = static_cast(_Last2 - _First2); - const int _Ans = _CSTD memcmp(_First1, _First2, _Num1 < _Num2 ? _Num1 : _Num2); - return _Memcmp_pr{}(_Ans, 0) || (_Ans == 0 && _Num1 < _Num2); +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + return _Lex_compare_unchecked(_First1, _Last1, _First2, _Last2, _Pred, _Lex_compare_optimize{}); + } else +#endif // __cpp_lib_is_constant_evaluated + { + (void) _Pred; + const auto _Num1 = static_cast(_Last1 - _First1); + const auto _Num2 = static_cast(_Last2 - _First2); + const int _Ans = _CSTD memcmp(_First1, _First2, _Num1 < _Num2 ? _Num1 : _Num2); + return _Memcmp_pr{}(_Ans, 0) || (_Ans == 0 && _Num1 < _Num2); + } } template -_NODISCARD bool lexicographical_compare(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _Pr _Pred) { +_NODISCARD _CONSTEXPR20_ICE bool lexicographical_compare( + _InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _Pr _Pred) { // order [_First1, _Last1) vs. [_First2, _Last2) using _Pred _Adl_verify_range(_First1, _Last1); _Adl_verify_range(_First2, _Last2); @@ -4543,7 +4627,7 @@ _NODISCARD bool lexicographical_compare(_InIt1 _First1, _InIt1 _Last1, _InIt2 _F } template -_NODISCARD bool lexicographical_compare(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2) { +_NODISCARD _CONSTEXPR20_ICE bool lexicographical_compare(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2) { // order [_First1, _Last1) vs. [_First2, _Last2) return _STD lexicographical_compare(_First1, _Last1, _First2, _Last2, less<>()); } @@ -4572,59 +4656,47 @@ _NODISCARD bool lexicographical_compare( // FUNCTION TEMPLATE find template -bool _Within_limits(const _Ty& _Val, true_type, true_type, _Any_tag) { // signed _Elem, signed _Ty +_NODISCARD constexpr bool _Within_limits(const _Ty& _Val, true_type, true_type, _Any_tag) { // signed _Elem, signed _Ty return SCHAR_MIN <= _Val && _Val <= SCHAR_MAX; } template -bool _Within_limits(const _Ty& _Val, true_type, false_type, true_type) { +_NODISCARD constexpr bool _Within_limits(const _Ty& _Val, true_type, false_type, true_type) { // signed _Elem, unsigned _Ty, -1 == static_cast<_Ty>(-1) return _Val <= SCHAR_MAX || static_cast<_Ty>(SCHAR_MIN) <= _Val; } template -bool _Within_limits(const _Ty& _Val, true_type, false_type, false_type) { +_NODISCARD constexpr bool _Within_limits(const _Ty& _Val, true_type, false_type, false_type) { // signed _Elem, unsigned _Ty, -1 != static_cast<_Ty>(-1) return _Val <= SCHAR_MAX; } template -bool _Within_limits(const _Ty& _Val, false_type, true_type, _Any_tag) { +_NODISCARD constexpr bool _Within_limits(const _Ty& _Val, false_type, true_type, _Any_tag) { // unsigned _Elem, signed _Ty return 0 <= _Val && _Val <= UCHAR_MAX; } template -bool _Within_limits(const _Ty& _Val, false_type, false_type, _Any_tag) { +_NODISCARD constexpr bool _Within_limits(const _Ty& _Val, false_type, false_type, _Any_tag) { // unsigned _Elem, unsigned _Ty return _Val <= UCHAR_MAX; } template -bool _Within_limits(_InIt, const _Ty& _Val) { // check whether _Val is within the limits of _Elem +_NODISCARD constexpr bool _Within_limits(_InIt, const _Ty& _Val) { // check whether _Val is within the limits of _Elem using _Elem = remove_pointer_t<_InIt>; return _Within_limits(_Val, is_signed<_Elem>{}, is_signed<_Ty>{}, bool_constant<-1 == static_cast<_Ty>(-1)>{}); } template -bool _Within_limits(_InIt, const bool&) { // bools are always within the limits of _Elem +_NODISCARD constexpr bool _Within_limits(_InIt, const bool&) { // bools are always within the limits of _Elem return true; } template -_InIt _Find_unchecked1(_InIt _First, const _InIt _Last, const _Ty& _Val, true_type) { - // find first byte matching integral _Val - if (!_Within_limits(_First, _Val)) { - return _Last; - } - - _First = - static_cast<_InIt>(_CSTD memchr(_First, static_cast(_Val), static_cast(_Last - _First))); - return _First ? _First : _Last; -} - -template -_InIt _Find_unchecked1(_InIt _First, const _InIt _Last, const _Ty& _Val, false_type) { +_NODISCARD constexpr _InIt _Find_unchecked1(_InIt _First, const _InIt _Last, const _Ty& _Val, false_type) { // find first matching _Val for (; _First != _Last; ++_First) { if (*_First == _Val) { @@ -4636,7 +4708,26 @@ _InIt _Find_unchecked1(_InIt _First, const _InIt _Last, const _Ty& _Val, false_t } template -_InIt _Find_unchecked(const _InIt _First, const _InIt _Last, const _Ty& _Val) { +_NODISCARD _CONSTEXPR20_ICE _InIt _Find_unchecked1(_InIt _First, const _InIt _Last, const _Ty& _Val, true_type) { + // find first byte matching integral _Val + if (!_Within_limits(_First, _Val)) { + return _Last; + } + +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + return _Find_unchecked1(_First, _Last, _Val, false_type{}); + } else +#endif // __cpp_lib_is_constant_evaluated + { + _First = static_cast<_InIt>( + _CSTD memchr(_First, static_cast(_Val), static_cast(_Last - _First))); + return _First ? _First : _Last; + } +} + +template +_NODISCARD _CONSTEXPR20_ICE _InIt _Find_unchecked(const _InIt _First, const _InIt _Last, const _Ty& _Val) { // find first matching _Val; choose optimization // activate optimization for pointers to (const) bytes and integral values using _Memchr_opt = bool_constant< @@ -4647,7 +4738,7 @@ _InIt _Find_unchecked(const _InIt _First, const _InIt _Last, const _Ty& _Val) { } template -_NODISCARD _InIt find(_InIt _First, const _InIt _Last, const _Ty& _Val) { // find first matching _Val +_NODISCARD _CONSTEXPR20_ICE _InIt find(_InIt _First, const _InIt _Last, const _Ty& _Val) { // find first matching _Val _Adl_verify_range(_First, _Last); _Seek_wrapped(_First, _Find_unchecked(_Get_unwrapped(_First), _Get_unwrapped(_Last), _Val)); return _First; @@ -4660,7 +4751,7 @@ _NODISCARD _FwdIt find(_ExPo&& _Exec, _FwdIt _First, const _FwdIt _Last, const _ // FUNCTION TEMPLATE count template -_NODISCARD _Iter_diff_t<_InIt> count(const _InIt _First, const _InIt _Last, const _Ty& _Val) { +_NODISCARD _CONSTEXPR20 _Iter_diff_t<_InIt> count(const _InIt _First, const _InIt _Last, const _Ty& _Val) { // count elements that match _Val _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); @@ -4684,7 +4775,7 @@ _NODISCARD _Iter_diff_t<_FwdIt> count( // FUNCTION TEMPLATE is_permutation template -_NODISCARD _InIt _Find_pr(_InIt _First, const _InIt _Last, const _Ty& _Val, _Pr _Pred) { +_NODISCARD constexpr _InIt _Find_pr(_InIt _First, const _InIt _Last, const _Ty& _Val, _Pr _Pred) { for (; _First != _Last; ++_First) { if (_Pred(*_First, _Val)) { break; @@ -4695,7 +4786,7 @@ _NODISCARD _InIt _Find_pr(_InIt _First, const _InIt _Last, const _Ty& _Val, _Pr } template -_NODISCARD _Iter_diff_t<_InIt> _Count_pr(_InIt _First, const _InIt _Last, const _Ty& _Val, _Pr _Pred) { +_NODISCARD constexpr _Iter_diff_t<_InIt> _Count_pr(_InIt _First, const _InIt _Last, const _Ty& _Val, _Pr _Pred) { _Iter_diff_t<_InIt> _Count = 0; for (; _First != _Last; ++_First) { @@ -4728,7 +4819,7 @@ void _Trim_matching_suffixes( #endif // !_HAS_IF_CONSTEXPR template -_NODISCARD bool _Check_match_counts( +_NODISCARD _CONSTEXPR20 bool _Check_match_counts( const _FwdIt1 _First1, _FwdIt1 _Last1, const _FwdIt2 _First2, _FwdIt2 _Last2, _Pr _Pred) { // test if [_First1, _Last1) == permuted [_First2, _Last2), after matching prefix removal _STL_INTERNAL_CHECK(!_Pred(*_First1, *_First2)); @@ -4764,7 +4855,7 @@ _NODISCARD bool _Check_match_counts( } template -_NODISCARD bool _Is_permutation_unchecked(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _Pr _Pred) { +_NODISCARD _CONSTEXPR20 bool _Is_permutation_unchecked(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _Pr _Pred) { // test if [_First1, _Last1) == permuted [_First2, ...), using _Pred for (; _First1 != _Last1; ++_First1, (void) ++_First2) { // trim matching prefix if (!_Pred(*_First1, *_First2)) { @@ -4781,7 +4872,7 @@ _NODISCARD bool _Is_permutation_unchecked(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdI } template -_NODISCARD bool is_permutation(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _Pr _Pred) { +_NODISCARD _CONSTEXPR20 bool is_permutation(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _Pr _Pred) { // test if [_First1, _Last1) == permuted [_First2, ...), using _Pred _Adl_verify_range(_First1, _Last1); const auto _UFirst1 = _Get_unwrapped(_First1); @@ -4792,14 +4883,15 @@ _NODISCARD bool is_permutation(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, #if _ITERATOR_DEBUG_ARRAY_OVERLOADS template , int> = 0> -_NODISCARD bool is_permutation(_FwdIt1 _First1, _FwdIt1 _Last1, _RightTy (&_First2)[_RightSize], _Pr _Pred) { +_NODISCARD _CONSTEXPR20 bool is_permutation( + _FwdIt1 _First1, _FwdIt1 _Last1, _RightTy (&_First2)[_RightSize], _Pr _Pred) { // test if [_First1, _Last1) == permuted [_First2, ...), using _Pred return _STD is_permutation(_First1, _Last1, _Array_iterator<_RightTy, _RightSize>(_First2), _Pass_fn(_Pred)); } #endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS template -bool is_permutation(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2) { +_CONSTEXPR20 bool is_permutation(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2) { // test if [_First1, _Last1) == permuted [_First2, ...) return _STD is_permutation(_First1, _Last1, _First2, equal_to<>()); } @@ -4807,14 +4899,14 @@ bool is_permutation(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2) { #if _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_NODISCARD bool is_permutation(_FwdIt1 _First1, _FwdIt1 _Last1, _RightTy (&_First2)[_RightSize]) { +_NODISCARD _CONSTEXPR20 bool is_permutation(_FwdIt1 _First1, _FwdIt1 _Last1, _RightTy (&_First2)[_RightSize]) { // test if [_First1, _Last1) == permuted [_First2, ...) return _STD is_permutation(_First1, _Last1, _First2, equal_to<>()); } #endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS template -bool _Is_permutation_unchecked(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2, _Pr _Pred, +_CONSTEXPR20 bool _Is_permutation_unchecked(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2, _Pr _Pred, forward_iterator_tag, forward_iterator_tag) { // test if [_First1, _Last1) == permuted [_First2, _Last2), using _Pred, arbitrary iterators for (;;) { // trim matching prefix @@ -4855,7 +4947,7 @@ bool _Is_permutation_unchecked(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, } template -bool _Is_permutation_unchecked(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2, _Pr _Pred, +_CONSTEXPR20 bool _Is_permutation_unchecked(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2, _Pr _Pred, random_access_iterator_tag, random_access_iterator_tag) { // test if [_First1, _Last1) == permuted [_First2, _Last2), using _Pred, random-access iterators if (_Last1 - _First1 != _Last2 - _First2) { @@ -4873,7 +4965,8 @@ bool _Is_permutation_unchecked(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, } template -_NODISCARD bool is_permutation(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2, _Pr _Pred) { +_NODISCARD _CONSTEXPR20 bool is_permutation( + _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2, _Pr _Pred) { // test if [_First1, _Last1) == permuted [_First2, _Last2), using _Pred _Adl_verify_range(_First1, _Last1); _Adl_verify_range(_First2, _Last2); @@ -4882,7 +4975,7 @@ _NODISCARD bool is_permutation(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, } template -_NODISCARD bool is_permutation(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2) { +_NODISCARD _CONSTEXPR20 bool is_permutation(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2) { // test if [_First1, _Last1) == permuted [_First2, _Last2) return _STD is_permutation(_First1, _Last1, _First2, _Last2, equal_to<>()); } @@ -4890,7 +4983,7 @@ _NODISCARD bool is_permutation(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, // FUNCTION TEMPLATE reverse #if _HAS_IF_CONSTEXPR template -void reverse(const _BidIt _First, const _BidIt _Last) { // reverse elements in [_First, _Last) +_CONSTEXPR20_ICE void reverse(const _BidIt _First, const _BidIt _Last) { // reverse elements in [_First, _Last) _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); auto _ULast = _Get_unwrapped(_Last); @@ -4898,14 +4991,52 @@ void reverse(const _BidIt _First, const _BidIt _Last) { // reverse elements in [ using _Elem = remove_pointer_t; constexpr bool _Allow_vectorization = conjunction_v, _Is_trivially_swappable<_Elem>, negation>>; + + // repeated loop is TRANSITION, DevCom-889321 if constexpr (_Allow_vectorization && sizeof(_Elem) == 1) { - __std_reverse_trivially_swappable_1(_UFirst, _ULast); +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + for (; _UFirst != _ULast && _UFirst != --_ULast; ++_UFirst) { + _STD iter_swap(_UFirst, _ULast); + } + } else +#endif // __cpp_lib_is_constant_evaluated + { + __std_reverse_trivially_swappable_1(_UFirst, _ULast); + } } else if constexpr (_Allow_vectorization && sizeof(_Elem) == 2) { - __std_reverse_trivially_swappable_2(_UFirst, _ULast); +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + for (; _UFirst != _ULast && _UFirst != --_ULast; ++_UFirst) { + _STD iter_swap(_UFirst, _ULast); + } + } else +#endif // __cpp_lib_is_constant_evaluated + { + __std_reverse_trivially_swappable_2(_UFirst, _ULast); + } } else if constexpr (_Allow_vectorization && sizeof(_Elem) == 4) { - __std_reverse_trivially_swappable_4(_UFirst, _ULast); +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + for (; _UFirst != _ULast && _UFirst != --_ULast; ++_UFirst) { + _STD iter_swap(_UFirst, _ULast); + } + } else +#endif // __cpp_lib_is_constant_evaluated + { + __std_reverse_trivially_swappable_4(_UFirst, _ULast); + } } else if constexpr (_Allow_vectorization && sizeof(_Elem) == 8) { - __std_reverse_trivially_swappable_8(_UFirst, _ULast); +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + for (; _UFirst != _ULast && _UFirst != --_ULast; ++_UFirst) { + _STD iter_swap(_UFirst, _ULast); + } + } else +#endif // __cpp_lib_is_constant_evaluated + { + __std_reverse_trivially_swappable_8(_UFirst, _ULast); + } } else #endif // (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_CEE_PURE) && !defined(_M_HYBRID) { @@ -4986,7 +5117,7 @@ void reverse(_ExPo&&, _BidIt _First, _BidIt _Last) noexcept /* terminates */ { // FUNCTION TEMPLATE rotate template -pair<_BidIt, _BidIt> _Reverse_until_sentinel_unchecked(_BidIt _First, _BidIt _Sentinel, _BidIt _Last) { +constexpr pair<_BidIt, _BidIt> _Reverse_until_sentinel_unchecked(_BidIt _First, _BidIt _Sentinel, _BidIt _Last) { // reverse until either _First or _Last hits _Sentinel while (_First != _Sentinel && _Last != _Sentinel) { _STD iter_swap(_First, --_Last); @@ -4998,7 +5129,7 @@ pair<_BidIt, _BidIt> _Reverse_until_sentinel_unchecked(_BidIt _First, _BidIt _Se #if _HAS_IF_CONSTEXPR template -_FwdIt rotate(_FwdIt _First, _FwdIt _Mid, _FwdIt _Last) { +_CONSTEXPR20 _FwdIt rotate(_FwdIt _First, _FwdIt _Mid, _FwdIt _Last) { // exchange the ranges [_First, _Mid) and [_Mid, _Last) // that is, rotates [_First, _Last) left by distance(_First, _Mid) positions // returns the iterator pointing at *_First's new home @@ -5130,7 +5261,7 @@ _FwdIt rotate(_ExPo&&, _FwdIt _First, _FwdIt _Mid, _FwdIt _Last) noexcept /* ter // FUNCTION TEMPLATE find_if template -_NODISCARD _InIt find_if(_InIt _First, const _InIt _Last, _Pr _Pred) { // find first satisfying _Pred +_NODISCARD _CONSTEXPR20 _InIt find_if(_InIt _First, const _InIt _Last, _Pr _Pred) { // find first satisfying _Pred _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); @@ -5146,7 +5277,7 @@ _NODISCARD _InIt find_if(_InIt _First, const _InIt _Last, _Pr _Pred) { // find f // FUNCTION TEMPLATE lower_bound template -_NODISCARD _FwdIt lower_bound(_FwdIt _First, const _FwdIt _Last, const _Ty& _Val, _Pr _Pred) { +_NODISCARD _CONSTEXPR20 _FwdIt lower_bound(_FwdIt _First, const _FwdIt _Last, const _Ty& _Val, _Pr _Pred) { // find first element not before _Val, using _Pred _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); @@ -5167,6 +5298,12 @@ _NODISCARD _FwdIt lower_bound(_FwdIt _First, const _FwdIt _Last, const _Ty& _Val return _First; } +template +_NODISCARD _CONSTEXPR20 _FwdIt lower_bound(_FwdIt _First, _FwdIt _Last, const _Ty& _Val) { + // find first element not before _Val, using operator< + return _STD lower_bound(_First, _Last, _Val, less<>()); +} + // CLASS TEMPLATE _Rng_from_urng template class _Rng_from_urng { // wrap a URNG as an RNG diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 4ba1f6639b1..e5122427498 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -1025,7 +1025,8 @@ #define __cpp_lib_unwrap_ref 201811L #ifdef __cpp_lib_is_constant_evaluated -#define __cpp_lib_constexpr_numeric 201911L +#define __cpp_lib_constexpr_algorithms 201806L +#define __cpp_lib_constexpr_numeric 201911L #endif // __cpp_lib_is_constant_evaluated #endif // _HAS_CXX20 diff --git a/tests/libcxx/skipped_tests.txt b/tests/libcxx/skipped_tests.txt index f50071d081e..5bf70d448c2 100644 --- a/tests/libcxx/skipped_tests.txt +++ b/tests/libcxx/skipped_tests.txt @@ -40,6 +40,24 @@ utilities\template.bitset\bitset.cons\string_ctor.pass.cpp # This test has undefined behavior under N4842 [basic.start.term]/6 thread\futures\futures.task\futures.task.members\dtor.pass.cpp +# libcxx is incorrect on what the type passed to allocator construct should be +# See https://reviews.llvm.org/D61364 +containers\associative\map\map.modifiers\insert_and_emplace_allocator_requirements.pass.cpp +containers\associative\set\insert_and_emplace_allocator_requirements.pass.cpp +containers\unord\unord.map\unord.map.modifiers\insert_and_emplace_allocator_requirements.pass.cpp +containers\unord\unord.set\insert_and_emplace_allocator_requirements.pass.cpp + +# libcxx incorrectly assumes moved-from non-POCMA containers are empty +# See https://reviews.llvm.org/D61366 +containers\associative\map\map.cons\move_assign.pass.cpp +containers\associative\multimap\multimap.cons\move_assign.pass.cpp +containers\associative\multiset\multiset.cons\move_assign.pass.cpp +containers\associative\set\set.cons\move_assign.pass.cpp + +# libcxx incorrectly thinks subspan can produce a span of dynamic extent +# See https://reviews.llvm.org/D73138 +containers\views\span.sub\subspan.pass.cpp + # *** INTERACTIONS WITH CONTEST / C1XX THAT UPSTREAM LIKELY WON'T FIX *** # Tracked by VSO-593630 " Enable libcxx filesystem tests" @@ -196,85 +214,6 @@ utilities\tuple\tuple.tuple\tuple.apply\apply_large_arity.pass.cpp # C++20 P0019R8 "atomic_ref" language.support\support.limits\support.limits.general\atomic.version.pass.cpp -# C++20 P0202R3 "constexpr For And exchange()" -algorithms\alg.modifying.operations\alg.copy\copy_backward.pass.cpp -algorithms\alg.modifying.operations\alg.copy\copy_if.pass.cpp -algorithms\alg.modifying.operations\alg.copy\copy_n.pass.cpp -algorithms\alg.modifying.operations\alg.copy\copy.pass.cpp -algorithms\alg.modifying.operations\alg.fill\fill_n.pass.cpp -algorithms\alg.modifying.operations\alg.fill\fill.pass.cpp -algorithms\alg.modifying.operations\alg.generate\generate_n.pass.cpp -algorithms\alg.modifying.operations\alg.generate\generate.pass.cpp -algorithms\alg.modifying.operations\alg.partitions\is_partitioned.pass.cpp -algorithms\alg.modifying.operations\alg.partitions\partition_copy.pass.cpp -algorithms\alg.modifying.operations\alg.partitions\partition_point.pass.cpp -algorithms\alg.modifying.operations\alg.remove\remove_copy_if.pass.cpp -algorithms\alg.modifying.operations\alg.remove\remove_copy.pass.cpp -algorithms\alg.modifying.operations\alg.remove\remove_if.pass.cpp -algorithms\alg.modifying.operations\alg.remove\remove.pass.cpp -algorithms\alg.modifying.operations\alg.replace\replace_copy_if.pass.cpp -algorithms\alg.modifying.operations\alg.replace\replace_copy.pass.cpp -algorithms\alg.modifying.operations\alg.replace\replace_if.pass.cpp -algorithms\alg.modifying.operations\alg.replace\replace.pass.cpp -algorithms\alg.modifying.operations\alg.reverse\reverse_copy.pass.cpp -algorithms\alg.modifying.operations\alg.transform\binary_transform.pass.cpp -algorithms\alg.modifying.operations\alg.transform\unary_transform.pass.cpp -algorithms\alg.modifying.operations\alg.unique\unique_copy_pred.pass.cpp -algorithms\alg.modifying.operations\alg.unique\unique_copy.pass.cpp -algorithms\alg.modifying.operations\alg.unique\unique_pred.pass.cpp -algorithms\alg.modifying.operations\alg.unique\unique.pass.cpp -algorithms\alg.nonmodifying\alg.adjacent.find\adjacent_find_pred.pass.cpp -algorithms\alg.nonmodifying\alg.adjacent.find\adjacent_find.pass.cpp -algorithms\alg.nonmodifying\alg.all_of\all_of.pass.cpp -algorithms\alg.nonmodifying\alg.any_of\any_of.pass.cpp -algorithms\alg.nonmodifying\alg.count\count_if.pass.cpp -algorithms\alg.nonmodifying\alg.count\count.pass.cpp -algorithms\alg.nonmodifying\alg.equal\equal_pred.pass.cpp -algorithms\alg.nonmodifying\alg.equal\equal.pass.cpp -algorithms\alg.nonmodifying\alg.find.end\find_end_pred.pass.cpp -algorithms\alg.nonmodifying\alg.find.end\find_end.pass.cpp -algorithms\alg.nonmodifying\alg.find.first.of\find_first_of_pred.pass.cpp -algorithms\alg.nonmodifying\alg.find.first.of\find_first_of.pass.cpp -algorithms\alg.nonmodifying\alg.find\find_if_not.pass.cpp -algorithms\alg.nonmodifying\alg.find\find_if.pass.cpp -algorithms\alg.nonmodifying\alg.find\find.pass.cpp -algorithms\alg.nonmodifying\alg.foreach\for_each_n.pass.cpp -algorithms\alg.nonmodifying\alg.foreach\test.pass.cpp -algorithms\alg.nonmodifying\alg.is_permutation\is_permutation_pred.pass.cpp -algorithms\alg.nonmodifying\alg.is_permutation\is_permutation.pass.cpp -algorithms\alg.nonmodifying\alg.none_of\none_of.pass.cpp -algorithms\alg.nonmodifying\alg.search\search_n_pred.pass.cpp -algorithms\alg.nonmodifying\alg.search\search_n.pass.cpp -algorithms\alg.nonmodifying\alg.search\search_pred.pass.cpp -algorithms\alg.nonmodifying\alg.search\search.pass.cpp -algorithms\alg.nonmodifying\mismatch\mismatch_pred.pass.cpp -algorithms\alg.nonmodifying\mismatch\mismatch.pass.cpp -algorithms\alg.sorting\alg.binary.search\binary.search\binary_search_comp.pass.cpp -algorithms\alg.sorting\alg.binary.search\binary.search\binary_search.pass.cpp -algorithms\alg.sorting\alg.binary.search\equal.range\equal_range_comp.pass.cpp -algorithms\alg.sorting\alg.binary.search\equal.range\equal_range.pass.cpp -algorithms\alg.sorting\alg.binary.search\lower.bound\lower_bound_comp.pass.cpp -algorithms\alg.sorting\alg.binary.search\lower.bound\lower_bound.pass.cpp -algorithms\alg.sorting\alg.binary.search\upper.bound\upper_bound_comp.pass.cpp -algorithms\alg.sorting\alg.binary.search\upper.bound\upper_bound.pass.cpp -algorithms\alg.sorting\alg.heap.operations\is.heap\is_heap_comp.pass.cpp -algorithms\alg.sorting\alg.heap.operations\is.heap\is_heap_until_comp.pass.cpp -algorithms\alg.sorting\alg.heap.operations\is.heap\is_heap_until.pass.cpp -algorithms\alg.sorting\alg.heap.operations\is.heap\is_heap.pass.cpp -algorithms\alg.sorting\alg.lex.comparison\lexicographical_compare_comp.pass.cpp -algorithms\alg.sorting\alg.lex.comparison\lexicographical_compare.pass.cpp -algorithms\alg.sorting\alg.set.operations\includes\includes_comp.pass.cpp -algorithms\alg.sorting\alg.set.operations\includes\includes.pass.cpp -algorithms\alg.sorting\alg.set.operations\set.intersection\set_intersection_comp.pass.cpp -algorithms\alg.sorting\alg.set.operations\set.intersection\set_intersection.pass.cpp -algorithms\alg.sorting\alg.sort\is.sorted\is_sorted_comp.pass.cpp -algorithms\alg.sorting\alg.sort\is.sorted\is_sorted_until_comp.pass.cpp -algorithms\alg.sorting\alg.sort\is.sorted\is_sorted_until.pass.cpp -algorithms\alg.sorting\alg.sort\is.sorted\is_sorted.pass.cpp -containers\views\span.sub\first.pass.cpp -containers\views\span.sub\last.pass.cpp -containers\views\span.sub\subspan.pass.cpp -utilities\utility\exchange\exchange.pass.cpp # C++20 P0355R7 " Calendars And Time Zones" utilities\time\days.pass.cpp @@ -512,13 +451,6 @@ language.support\support.limits\support.limits.general\compare.version.pass.cpp language.support\support.limits\support.limits.general\numeric.version.pass.cpp numerics\c.math\c.math.lerp\c.math.lerp.pass.cpp -# C++20 P0879R0 "constexpr For Swapping Functions" -algorithms\alg.modifying.operations\alg.swap\iter_swap.pass.cpp -algorithms\alg.modifying.operations\alg.swap\swap_ranges.pass.cpp -language.support\support.limits\support.limits.general\algorithm.version.pass.cpp -utilities\utility\utility.swap\swap.pass.cpp -utilities\utility\utility.swap\swap_array.pass.cpp - # C++20 P0896R4 "" language.support\support.limits\support.limits.general\algorithm.version.pass.cpp language.support\support.limits\support.limits.general\functional.version.pass.cpp @@ -1030,17 +962,5 @@ containers\unord\unord.multimap\unord.multimap.cnstr\deduct.pass.cpp containers\unord\unord.multimap\unord.multimap.cnstr\deduct_const.pass.cpp utilities\tuple\tuple.tuple\tuple.cnstr\deduct.pass.cpp -# Not yet analyzed. Assertion failed: m1.empty() -containers\associative\map\map.cons\move_assign.pass.cpp -containers\associative\multimap\multimap.cons\move_assign.pass.cpp -containers\associative\multiset\multiset.cons\move_assign.pass.cpp -containers\associative\set\set.cons\move_assign.pass.cpp - -# Not yet analyzed. Assertion failed: controller->check() -containers\associative\map\map.modifiers\insert_and_emplace_allocator_requirements.pass.cpp -containers\associative\set\insert_and_emplace_allocator_requirements.pass.cpp -containers\unord\unord.map\unord.map.modifiers\insert_and_emplace_allocator_requirements.pass.cpp -containers\unord\unord.set\insert_and_emplace_allocator_requirements.pass.cpp - # Not yet analyzed. Assertion failed: f16_8.out(mbs, c16, c_c16p, c_c16p, c8, c8+4, c8p) == F32_8::ok localization\locale.categories\category.ctype\locale.codecvt\locale.codecvt.members\utf_sanity_check.pass.cpp From 88ec8002a72ea29798168ea739447b1ae233ae9a Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Tue, 21 Jan 2020 19:42:18 -0800 Subject: [PATCH 2/5] Attempt alternate fix of GH-414 suggested by Stephan. --- stl/inc/algorithm | 38 ++++----- stl/inc/numeric | 36 +++----- stl/inc/xutility | 211 +++++++++++++++++++--------------------------- 3 files changed, 113 insertions(+), 172 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 6c381b4723d..ba3e8b614cf 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -678,15 +678,7 @@ _NODISCARD _CONSTEXPR20_ICE bool _Equal_rev_pred_unchecked( // compare [_First1, ...) to [_First2, _Last2) using _Pred if constexpr (decltype(_Equal_memcmp_is_safe(_First1, _First2, _Pred))::value) { #ifdef __cpp_lib_is_constant_evaluated - if (_STD is_constant_evaluated()) { - for (; _First2 != _Last2; ++_First1, (void) ++_First2) { - if (!_Pred(*_First1, *_First2)) { - return false; - } - } - - return true; - } else + if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated { const auto _First1_ch = reinterpret_cast(_First1); @@ -694,15 +686,15 @@ _NODISCARD _CONSTEXPR20_ICE bool _Equal_rev_pred_unchecked( const auto _Count = static_cast(reinterpret_cast(_Last2) - _First2_ch); return _CSTD memcmp(_First1_ch, _First2_ch, _Count) == 0; } - } else { - for (; _First2 != _Last2; ++_First1, (void) ++_First2) { - if (!_Pred(*_First1, *_First2)) { - return false; - } - } + } - return true; + for (; _First2 != _Last2; ++_First1, (void) ++_First2) { + if (!_Pred(*_First1, *_First2)) { + return false; + } } + + return true; } #else // ^^^ _HAS_IF_CONSTEXPR ^^^ // vvv !_HAS_IF_CONSTEXPR vvv template @@ -1285,18 +1277,18 @@ template , int> = 0> _CONSTEXPR20_ICE _Ty* _Swap_ranges_unchecked(_Ty* _First1, _Ty* const _Last1, _Ty* _First2) { // swap [_First1, _Last1) with [_First2, ...), trivially swappable optimization #ifdef __cpp_lib_is_constant_evaluated - if (_STD is_constant_evaluated()) { - for (; _First1 != _Last1; ++_First1, (void) ++_First2) { - _STD iter_swap(_First1, _First2); - } - - return _First2; - } else + if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated { __std_swap_ranges_trivially_swappable_noalias(_First1, _Last1, _First2); return _First2 + (_Last1 - _First1); } + + for (; _First1 != _Last1; ++_First1, (void) ++_First2) { + _STD iter_swap(_First1, _First2); + } + + return _First2; } #endif // (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_CEE_PURE) && !defined(_M_HYBRID) diff --git a/stl/inc/numeric b/stl/inc/numeric index 6e9cccb0df8..c22b937d5ce 100644 --- a/stl/inc/numeric +++ b/stl/inc/numeric @@ -77,25 +77,19 @@ _NODISCARD _CONSTEXPR20_ICE _Ty reduce(const _InIt _First, const _InIt _Last, _T const auto _ULast = _Get_unwrapped(_Last); if constexpr (_Plus_on_arithmetic_ranges_reduction_v<_Unwrapped_t, _Ty, _BinOp>) { #ifdef __cpp_lib_is_constant_evaluated - if (_STD is_constant_evaluated()) { - for (; _UFirst != _ULast; ++_UFirst) { - _Val = _Reduce_op(_STD move(_Val), *_UFirst); // Requirement missing from N4713 - } - - return _Val; - } else + if (!_STD is_constant_evaluated()) #endif { (void) _Reduce_op; // TRANSITION, VSO-486357 return _Reduce_plus_arithmetic_ranges(_UFirst, _ULast, _Val); } - } else { - for (; _UFirst != _ULast; ++_UFirst) { - _Val = _Reduce_op(_STD move(_Val), *_UFirst); // Requirement missing from N4713 - } + } - return _Val; + for (; _UFirst != _ULast; ++_UFirst) { + _Val = _Reduce_op(_STD move(_Val), *_UFirst); // Requirement missing from N4713 } + + return _Val; } template @@ -216,25 +210,19 @@ _NODISCARD _CONSTEXPR20_ICE _Ty transform_reduce( _BinOp1, _BinOp2>) { #ifdef __cpp_lib_is_constant_evaluated // TRANSITION, DevCom-878972 - if (_STD is_constant_evaluated()) { - for (; _UFirst1 != _ULast1; ++_UFirst1, (void) ++_UFirst2) { - _Val = - _Reduce_op(_STD move(_Val), _Transform_op(*_UFirst1, *_UFirst2)); // Requirement missing from N4713 - } - return _Val; - } else + if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated { (void) _Reduce_op; // TRANSITION, VSO-486357 (void) _Transform_op; // TRANSITION, VSO-486357 return _Transform_reduce_arithmetic_defaults(_UFirst1, _ULast1, _UFirst2, _STD move(_Val)); } - } else { - for (; _UFirst1 != _ULast1; ++_UFirst1, (void) ++_UFirst2) { - _Val = _Reduce_op(_STD move(_Val), _Transform_op(*_UFirst1, *_UFirst2)); // Requirement missing from N4713 - } - return _Val; } + + for (; _UFirst1 != _ULast1; ++_UFirst1, (void) ++_UFirst2) { + _Val = _Reduce_op(_STD move(_Val), _Transform_op(*_UFirst1, *_UFirst2)); // Requirement missing from N4713 + } + return _Val; } #if _ITERATOR_DEBUG_ARRAY_OVERLOADS diff --git a/stl/inc/xutility b/stl/inc/xutility index 6b02cf5b87d..ed460aa7ac6 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -3584,24 +3584,18 @@ _CONSTEXPR20_ICE _OutIt _Copy_unchecked(_InIt _First, _InIt _Last, _OutIt _Dest) // note: _Copy_unchecked has callers other than the copy family if constexpr (_Ptr_copy_cat<_InIt, _OutIt>::_Trivially_copyable) { #ifdef __cpp_lib_is_constant_evaluated - if (_STD is_constant_evaluated()) { - for (; _First != _Last; ++_Dest, (void) ++_First) { - *_Dest = *_First; - } - - return _Dest; - } else + if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated { return _Copy_memmove(_First, _Last, _Dest); } - } else { - for (; _First != _Last; ++_Dest, (void) ++_First) { - *_Dest = *_First; - } + } - return _Dest; + for (; _First != _Last; ++_Dest, (void) ++_First) { + *_Dest = *_First; } + + return _Dest; } #else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv template @@ -3669,19 +3663,7 @@ _DestTy* copy(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _DestTy (&_Dest)[_DestSize // FUNCTION TEMPLATE copy_n template -constexpr _OutIt _Copy_n_core(_InIt _First, _Diff _Count, _OutIt _Dest) { - for (;;) { - *_Dest = *_First; - ++_Dest; - --_Count; - if (_Count == 0) { // note that we avoid an extra ++_First here to allow istream_iterator to work, - // see LWG-2471 - return _Dest; - } - - ++_First; - } -} +constexpr _OutIt _Copy_n_core(_InIt _First, _Diff _Count, _OutIt _Dest) {} #if _HAS_IF_CONSTEXPR template @@ -3693,15 +3675,25 @@ _CONSTEXPR20_ICE _OutIt copy_n(_InIt _First, _Diff _Count_raw, _OutIt _Dest) { auto _UDest = _Get_unwrapped_n(_Dest, _Count); if constexpr (_Ptr_copy_cat::_Trivially_copyable) { #ifdef __cpp_lib_is_constant_evaluated - if (_STD is_constant_evaluated()) { - _UDest = _Copy_n_core(_UFirst, _Count, _UDest); - } else + if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated { _UDest = _Copy_memmove(_UFirst, _UFirst + _Count, _UDest); + _Seek_wrapped(_Dest, _UDest); + return _Dest; } - } else { - _UDest = _Copy_n_core(_UFirst, _Count, _UDest); + } + + for (;;) { + *_UDest = *_UFirst; + ++_UDest; + --_Count; + if (_Count == 0) { // note that we avoid an extra ++_First here to allow istream_iterator to work, + // see LWG-2471 + break; + } + + ++_UFirst; } _Seek_wrapped(_Dest, _UDest); @@ -3715,7 +3707,17 @@ template _OutIt _Copy_n_unchecked4(_InIt _First, _Diff _Count, _OutIt _Dest, false_type) { // copy [_First, _First + _Count) to [_Dest, ...), no special optimization // pre: 0 < _Count - return _Copy_n_core(_First, _Count, _Dest); + for (;;) { + *_Dest = *_First; + ++_Dest; + --_Count; + if (_Count == 0) { // note that we avoid an extra ++_First here to allow istream_iterator to work, + // see LWG-2471 + return _Dest; + } + + ++_First; + } } template @@ -3845,21 +3847,18 @@ _CONSTEXPR20_ICE _BidIt2 copy_backward(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _D auto _UDest = _Get_unwrapped_n(_Dest, -_Idl_distance<_BidIt1>(_UFirst, _ULast)); if constexpr (_Ptr_copy_cat::_Trivially_copyable) { #ifdef __cpp_lib_is_constant_evaluated - if (_STD is_constant_evaluated()) { - while (_UFirst != _ULast) { - *--_UDest = *--_ULast; - } - } else + if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated { _UDest = _Copy_backward_memmove(_UFirst, _ULast, _UDest); - } - } else { - while (_UFirst != _ULast) { - *--_UDest = *--_ULast; + _Seek_wrapped(_Dest, _UDest); + return _Dest; } } + while (_UFirst != _ULast) { + *--_UDest = *--_ULast; + } _Seek_wrapped(_Dest, _UDest); return _Dest; } @@ -3909,24 +3908,18 @@ _CONSTEXPR20_ICE _OutIt _Move_unchecked(_InIt _First, _InIt _Last, _OutIt _Dest) // note: _Move_unchecked has callers other than the move family if constexpr (_Ptr_move_cat<_InIt, _OutIt>::_Trivially_copyable) { #ifdef __cpp_lib_is_constant_evaluated - if (_STD is_constant_evaluated()) { - for (; _First != _Last; ++_Dest, (void) ++_First) { - *_Dest = _STD move(*_First); - } - - return _Dest; - } else + if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated { return _Copy_memmove(_First, _Last, _Dest); } - } else { - for (; _First != _Last; ++_Dest, (void) ++_First) { - *_Dest = _STD move(*_First); - } + } - return _Dest; + for (; _First != _Last; ++_Dest, (void) ++_First) { + *_Dest = _STD move(*_First); } + + return _Dest; } #else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv template @@ -4000,24 +3993,18 @@ _CONSTEXPR20_ICE _BidIt2 _Move_backward_unchecked(_BidIt1 _First, _BidIt1 _Last, // note: _Move_backward_unchecked has callers other than the move_backward family if constexpr (_Ptr_move_cat<_BidIt1, _BidIt2>::_Trivially_copyable) { #ifdef __cpp_lib_is_constant_evaluated - if (_STD is_constant_evaluated()) { - while (_First != _Last) { - *--_Dest = _STD move(*--_Last); - } - - return _Dest; - } else + if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated { return _Copy_backward_memmove(_First, _Last, _Dest); } - } else { - while (_First != _Last) { - *--_Dest = _STD move(*--_Last); - } + } - return _Dest; + while (_First != _Last) { + *--_Dest = _STD move(*--_Last); } + + return _Dest; } #else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv template @@ -4114,19 +4101,16 @@ _CONSTEXPR20_ICE void fill(const _FwdIt _First, const _FwdIt _Last, const _Ty& _ const auto _ULast = _Get_unwrapped(_Last); if constexpr (_Fill_memset_is_safe) { #ifdef __cpp_lib_is_constant_evaluated - if (_STD is_constant_evaluated()) { - for (; _UFirst != _ULast; ++_UFirst) { - *_UFirst = _Val; - } - } else + if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated { _CSTD memset(_UFirst, static_cast(_Val), static_cast(_ULast - _UFirst)); + return; } - } else { - for (; _UFirst != _ULast; ++_UFirst) { - *_UFirst = _Val; - } + } + + for (; _UFirst != _ULast; ++_UFirst) { + *_UFirst = _Val; } } #else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv @@ -4172,20 +4156,18 @@ _CONSTEXPR20_ICE _OutIt fill_n(_OutIt _Dest, const _Diff _Count_raw, const _Ty& auto _UDest = _Get_unwrapped_n(_Dest, _Count); if constexpr (_Fill_memset_is_safe) { #ifdef __cpp_lib_is_constant_evaluated - if (_STD is_constant_evaluated()) { - for (; 0 < _Count; --_Count, (void) ++_UDest) { - *_UDest = _Val; - } - } else + if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated { _CSTD memset(_UDest, static_cast(_Val), static_cast(_Count)); _UDest += _Count; + _Seek_wrapped(_Dest, _UDest); + return _Dest; } - } else { - for (; 0 < _Count; --_Count, (void) ++_UDest) { - *_UDest = _Val; - } + } + + for (; 0 < _Count; --_Count, (void) ++_UDest) { + *_UDest = _Val; } _Seek_wrapped(_Dest, _UDest); @@ -4297,15 +4279,7 @@ _NODISCARD _CONSTEXPR20_ICE bool equal(const _InIt1 _First1, const _InIt1 _Last1 auto _UFirst2 = _Get_unwrapped_n(_First2, _Idl_distance<_InIt1>(_UFirst1, _ULast1)); if constexpr (decltype(_Equal_memcmp_is_safe(_UFirst1, _UFirst2, _Pred))::value) { #ifdef __cpp_lib_is_constant_evaluated - if (_STD is_constant_evaluated()) { - for (; _UFirst1 != _ULast1; ++_UFirst1, (void) ++_UFirst2) { - if (!_Pred(*_UFirst1, *_UFirst2)) { - return false; - } - } - - return true; - } else + if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated { const auto _First1_ch = reinterpret_cast(_UFirst1); @@ -4313,15 +4287,15 @@ _NODISCARD _CONSTEXPR20_ICE bool equal(const _InIt1 _First1, const _InIt1 _Last1 const auto _Count = static_cast(reinterpret_cast(_ULast1) - _First1_ch); return _CSTD memcmp(_First1_ch, _First2_ch, _Count) == 0; } - } else { - for (; _UFirst1 != _ULast1; ++_UFirst1, (void) ++_UFirst2) { - if (!_Pred(*_UFirst1, *_UFirst2)) { - return false; - } - } + } - return true; + for (; _UFirst1 != _ULast1; ++_UFirst1, (void) ++_UFirst2) { + if (!_Pred(*_UFirst1, *_UFirst2)) { + return false; + } } + + return true; } #else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv template @@ -4601,7 +4575,7 @@ _NODISCARD _CONSTEXPR20_ICE bool _Lex_compare_unchecked( #ifdef __cpp_lib_is_constant_evaluated if (_STD is_constant_evaluated()) { return _Lex_compare_unchecked(_First1, _Last1, _First2, _Last2, _Pred, _Lex_compare_optimize{}); - } else + } #endif // __cpp_lib_is_constant_evaluated { (void) _Pred; @@ -4717,7 +4691,7 @@ _NODISCARD _CONSTEXPR20_ICE _InIt _Find_unchecked1(_InIt _First, const _InIt _La #ifdef __cpp_lib_is_constant_evaluated if (_STD is_constant_evaluated()) { return _Find_unchecked1(_First, _Last, _Val, false_type{}); - } else + } #endif // __cpp_lib_is_constant_evaluated { _First = static_cast<_InIt>( @@ -4995,54 +4969,41 @@ _CONSTEXPR20_ICE void reverse(const _BidIt _First, const _BidIt _Last) { // reve // repeated loop is TRANSITION, DevCom-889321 if constexpr (_Allow_vectorization && sizeof(_Elem) == 1) { #ifdef __cpp_lib_is_constant_evaluated - if (_STD is_constant_evaluated()) { - for (; _UFirst != _ULast && _UFirst != --_ULast; ++_UFirst) { - _STD iter_swap(_UFirst, _ULast); - } - } else + if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated { __std_reverse_trivially_swappable_1(_UFirst, _ULast); + return; } } else if constexpr (_Allow_vectorization && sizeof(_Elem) == 2) { #ifdef __cpp_lib_is_constant_evaluated - if (_STD is_constant_evaluated()) { - for (; _UFirst != _ULast && _UFirst != --_ULast; ++_UFirst) { - _STD iter_swap(_UFirst, _ULast); - } - } else + if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated { __std_reverse_trivially_swappable_2(_UFirst, _ULast); + return; } } else if constexpr (_Allow_vectorization && sizeof(_Elem) == 4) { #ifdef __cpp_lib_is_constant_evaluated - if (_STD is_constant_evaluated()) { - for (; _UFirst != _ULast && _UFirst != --_ULast; ++_UFirst) { - _STD iter_swap(_UFirst, _ULast); - } - } else + if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated { __std_reverse_trivially_swappable_4(_UFirst, _ULast); + return; } } else if constexpr (_Allow_vectorization && sizeof(_Elem) == 8) { #ifdef __cpp_lib_is_constant_evaluated - if (_STD is_constant_evaluated()) { - for (; _UFirst != _ULast && _UFirst != --_ULast; ++_UFirst) { - _STD iter_swap(_UFirst, _ULast); - } - } else + if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated { __std_reverse_trivially_swappable_8(_UFirst, _ULast); + return; } - } else + } #endif // (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_CEE_PURE) && !defined(_M_HYBRID) - { - for (; _UFirst != _ULast && _UFirst != --_ULast; ++_UFirst) { - _STD iter_swap(_UFirst, _ULast); - } + + for (; _UFirst != _ULast && _UFirst != --_ULast; ++_UFirst) { + _STD iter_swap(_UFirst, _ULast); } } #else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv From b10ada4a4470869ee9302c8b447e7dbcd62d0a4e Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Tue, 21 Jan 2020 19:48:06 -0800 Subject: [PATCH 3/5] Stephan product code PR comments: * _Swap_ranges_unchecked => _CONSTEXPR20 * _Idl_dist_add => _NODISCARD (and remove DinkumComments) * is_permutation => _NODISCARD * Add yvals_core.h comments. --- stl/inc/algorithm | 11 +++++------ stl/inc/xutility | 2 +- stl/inc/yvals_core.h | 2 ++ 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index ba3e8b614cf..77777c5b4b5 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -1263,7 +1263,7 @@ _NODISCARD _FwdIt1 find_first_of(_ExPo&& _Exec, const _FwdIt1 _First1, const _Fw // FUNCTION TEMPLATE swap_ranges template -constexpr _FwdIt2 _Swap_ranges_unchecked(_FwdIt1 _First1, const _FwdIt1 _Last1, _FwdIt2 _First2) { +_CONSTEXPR20 _FwdIt2 _Swap_ranges_unchecked(_FwdIt1 _First1, const _FwdIt1 _Last1, _FwdIt2 _First2) { // swap [_First1, _Last1) with [_First2, ...), no special optimization for (; _First1 != _Last1; ++_First1, (void) ++_First2) { _STD iter_swap(_First1, _First2); @@ -2994,23 +2994,22 @@ _NODISCARD _CONSTEXPR20 bool binary_search(_FwdIt _First, _FwdIt _Last, const _T } // FUNCTION TEMPLATE merge -constexpr _Distance_unknown _Idl_dist_add(_Distance_unknown, _Distance_unknown) { - // combine _Idl_distance results (both unknown) +_NODISCARD constexpr _Distance_unknown _Idl_dist_add(_Distance_unknown, _Distance_unknown) { return {}; } template -constexpr _Distance_unknown _Idl_dist_add(_Diff1, _Distance_unknown) { // combine _Idl_distance results (right unknown) +_NODISCARD constexpr _Distance_unknown _Idl_dist_add(_Diff1, _Distance_unknown) { return {}; } template -constexpr _Distance_unknown _Idl_dist_add(_Distance_unknown, _Diff2) { // combine _Idl_distance results (left unknown) +_NODISCARD constexpr _Distance_unknown _Idl_dist_add(_Distance_unknown, _Diff2) { return {}; } template -constexpr auto _Idl_dist_add(_Diff1 _Lhs, _Diff2 _Rhs) { // combine _Idl_distance results (both known) +_NODISCARD constexpr auto _Idl_dist_add(_Diff1 _Lhs, _Diff2 _Rhs) { return _Lhs + _Rhs; } diff --git a/stl/inc/xutility b/stl/inc/xutility index ed460aa7ac6..7a4d44fdcff 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4865,7 +4865,7 @@ _NODISCARD _CONSTEXPR20 bool is_permutation( #endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS template -_CONSTEXPR20 bool is_permutation(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2) { +_NODISCARD _CONSTEXPR20 bool is_permutation(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2) { // test if [_First1, _Last1) == permuted [_First2, ...) return _STD is_permutation(_First1, _Last1, _First2, equal_to<>()); } diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index e5122427498..11e70088ee8 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -39,6 +39,7 @@ // P0063R3 C11 Standard Library // P0074R0 owner_less<> // P0092R1 floor(), ceil(), round(), abs() +// P0202R3 constexpr For And exchange() // P0340R3 SFINAE-Friendly underlying_type // P0414R2 shared_ptr, shared_ptr // P0418R2 atomic compare_exchange memory_order Requirements @@ -54,6 +55,7 @@ // P0771R1 noexcept For std::function's Move Constructor // P0777R1 Avoiding Unnecessary decay // P0809R0 Comparing Unordered Containers +// P0879R0 constexpr For Swapping Functions // P0941R2 Feature-Test Macros // P0972R0 noexcept For zero(), min(), max() // P1164R1 Making create_directory() Intuitive From e307d2f96390022ad124494fbead71b5c953c59d Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Tue, 21 Jan 2020 20:22:25 -0800 Subject: [PATCH 4/5] Delete unused _Copy_n_core and TRANSITION, DevCom-889321 comment. --- stl/inc/xutility | 4 ---- 1 file changed, 4 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 7a4d44fdcff..761f5b9f979 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -3662,9 +3662,6 @@ _DestTy* copy(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _DestTy (&_Dest)[_DestSize #endif // _HAS_CXX17 // FUNCTION TEMPLATE copy_n -template -constexpr _OutIt _Copy_n_core(_InIt _First, _Diff _Count, _OutIt _Dest) {} - #if _HAS_IF_CONSTEXPR template _CONSTEXPR20_ICE _OutIt copy_n(_InIt _First, _Diff _Count_raw, _OutIt _Dest) { @@ -4966,7 +4963,6 @@ _CONSTEXPR20_ICE void reverse(const _BidIt _First, const _BidIt _Last) { // reve constexpr bool _Allow_vectorization = conjunction_v, _Is_trivially_swappable<_Elem>, negation>>; - // repeated loop is TRANSITION, DevCom-889321 if constexpr (_Allow_vectorization && sizeof(_Elem) == 1) { #ifdef __cpp_lib_is_constant_evaluated if (!_STD is_constant_evaluated()) From be0738f3ce1125d5fa8f8624dfdbe0b4b7c8a5c9 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Wed, 22 Jan 2020 12:05:35 -0800 Subject: [PATCH 5/5] Put the comments in the right place and remove phantom braces. --- stl/inc/xutility | 20 ++++++++------------ stl/inc/yvals_core.h | 4 ++-- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 761f5b9f979..c329ecee9b2 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4574,13 +4574,11 @@ _NODISCARD _CONSTEXPR20_ICE bool _Lex_compare_unchecked( return _Lex_compare_unchecked(_First1, _Last1, _First2, _Last2, _Pred, _Lex_compare_optimize{}); } #endif // __cpp_lib_is_constant_evaluated - { - (void) _Pred; - const auto _Num1 = static_cast(_Last1 - _First1); - const auto _Num2 = static_cast(_Last2 - _First2); - const int _Ans = _CSTD memcmp(_First1, _First2, _Num1 < _Num2 ? _Num1 : _Num2); - return _Memcmp_pr{}(_Ans, 0) || (_Ans == 0 && _Num1 < _Num2); - } + (void) _Pred; + const auto _Num1 = static_cast(_Last1 - _First1); + const auto _Num2 = static_cast(_Last2 - _First2); + const int _Ans = _CSTD memcmp(_First1, _First2, _Num1 < _Num2 ? _Num1 : _Num2); + return _Memcmp_pr{}(_Ans, 0) || (_Ans == 0 && _Num1 < _Num2); } template @@ -4690,11 +4688,9 @@ _NODISCARD _CONSTEXPR20_ICE _InIt _Find_unchecked1(_InIt _First, const _InIt _La return _Find_unchecked1(_First, _Last, _Val, false_type{}); } #endif // __cpp_lib_is_constant_evaluated - { - _First = static_cast<_InIt>( - _CSTD memchr(_First, static_cast(_Val), static_cast(_Last - _First))); - return _First ? _First : _Last; - } + _First = + static_cast<_InIt>(_CSTD memchr(_First, static_cast(_Val), static_cast(_Last - _First))); + return _First ? _First : _Last; } template diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 11e70088ee8..06594e2bf82 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -39,7 +39,6 @@ // P0063R3 C11 Standard Library // P0074R0 owner_less<> // P0092R1 floor(), ceil(), round(), abs() -// P0202R3 constexpr For And exchange() // P0340R3 SFINAE-Friendly underlying_type // P0414R2 shared_ptr, shared_ptr // P0418R2 atomic compare_exchange memory_order Requirements @@ -55,7 +54,6 @@ // P0771R1 noexcept For std::function's Move Constructor // P0777R1 Avoiding Unnecessary decay // P0809R0 Comparing Unordered Containers -// P0879R0 constexpr For Swapping Functions // P0941R2 Feature-Test Macros // P0972R0 noexcept For zero(), min(), max() // P1164R1 Making create_directory() Intuitive @@ -130,6 +128,7 @@ // _HAS_CXX20 directly controls: // P0020R6 atomic, atomic, atomic // P0122R7 +// P0202R3 constexpr For And exchange() // P0318R1 unwrap_reference, unwrap_ref_decay // P0325R4 to_array() // P0356R5 bind_front() @@ -157,6 +156,7 @@ // P0769R2 shift_left(), shift_right() // P0811R3 midpoint(), lerp() // (partially implemented, lerp() not yet constexpr) +// P0879R0 constexpr For Swapping Functions // P0887R1 type_identity // P0896R4 Ranges // (partially implemented)