diff --git a/stl/inc/algorithm b/stl/inc/algorithm index d9422ad414..a3a8d87b1b 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -1841,9 +1841,9 @@ namespace ranges { template requires indirectly_movable<_It1, _It2> _NODISCARD constexpr _It2 _Move_backward_common(const _It1 _First, _It1 _Last, _It2 _Result) { - if constexpr (_Ptr_move_cat<_It1, _It2>::_Trivially_copyable) { + if constexpr (_Memmove_in_move_is_safe<_It1, _It2>) { if (!_STD is_constant_evaluated()) { - return _Copy_backward_memmove(_First, _Last, _Result); + return _Memmove_backward(_First, _Last, _Result); } } @@ -2208,7 +2208,7 @@ namespace ranges { template _NODISCARD _CONSTEXPR20 bool _Equal_rev_pred_unchecked(_InIt1 _First1, _InIt2 _First2, const _InIt2 _Last2, _Pr _Pred) { // compare [_First1, ...) to [_First2, _Last2) - if constexpr (_Equal_memcmp_is_safe<_InIt1, _InIt2, _Pr>) { + if constexpr (_Memcmp_in_equal_is_safe<_InIt1, _InIt2, _Pr>) { #ifdef __cpp_lib_is_constant_evaluated if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated @@ -2229,7 +2229,7 @@ _NODISCARD _CONSTEXPR20 bool _Equal_rev_pred_unchecked(_InIt1 _First1, _InIt2 _F return true; } #else // ^^^ _HAS_IF_CONSTEXPR ^^^ // vvv !_HAS_IF_CONSTEXPR vvv -template , int> = 0> +template , int> = 0> bool _Equal_rev_pred_unchecked(_InIt1 _First1, _InIt2 _First2, const _InIt2 _Last2, _Pr _Pred) { // compare [_First1, ...) to [_First2, _Last2), no special optimization for (; _First2 != _Last2; ++_First1, (void) ++_First2) { @@ -2241,7 +2241,7 @@ bool _Equal_rev_pred_unchecked(_InIt1 _First1, _InIt2 _First2, const _InIt2 _Las return true; } -template , int> = 0> +template , int> = 0> bool _Equal_rev_pred_unchecked(const _InIt1 _First1, const _InIt2 _First2, const _InIt2 _Last2, _Pr) { // compare [_First1, ...) to [_First2, _Last2), memcmp optimization const auto _First1_ch = reinterpret_cast(_First1); @@ -2382,7 +2382,7 @@ namespace ranges { // clang-format off template concept _Equal_rev_pred_can_memcmp = is_same_v<_Pj1, identity> && is_same_v<_Pj2, identity> - && is_same_v<_Se2, _It2> && _Equal_memcmp_is_safe<_It1, _It2, _Pr>; + && is_same_v<_Se2, _It2> && _Memcmp_in_equal_is_safe<_It1, _It2, _Pr>; template _Se2, class _Pr, class _Pj1, class _Pj2> requires indirectly_comparable<_It1, _It2, _Pr, _Pj1, _Pj2> @@ -3929,7 +3929,7 @@ namespace ranges { _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_STD move(_First)); const auto _ULast = _Get_unwrapped(_STD move(_Last)); - if constexpr (_Fill_memset_is_safe) { + if constexpr (_Memset_in_fill_is_safe) { #ifdef __cpp_lib_is_constant_evaluated if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated @@ -3969,7 +3969,7 @@ namespace ranges { constexpr _It operator()(_It _First, iter_difference_t<_It> _Count, const _Ty& _Value) const { if (_Count > 0) { auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); - if constexpr (_Fill_memset_is_safe) { + if constexpr (_Memset_in_fill_is_safe) { #ifdef __cpp_lib_is_constant_evaluated if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated diff --git a/stl/inc/memory b/stl/inc/memory index d168f49e69..09368c5b42 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -107,8 +107,8 @@ namespace ranges { _STL_INTERNAL_STATIC_ASSERT(_No_throw_sentinel_for<_OSe, _Out>); _STL_INTERNAL_STATIC_ASSERT(constructible_from, iter_reference_t<_It>>); - if constexpr (is_same_v<_Se, _It> && _Ptr_copy_cat<_It, _Out>::_Really_trivial) { - return _Copy_memcpy_common(_IFirst, _ILast, _OFirst, _OLast); + if constexpr (is_same_v<_Se, _It> && _Memmove_in_uninitialized_copy_is_safe<_It, _Out>) { + return _Memmove_forward_common(_IFirst, _ILast, _OFirst, _OLast); } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; @@ -137,8 +137,8 @@ _NoThrowFwdIt uninitialized_copy_n(const _InIt _First, const _Diff _Count_raw, _ auto _UFirst = _Get_unwrapped_n(_First, _Count); auto _UDest = _Get_unwrapped_n(_Dest, _Count); - if constexpr (_Ptr_copy_cat::_Really_trivial) { - _UDest = _Copy_memmove(_UFirst, _UFirst + _Count, _UDest); + if constexpr (_Memmove_in_uninitialized_copy_is_safe) { + _UDest = _Memmove_forward(_UFirst, _UFirst + _Count, _UDest); } else { _Uninitialized_backout _Backout{_UDest}; @@ -168,7 +168,7 @@ _NoThrowFwdIt _Uninitialized_copy_n_unchecked2(_InIt _First, _Diff _Count, const template _NoThrowFwdIt _Uninitialized_copy_n_unchecked2(const _InIt _First, const _Diff _Count, const _NoThrowFwdIt _Dest, true_type) { // copy [_First, _First + _Count) to [_Dest, ...), memmove optimization - return _Copy_memmove(_First, _First + _Count, _Dest); + return _Memmove_forward(_First, _First + _Count, _Dest); } template @@ -181,8 +181,9 @@ _NoThrowFwdIt uninitialized_copy_n(const _InIt _First, const _Diff _Count_raw, _ auto _UFirst = _Get_unwrapped_n(_First, _Count); auto _UDest = _Get_unwrapped_n(_Dest, _Count); - _Seek_wrapped(_Dest, _Uninitialized_copy_n_unchecked2(_UFirst, _Count, _UDest, - bool_constant<_Ptr_copy_cat::_Really_trivial>{})); + _Seek_wrapped( + _Dest, _Uninitialized_copy_n_unchecked2(_UFirst, _Count, _UDest, + bool_constant<_Memmove_in_uninitialized_copy_is_safe>{})); return _Dest; } #endif // _HAS_IF_CONSTEXPR @@ -212,8 +213,8 @@ namespace ranges { auto _IFirst = _Get_unwrapped_n(_STD move(_First1), _Count); auto _OFirst = _Get_unwrapped(_STD move(_First2)); const auto _OLast = _Get_unwrapped(_STD move(_Last2)); - if constexpr (_Ptr_copy_cat<_It, _Out>::_Really_trivial) { - _OFirst = _Copy_memcpy_common(_IFirst, _IFirst + _Count, _OFirst, _OLast); + if constexpr (_Memmove_in_uninitialized_copy_is_safe<_It, _Out>) { + _OFirst = _Memmove_forward_common(_IFirst, _IFirst + _Count, _OFirst, _OLast); } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; @@ -299,8 +300,8 @@ namespace ranges { _STL_INTERNAL_STATIC_ASSERT(_No_throw_sentinel_for<_OSe, _Out>); _STL_INTERNAL_STATIC_ASSERT(constructible_from, iter_rvalue_reference_t<_It>>); - if constexpr (is_same_v<_Se, _It> && _Ptr_move_cat<_It, _Out>::_Really_trivial) { - return _Copy_memcpy_common(_IFirst, _ILast, _OFirst, _OLast); + if constexpr (is_same_v<_Se, _It> && _Memmove_in_uninitialized_move_is_safe<_It, _Out>) { + return _Memmove_forward_common(_IFirst, _ILast, _OFirst, _OLast); } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; @@ -328,8 +329,8 @@ pair<_InIt, _NoThrowFwdIt> uninitialized_move_n(_InIt _First, const _Diff _Count auto _UFirst = _Get_unwrapped_n(_First, _Count); auto _UDest = _Get_unwrapped_n(_Dest, _Count); - if constexpr (_Ptr_move_cat::_Really_trivial) { - _UDest = _Copy_memmove(_UFirst, _UFirst + _Count, _UDest); + if constexpr (_Memmove_in_uninitialized_move_is_safe) { + _UDest = _Memmove_forward(_UFirst, _UFirst + _Count, _UDest); _UFirst += _Count; } else { _Uninitialized_backout _Backout{_UDest}; @@ -373,8 +374,8 @@ namespace ranges { auto _IFirst = _Get_unwrapped_n(_STD move(_First1), _Count); auto _OFirst = _Get_unwrapped(_STD move(_First2)); const auto _OLast = _Get_unwrapped(_STD move(_Last2)); - if constexpr (_Ptr_move_cat<_It, _Out>::_Really_trivial) { - _OFirst = _Copy_memcpy_common(_IFirst, _IFirst + _Count, _OFirst, _OLast); + if constexpr (_Memmove_in_uninitialized_move_is_safe<_It, _Out>) { + _OFirst = _Memmove_forward_common(_IFirst, _IFirst + _Count, _OFirst, _OLast); } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; @@ -426,7 +427,7 @@ namespace ranges { _STL_INTERNAL_STATIC_ASSERT(_No_throw_sentinel_for<_Se, _It>); _STL_INTERNAL_STATIC_ASSERT(constructible_from, const _Ty&>); - if constexpr (_Fill_memset_is_safe<_It, _Ty>) { + if constexpr (_Memset_in_fill_is_safe<_It, _Ty>) { const auto _OFinal = _RANGES next(_OFirst, _STD move(_OLast)); const auto _Diff = static_cast(_OFinal - _OFirst); _Fill_memset(_OFirst, _Val, _Diff); @@ -458,7 +459,7 @@ _NoThrowFwdIt uninitialized_fill_n(_NoThrowFwdIt _First, const _Diff _Count_raw, } auto _UFirst = _Get_unwrapped_n(_First, _Count); - if constexpr (_Fill_memset_is_safe<_Unwrapped_n_t, _Tval>) { + if constexpr (_Memset_in_fill_is_safe<_Unwrapped_n_t, _Tval>) { _Fill_memset(_UFirst, _Val, static_cast(_Count)); _UFirst += _Count; } else { @@ -505,7 +506,7 @@ _NoThrowFwdIt uninitialized_fill_n(_NoThrowFwdIt _First, const _Diff _Count_raw, auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); _Seek_wrapped(_First, _Uninitialized_fill_n_unchecked1(_STD move(_UFirst), _Count, _Val, - bool_constant<_Fill_memset_is_safe<_Unwrapped_t<_NoThrowFwdIt>, _Tval>>{})); + bool_constant<_Memset_in_fill_is_safe<_Unwrapped_t<_NoThrowFwdIt>, _Tval>>{})); return _First; } #endif // _HAS_IF_CONSTEXPR @@ -527,7 +528,7 @@ namespace ranges { } auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); - if constexpr (_Fill_memset_is_safe<_It, _Ty>) { + if constexpr (_Memset_in_fill_is_safe<_It, _Ty>) { _Fill_memset(_UFirst, _Val, static_cast(_Count)); _Seek_wrapped(_First, _UFirst + _Count); } else { @@ -2320,7 +2321,7 @@ struct _Reverse_destroy_multidimensional_n_guard { template void _Uninitialized_copy_multidimensional(const _Ty (&_In)[_Size], _Ty (&_Out)[_Size]) { if constexpr (is_trivial_v<_Ty>) { - _Copy_memmove(_In, _In + _Size, _Out); + _Memmove_forward(_In, _In + _Size, _Out); } else if constexpr (is_array_v<_Ty>) { _Reverse_destroy_multidimensional_n_guard<_Ty> _Guard{_Out, 0}; for (size_t& _Idx = _Guard._Index; _Idx < _Size; ++_Idx) { @@ -2383,7 +2384,7 @@ void _Uninitialized_fill_multidimensional_n(_Ty* const _Out, const size_t _Size, _Uninitialized_copy_multidimensional(_Val, _Out[_Idx]); // intentionally copy, not fill } _Guard._Target = nullptr; - } else if constexpr (_Fill_memset_is_safe<_Ty*, _Ty>) { + } else if constexpr (_Memset_in_fill_is_safe<_Ty*, _Ty>) { _Fill_memset(_Out, _Val, _Size); } else { _Uninitialized_rev_destroying_backout _Backout{_Out}; @@ -2683,7 +2684,7 @@ template void _Uninitialized_copy_multidimensional_al(const _Ty (&_In)[_Size], _Ty (&_Out)[_Size], _Alloc& _Al) { using _Item = remove_all_extents_t<_Ty>; if constexpr (conjunction_v, _Uses_default_construct<_Alloc, _Item*, const _Item&>>) { - _Copy_memmove(_In, _In + _Size, _Out); + _Memmove_forward(_In, _In + _Size, _Out); } else if constexpr (is_array_v<_Ty>) { _Reverse_destroy_multidimensional_n_al_guard<_Ty, _Alloc> _Guard{_Out, 0, _Al}; for (size_t& _Idx = _Guard._Index; _Idx < _Size; ++_Idx) { @@ -2727,7 +2728,8 @@ void _Uninitialized_fill_multidimensional_n_al(_Ty* const _Out, const size_t _Si _Uninitialized_copy_multidimensional_al(_Val, _Out[_Idx], _Al); // intentionally copy, not fill } _Guard._Target = nullptr; - } else if constexpr (_Fill_memset_is_safe<_Ty*, _Ty> && _Uses_default_construct<_Alloc, _Ty*, const _Ty&>::value) { + } else if constexpr (_Memset_in_fill_is_safe<_Ty*, + _Ty> && _Uses_default_construct<_Alloc, _Ty*, const _Ty&>::value) { _Fill_memset(_Out, _Val, _Size); } else { _Uninitialized_rev_destroying_backout_al _Backout{_Out, _Al}; diff --git a/stl/inc/vector b/stl/inc/vector index 5a08f9d8f9..348c80a216 100644 --- a/stl/inc/vector +++ b/stl/inc/vector @@ -636,13 +636,13 @@ private: const auto _Oldcapacity = static_cast(_My_data._Myend - _Myfirst); #if _HAS_IF_CONSTEXPR - if constexpr (conjunction_v::_Trivially_copyable>, + if constexpr (conjunction_v>, _Uses_default_construct<_Alty, _Ty*, _Ty>, _Uses_default_destroy<_Alty, _Ty*>>) { if (_Newsize > _Oldcapacity) { _Clear_and_reserve_geometric(_Newsize); } - _Mylast = _Refancy(_Copy_memmove(_Unfancy(_First), _Unfancy(_Last), _Unfancy(_Myfirst))); + _Mylast = _Refancy(_Memmove_forward(_Unfancy(_First), _Unfancy(_Last), _Unfancy(_Myfirst))); } else #endif // _HAS_IF_CONSTEXPR { @@ -1108,7 +1108,7 @@ private: _My_data._Orphan_all(); #if _HAS_IF_CONSTEXPR - if constexpr (conjunction_v::_Trivially_copyable>, + if constexpr (conjunction_v>, _Uses_default_construct<_Alty, _Ty*, decltype(*_First)>, _Uses_default_destroy<_Alty, _Ty*>>) { const auto _Oldcapacity = static_cast(_Myend - _Myfirst); @@ -1116,7 +1116,7 @@ private: _Clear_and_reserve_geometric(_Newsize); } - _Mylast = _Refancy(_Copy_memmove(_First, _Last, _Unfancy(_Myfirst))); + _Mylast = _Refancy(_Memmove_forward(_First, _Last, _Unfancy(_Myfirst))); } else #endif // _HAS_IF_CONSTEXPR { diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 61482e6f83..ee80d309a3 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1424,18 +1424,18 @@ struct _Uninitialized_backout { // struct to undo partially constructed ranges i _Uninitialized_backout(const _Uninitialized_backout&) = delete; _Uninitialized_backout& operator=(const _Uninitialized_backout&) = delete; - ~_Uninitialized_backout() { + _CONSTEXPR20_DYNALLOC ~_Uninitialized_backout() { _Destroy_range(_First, _Last); } template - void _Emplace_back(_Types&&... _Vals) { + _CONSTEXPR20_DYNALLOC void _Emplace_back(_Types&&... _Vals) { // construct a new element at *_Last and increment _Construct_in_place(*_Last, _STD forward<_Types>(_Vals)...); ++_Last; } - _NoThrowFwdIt _Release() { // suppress any exception handling backout and return _Last + constexpr _NoThrowFwdIt _Release() { // suppress any exception handling backout and return _Last _First = _Last; return _Last; } @@ -1469,18 +1469,23 @@ namespace ranges { // FUNCTION TEMPLATE _Uninitialized_move_unchecked #if _HAS_IF_CONSTEXPR template -_NoThrowFwdIt _Uninitialized_move_unchecked(_InIt _First, const _InIt _Last, _NoThrowFwdIt _Dest) { +_CONSTEXPR20_DYNALLOC _NoThrowFwdIt _Uninitialized_move_unchecked( + _InIt _First, const _InIt _Last, _NoThrowFwdIt _Dest) { // move [_First, _Last) to raw [_Dest, ...) - if constexpr (_Ptr_move_cat<_InIt, _NoThrowFwdIt>::_Really_trivial) { - return _Copy_memmove(_First, _Last, _Dest); - } else { - _Uninitialized_backout<_NoThrowFwdIt> _Backout{_Dest}; - for (; _First != _Last; ++_First) { - _Backout._Emplace_back(_STD move(*_First)); + if constexpr (_Memmove_in_uninitialized_move_is_safe<_InIt, _NoThrowFwdIt>) { +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + return _Memmove_forward(_First, _Last, _Dest); } - - return _Backout._Release(); } + _Uninitialized_backout<_NoThrowFwdIt> _Backout{_Dest}; + for (; _First != _Last; ++_First) { + _Backout._Emplace_back(_STD move(*_First)); + } + + return _Backout._Release(); } #else // ^^^ _HAS_IF_CONSTEXPR ^^^ // vvv !_HAS_IF_CONSTEXPR vvv template @@ -1498,14 +1503,14 @@ template _NoThrowFwdIt _Uninitialized_move_unchecked1( const _InIt _First, const _InIt _Last, const _NoThrowFwdIt _Dest, true_type) { // move [_First, _Last) to raw [_Dest, ...), memmove optimization - return _Copy_memmove(_First, _Last, _Dest); + return _Memmove_forward(_First, _Last, _Dest); } template _NoThrowFwdIt _Uninitialized_move_unchecked(_InIt _First, const _InIt _Last, _NoThrowFwdIt _Dest) { // move [_First, _Last) to raw [_Dest, ...), choose optimization return _Uninitialized_move_unchecked1( - _First, _Last, _Dest, bool_constant<_Ptr_move_cat<_InIt, _NoThrowFwdIt>::_Really_trivial>{}); + _First, _Last, _Dest, bool_constant<_Memmove_in_uninitialized_move_is_safe<_InIt, _NoThrowFwdIt>>{}); } #endif // _HAS_IF_CONSTEXPR @@ -1553,9 +1558,9 @@ _Alloc_ptr_t<_Alloc> _Uninitialized_copy( auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); - if constexpr (conjunction_v::_Really_trivial>, + if constexpr (conjunction_v>, _Uses_default_construct<_Alloc, _Ptrval, decltype(*_UFirst)>>) { - _Copy_memmove(_UFirst, _ULast, _Unfancy(_Dest)); + _Memmove_forward(_UFirst, _ULast, _Unfancy(_Dest)); _Dest += _ULast - _UFirst; } else { _Uninitialized_backout_al<_Alloc> _Backout{_Dest, _Al}; @@ -1585,7 +1590,7 @@ template _Alloc_ptr_t<_Alloc> _Uninitialized_copy_al_unchecked( const _InIt _First, const _InIt _Last, const _Alloc_ptr_t<_Alloc> _Dest, _Alloc&, true_type) { // copy [_First, _Last) to raw _Dest, using default _Alloc construct, memmove optimization - return _Copy_memmove(_First, _Last, _Unfancy(_Dest)); + return _Memmove_forward(_First, _Last, _Unfancy(_Dest)); } template @@ -1601,13 +1606,35 @@ _Alloc_ptr_t<_Alloc> _Uninitialized_copy( using _Ptrval = typename _Alloc::value_type*; return _Uninitialized_copy_al_unchecked(_UFirst, _ULast, _Dest, _Al, - bool_constant::_Really_trivial>, + bool_constant>, _Uses_default_construct<_Alloc, _Ptrval, decltype(*_UFirst)>>>{}); } #endif // _HAS_IF_CONSTEXPR // FUNCTION TEMPLATE uninitialized_copy #if _HAS_IF_CONSTEXPR +template +_CONSTEXPR20_DYNALLOC _NoThrowFwdIt _Uninitialized_copy_unchecked( + _InIt _First, const _InIt _Last, _NoThrowFwdIt _Dest) { + // copy [_First, _Last) to raw [_Dest, ...) + if constexpr (_Memmove_in_uninitialized_copy_is_safe<_InIt, _NoThrowFwdIt>) { +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + return _Memmove_forward(_First, _Last, _Dest); + } + } + _Uninitialized_backout<_NoThrowFwdIt> _Backout{_Dest}; + for (; _First != _Last; ++_First) { + _Backout._Emplace_back(*_First); + } + + _Dest = _Backout._Release(); + + return _Dest; +} + template _NoThrowFwdIt uninitialized_copy(const _InIt _First, const _InIt _Last, _NoThrowFwdIt _Dest) { // copy [_First, _Last) to raw [_Dest, ...) @@ -1615,18 +1642,7 @@ _NoThrowFwdIt uninitialized_copy(const _InIt _First, const _InIt _Last, _NoThrow auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); auto _UDest = _Get_unwrapped_n(_Dest, _Idl_distance<_InIt>(_UFirst, _ULast)); - if constexpr (_Ptr_copy_cat::_Really_trivial) { - _UDest = _Copy_memmove(_UFirst, _ULast, _UDest); - } else { - _Uninitialized_backout _Backout{_UDest}; - for (; _UFirst != _ULast; ++_UFirst) { - _Backout._Emplace_back(*_UFirst); - } - - _UDest = _Backout._Release(); - } - - _Seek_wrapped(_Dest, _UDest); + _Seek_wrapped(_Dest, _Uninitialized_copy_unchecked(_UFirst, _ULast, _UDest)); return _Dest; } #else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv @@ -1645,7 +1661,7 @@ template _NoThrowFwdIt _Uninitialized_copy_unchecked( const _InIt _First, const _InIt _Last, const _NoThrowFwdIt _Dest, true_type) { // copy [_First, _Last) to raw [_Dest, ...), memmove optimization - return _Copy_memmove(_First, _Last, _Dest); + return _Memmove_forward(_First, _Last, _Dest); } template @@ -1655,8 +1671,9 @@ _NoThrowFwdIt uninitialized_copy(const _InIt _First, const _InIt _Last, _NoThrow auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); auto _UDest = _Get_unwrapped_n(_Dest, _Idl_distance<_InIt>(_UFirst, _ULast)); - _Seek_wrapped(_Dest, _Uninitialized_copy_unchecked(_UFirst, _ULast, _UDest, - bool_constant<_Ptr_copy_cat::_Really_trivial>{})); + _Seek_wrapped( + _Dest, _Uninitialized_copy_unchecked(_UFirst, _ULast, _UDest, + bool_constant<_Memmove_in_uninitialized_copy_is_safe>{})); return _Dest; } #endif // _HAS_IF_CONSTEXPR @@ -1671,9 +1688,9 @@ _Alloc_ptr_t<_Alloc> _Uninitialized_move( using _Ptrval = typename _Alloc::value_type*; auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); - if constexpr (conjunction_v::_Really_trivial>, + if constexpr (conjunction_v>, _Uses_default_construct<_Alloc, _Ptrval, decltype(_STD move(*_UFirst))>>) { - _Copy_memmove(_UFirst, _ULast, _Unfancy(_Dest)); + _Memmove_forward(_UFirst, _ULast, _Unfancy(_Dest)); return _Dest + (_ULast - _UFirst); } else { _Uninitialized_backout_al<_Alloc> _Backout{_Dest, _Al}; @@ -1701,7 +1718,7 @@ template _Alloc_ptr_t<_Alloc> _Uninitialized_move_al_unchecked( const _InIt _First, const _InIt _Last, _Alloc_ptr_t<_Alloc> _Dest, _Alloc&, true_type) { // move [_First, _Last) to raw _Dest, using default _Alloc construct, memmove optimization - _Copy_memmove(_First, _Last, _Unfancy(_Dest)); + _Memmove_forward(_First, _Last, _Unfancy(_Dest)); return _Dest + (_Last - _First); } @@ -1718,10 +1735,10 @@ _Alloc_ptr_t<_Alloc> _Uninitialized_move( // clang-format on using _Ptrval = typename _Alloc::value_type*; - _Seek_wrapped( - _Dest, _Uninitialized_move_al_unchecked(_UFirst, _ULast, _UDest, _Al, - bool_constant < _Ptr_move_cat::_Really_trivial - && _Uses_default_construct<_Alloc, _Ptrval, decltype(_STD move(*_UFirst))>::value > {})); + _Seek_wrapped(_Dest, + _Uninitialized_move_al_unchecked(_UFirst, _ULast, _UDest, _Al, + bool_constant < _Memmove_in_uninitialized_move_is_safe && _Uses_default_construct<_Alloc, _Ptrval, decltype(_STD move(*_UFirst))>::value > {})); return _Dest; } #endif // _HAS_IF_CONSTEXPR @@ -1733,7 +1750,7 @@ _Alloc_ptr_t<_Alloc> _Uninitialized_fill_n( _Alloc_ptr_t<_Alloc> _First, _Alloc_size_t<_Alloc> _Count, const typename _Alloc::value_type& _Val, _Alloc& _Al) { // copy _Count copies of _Val to raw _First, using _Al using _Ty = typename _Alloc::value_type; - if constexpr (_Fill_memset_is_safe<_Ty*, _Ty> && _Uses_default_construct<_Alloc, _Ty*, _Ty>::value) { + if constexpr (_Memset_in_fill_is_safe<_Ty*, _Ty> && _Uses_default_construct<_Alloc, _Ty*, _Ty>::value) { _Fill_memset(_Unfancy(_First), _Val, static_cast(_Count)); return _First + _Count; } else { @@ -1772,7 +1789,7 @@ _Alloc_ptr_t<_Alloc> _Uninitialized_fill_n(_Alloc_ptr_t<_Alloc> _First, const _A // copy _Count copies of _Val to raw _First, using _Al using _Ty = typename _Alloc::value_type; return _Uninit_alloc_fill_n1(_First, _Count, _Val, _Al, - bool_constant < _Fill_memset_is_safe<_Ty*, _Ty> && _Uses_default_construct<_Alloc, _Ty*, _Ty>::value > {}); + bool_constant < _Memset_in_fill_is_safe<_Ty*, _Ty> && _Uses_default_construct<_Alloc, _Ty*, _Ty>::value > {}); } #endif // _HAS_IF_CONSTEXPR @@ -1784,7 +1801,7 @@ void uninitialized_fill(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last, c _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); - if constexpr (_Fill_memset_is_safe<_Unwrapped_t, _Tval>) { + if constexpr (_Memset_in_fill_is_safe<_Unwrapped_t, _Tval>) { _Fill_memset(_UFirst, _Val, static_cast(_ULast - _UFirst)); } else { _Uninitialized_backout<_Unwrapped_t> _Backout{_UFirst}; @@ -1821,7 +1838,7 @@ void uninitialized_fill(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last, c _Adl_verify_range(_First, _Last); const auto _UFirst = _Get_unwrapped(_First); _Uninitialized_fill_unchecked(_UFirst, _Get_unwrapped(_Last), _Val, - bool_constant<_Fill_memset_is_safe<_Unwrapped_t, _Tval>>{}); + bool_constant<_Memset_in_fill_is_safe<_Unwrapped_t, _Tval>>{}); } #endif // _HAS_IF_CONSTEXPR diff --git a/stl/inc/xutility b/stl/inc/xutility index fa244555d0..03a4343867 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -121,7 +121,7 @@ struct _Get_rebind_alias<_Ty, _Other, void_t -_NODISCARD void* _Voidify_iter(_Iter _It) noexcept { +_NODISCARD constexpr void* _Voidify_iter(_Iter _It) noexcept { #if _HAS_IF_CONSTEXPR if constexpr (is_pointer_v<_Iter>) { return const_cast(static_cast(_It)); @@ -134,13 +134,14 @@ _NODISCARD void* _Voidify_iter(_Iter _It) noexcept { // FUNCTION TEMPLATE _Construct_in_place template -void _Construct_in_place(_Ty& _Obj, _Types&&... _Args) noexcept(is_nothrow_constructible_v<_Ty, _Types...>) { +_CONSTEXPR20_DYNALLOC void _Construct_in_place(_Ty& _Obj, _Types&&... _Args) noexcept( + is_nothrow_constructible_v<_Ty, _Types...>) { ::new (_Voidify_iter(_STD addressof(_Obj))) _Ty(_STD forward<_Types>(_Args)...); } // FUNCTION TEMPLATE _Default_construct_in_place template -void _Default_construct_in_place(_Ty& _Obj) noexcept(is_nothrow_default_constructible_v<_Ty>) { +_CONSTEXPR20_DYNALLOC void _Default_construct_in_place(_Ty& _Obj) noexcept(is_nothrow_default_constructible_v<_Ty>) { ::new (_Voidify_iter(_STD addressof(_Obj))) _Ty; } @@ -4307,72 +4308,116 @@ 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; -}; +// _Iterators_are_contiguous<_Iter1, _Iter2> reports whether both iterators are known to be contiguous. +// (Without concepts, this detection is limited, which will limit when we can activate certain optimizations.) +#ifdef __cpp_lib_concepts +// When concepts are available, we can detect arbitrary contiguous iterators. +template +_INLINE_VAR constexpr bool _Iterators_are_contiguous = contiguous_iterator<_Iter1> // + && contiguous_iterator<_Iter2>; +#else // ^^^ defined(__cpp_lib_concepts) ^^^ / vvv !defined(__cpp_lib_concepts) vvv +// When concepts aren't available, we can detect pointers. (Iterators should be unwrapped before using this.) +template +_INLINE_VAR constexpr bool _Iterators_are_contiguous = conjunction_v, is_pointer<_Iter2>>; +#endif // ^^^ !defined(__cpp_lib_concepts) ^^^ -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>; +// VARIABLE TEMPLATE _Can_memop +enum class _Memop_cat { + _Copy, + _Copy_uninitialized, + _Move, + _Move_uninitialized, }; -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; -}; +// Integral types are eligible for memcpy in very specific cases. +// * Enumerations are treated as their underlying integral type +// * They must be the same size. (`int == long` is eligible; `int != long long` isn't.) +// * They are either both bool or both non bool +template +struct _Same_size_integral_or_bool + : bool_constant == is_same_v> {}; -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 +_INLINE_VAR constexpr bool _Can_memop_integrals = + conjunction_v, is_integral<_Dest>, _Same_size_integral_or_bool<_Source, _Dest>>; -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; -}; +// Matching integer type are eligible for memcpy +template , _Unwrap_enum_t<_Dest>>> +_INLINE_VAR constexpr bool _Can_memop_elements = _Result; -struct _False_copy_cat { - static constexpr bool _Really_trivial = false; - static constexpr bool _Trivially_copyable = false; -}; +// Pointer elements are eligible for memcpy when they point to the same type, ignoring cv-qualification. +// This handles pointers to object types, pointers to void, and pointers to function types. +// Performance note: This doesn't attempt to handle `object* != void*`. +template +_INLINE_VAR constexpr bool _Can_memop_elements<_Source*, _Dest*, _Cat, false> = + is_same_v, remove_cv_t<_Dest>>; -template -struct _Ptr_copy_cat : _False_copy_cat {}; // unwrap the pointer-like type and dispatch to _Ptr_cat_helper for copy +// Types are eligible for memcpy / memmove when they are trivially copyable. +template +_INLINE_VAR constexpr bool _Can_memop_elements<_Ty, enable_if_t, _Ty>, _Memop_cat::_Copy, false> = + is_trivially_copyable_v<_Ty>; -template -struct _Ptr_copy_cat<_Source*, _Dest*> - : conditional_t, - _Ptr_cat_helper, remove_cv_t<_Dest>>, _False_copy_cat> {}; +template +_INLINE_VAR constexpr bool _Can_memop_elements<_Ty, enable_if_t, _Ty>, _Memop_cat::_Move, false> = + is_trivially_copyable_v<_Ty>; -template -struct _Ptr_copy_cat, _Dest*> : _Ptr_copy_cat<_Source*, _Dest*> {}; +// Types are eligible for memcpy / memmove into uninitialized memory when they are trivial. +template +_INLINE_VAR constexpr bool + _Can_memop_elements<_Ty, enable_if_t, _Ty>, _Memop_cat::_Copy_uninitialized, false> = + is_trivial_v<_Ty>; -template -struct _Ptr_move_cat : _False_copy_cat {}; // unwrap the pointer-like type and dispatch to _Ptr_cat_helper for move +template +_INLINE_VAR constexpr bool + _Can_memop_elements<_Ty, enable_if_t, _Ty>, _Memop_cat::_Move_uninitialized, false> = + is_trivial_v<_Ty>; + +// Different types are eligible for memcpy when they are trivially copy assignable. +template +_INLINE_VAR constexpr bool _Can_assign_elements = is_trivially_assignable_v<_Dest&, _Source&>; +// Different types are eligible for memmove when they are trivially move assignable. template -struct _Ptr_move_cat<_Source*, _Dest*> - : conditional_t, - _Ptr_cat_helper, remove_cv_t<_Dest>>, _False_copy_cat> {}; +_INLINE_VAR constexpr bool _Can_assign_elements<_Source, _Dest, _Memop_cat::_Move> = + is_trivially_assignable_v<_Dest&, _Source&&>; template -struct _Ptr_move_cat, _Dest*> : _Ptr_move_cat<_Source*, _Dest*> {}; +_INLINE_VAR constexpr bool _Can_assign_elements<_Source, _Dest, _Memop_cat::_Move_uninitialized> = + is_trivially_assignable_v<_Dest&, _Source&&>; + +// _Can_memop<_IterSource, _IterDest> reports whether we can activate the memory operation for +// arbitrary iterators. It ignores top-level constness on the source iterators and on the source elements. +template +_INLINE_VAR constexpr bool _Can_memop = false; + +template +_INLINE_VAR constexpr bool _Can_memop<_Source*, _Dest*, _Cat> = + conjunction_v>, + bool_constant<_Can_memop_elements, remove_volatile_t<_Dest>, _Cat>>>; + +template +_INLINE_VAR constexpr bool _Can_memop, _IterDest, _Cat> = + _Can_memop<_IterSource, _IterDest, _Cat>; + +template +_INLINE_VAR constexpr bool _Memmove_in_copy_is_safe = + _Can_memop, _IterDest, _Memop_cat::_Copy>; + +template +_INLINE_VAR constexpr bool _Memmove_in_uninitialized_copy_is_safe = + _Can_memop, _IterDest, _Memop_cat::_Copy_uninitialized>; + +template +_INLINE_VAR constexpr bool _Memmove_in_move_is_safe = + _Can_memop, _IterDest, _Memop_cat::_Move>; + +template +_INLINE_VAR constexpr bool _Memmove_in_uninitialized_move_is_safe = + _Can_memop, _IterDest, _Memop_cat::_Move_uninitialized>; template -_OutIt _Copy_memmove(_InIt _First, _InIt _Last, _OutIt _Dest) { +_OutIt _Memmove_forward(_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)); @@ -4382,18 +4427,18 @@ _OutIt _Copy_memmove(_InIt _First, _InIt _Last, _OutIt _Dest) { } template -_OutIt _Copy_memmove(move_iterator<_InIt> _First, move_iterator<_InIt> _Last, _OutIt _Dest) { - return _Copy_memmove(_First.base(), _Last.base(), _Dest); +_OutIt _Memmove_forward(move_iterator<_InIt> _First, move_iterator<_InIt> _Last, _OutIt _Dest) { + return _Memmove_forward(_First.base(), _Last.base(), _Dest); } template -_OutIt _Copy_memcpy_common(_InIt _IFirst, _InIt _ILast, _OutIt _OFirst, _OutIt _OLast) noexcept { +_OutIt _Memmove_forward_common(_InIt _IFirst, _InIt _ILast, _OutIt _OFirst, _OutIt _OLast) noexcept { const auto _IFirst_ch = const_cast(reinterpret_cast(_IFirst)); const auto _ILast_ch = const_cast(reinterpret_cast(_ILast)); const auto _OFirst_ch = const_cast(reinterpret_cast(_OFirst)); const auto _OLast_ch = const_cast(reinterpret_cast(_OLast)); const auto _Count = static_cast((_STD min)(_ILast_ch - _IFirst_ch, _OLast_ch - _OFirst_ch)); - _CSTD memcpy(_OFirst_ch, _IFirst_ch, _Count); + _CSTD memmove(_OFirst_ch, _IFirst_ch, _Count); return reinterpret_cast<_OutIt>(_OFirst_ch + _Count); } @@ -4406,12 +4451,12 @@ template _CONSTEXPR20 _OutIt _Copy_unchecked(_InIt _First, _InIt _Last, _OutIt _Dest) { // copy [_First, _Last) to [_Dest, ...) // note: _Copy_unchecked has callers other than the copy family - if constexpr (_Ptr_copy_cat<_InIt, _OutIt>::_Trivially_copyable) { + if constexpr (_Memmove_in_copy_is_safe<_InIt, _OutIt>) { #ifdef __cpp_lib_is_constant_evaluated if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated { - return _Copy_memmove(_First, _Last, _Dest); + return _Memmove_forward(_First, _Last, _Dest); } } @@ -4435,14 +4480,14 @@ _OutIt _Copy_unchecked1(_InIt _First, _InIt _Last, _OutIt _Dest, false_type) { template _OutIt _Copy_unchecked1(_InIt _First, _InIt _Last, _OutIt _Dest, true_type) { // copy [_First, _Last) to [_Dest, ...), pointers to trivially copyable - return _Copy_memmove(_First, _Last, _Dest); + return _Memmove_forward(_First, _Last, _Dest); } template _OutIt _Copy_unchecked(_InIt _First, _InIt _Last, _OutIt _Dest) { // copy [_First, _Last) to [_Dest, ...) // 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>{}); + return _Copy_unchecked1(_First, _Last, _Dest, bool_constant<_Memmove_in_copy_is_safe<_InIt, _OutIt>>{}); } #endif // _HAS_IF_CONSTEXPR @@ -4476,12 +4521,12 @@ _CONSTEXPR20 _OutIt copy_n(_InIt _First, _Diff _Count_raw, _OutIt _Dest) { if (0 < _Count) { auto _UFirst = _Get_unwrapped_n(_First, _Count); auto _UDest = _Get_unwrapped_n(_Dest, _Count); - if constexpr (_Ptr_copy_cat::_Trivially_copyable) { + if constexpr (_Memmove_in_copy_is_safe) { #ifdef __cpp_lib_is_constant_evaluated if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated { - _UDest = _Copy_memmove(_UFirst, _UFirst + _Count, _UDest); + _UDest = _Memmove_forward(_UFirst, _UFirst + _Count, _UDest); _Seek_wrapped(_Dest, _UDest); return _Dest; } @@ -4527,7 +4572,7 @@ template _OutIt _Copy_n_unchecked4(_InIt _First, _Diff _Count, _OutIt _Dest, true_type) { // copy [_First, _First + _Count) to [_Dest, ...), memmove optimization // pre: 0 < _Count - return _Copy_memmove(_First, _First + _Count, _Dest); + return _Memmove_forward(_First, _First + _Count, _Dest); } template @@ -4536,9 +4581,8 @@ _OutIt copy_n(_InIt _First, _Diff _Count_raw, _OutIt _Dest) { // copy [_First, _ if (0 < _Count) { auto _UFirst = _Get_unwrapped_n(_First, _Count); auto _UDest = _Get_unwrapped_n(_Dest, _Count); - _Seek_wrapped( - _Dest, _Copy_n_unchecked4(_UFirst, _Count, _UDest, - bool_constant<_Ptr_copy_cat::_Trivially_copyable>{})); + _Seek_wrapped(_Dest, _Copy_n_unchecked4(_UFirst, _Count, _UDest, + bool_constant<_Memmove_in_copy_is_safe>{})); } return _Dest; @@ -4558,7 +4602,7 @@ _FwdIt2 copy_n(_ExPo&&, _FwdIt1 _First, _Diff _Count_raw, _FwdIt2 _Dest) noexcep // FUNCTION TEMPLATE copy_backward template -_BidIt2 _Copy_backward_memmove(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest) { +_BidIt2 _Memmove_backward(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest) { // implement copy_backward-like function as memmove const char* const _First_ch = const_cast(reinterpret_cast(_First)); const char* const _Last_ch = const_cast(reinterpret_cast(_Last)); @@ -4568,20 +4612,20 @@ _BidIt2 _Copy_backward_memmove(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest) { } template -_BidIt2 _Copy_backward_memmove(move_iterator<_BidIt1> _First, move_iterator<_BidIt1> _Last, _BidIt2 _Dest) { - return _Copy_backward_memmove(_First.base(), _Last.base(), _Dest); +_BidIt2 _Memmove_backward(move_iterator<_BidIt1> _First, move_iterator<_BidIt1> _Last, _BidIt2 _Dest) { + return _Memmove_backward(_First.base(), _Last.base(), _Dest); } #if _HAS_IF_CONSTEXPR template _NODISCARD _CONSTEXPR20 _BidIt2 _Copy_backward_unchecked(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest) { // copy [_First, _Last) backwards to [..., _Dest) - if constexpr (_Ptr_copy_cat<_BidIt1, _BidIt2>::_Trivially_copyable) { + if constexpr (_Memmove_in_copy_is_safe<_BidIt1, _BidIt2>) { #ifdef __cpp_lib_is_constant_evaluated if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated { - return _Copy_backward_memmove(_First, _Last, _Dest); + return _Memmove_backward(_First, _Last, _Dest); } } @@ -4616,7 +4660,7 @@ _BidIt2 _Copy_backward_unchecked(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest, f template _BidIt2 _Copy_backward_unchecked(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest, true_type) { // copy [_First, _Last) backwards to [..., _Dest), memmove optimization - return _Copy_backward_memmove(_First, _Last, _Dest); + return _Memmove_backward(_First, _Last, _Dest); } template @@ -4626,7 +4670,7 @@ _BidIt2 copy_backward(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest) { // copy [_ const auto _ULast = _Get_unwrapped(_Last); auto _UDest = _Get_unwrapped_n(_Dest, -_Idl_distance<_BidIt1>(_UFirst, _ULast)); _Seek_wrapped(_Dest, _Copy_backward_unchecked(_UFirst, _ULast, _UDest, - bool_constant<_Ptr_copy_cat::_Trivially_copyable>{})); + bool_constant<_Memmove_in_copy_is_safe>{})); return _Dest; } #endif // _HAS_IF_CONSTEXPR @@ -4646,12 +4690,12 @@ template _CONSTEXPR20 _OutIt _Move_unchecked(_InIt _First, _InIt _Last, _OutIt _Dest) { // move [_First, _Last) to [_Dest, ...) // note: _Move_unchecked has callers other than the move family - if constexpr (_Ptr_move_cat<_InIt, _OutIt>::_Trivially_copyable) { + if constexpr (_Memmove_in_move_is_safe<_InIt, _OutIt>) { #ifdef __cpp_lib_is_constant_evaluated if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated { - return _Copy_memmove(_First, _Last, _Dest); + return _Memmove_forward(_First, _Last, _Dest); } } @@ -4675,14 +4719,14 @@ _OutIt _Move_unchecked1(_InIt _First, _InIt _Last, _OutIt _Dest, false_type) { template _OutIt _Move_unchecked1(_InIt _First, _InIt _Last, _OutIt _Dest, true_type) { // move [_First, _Last) to [_Dest, ...), memmove optimization - return _Copy_memmove(_First, _Last, _Dest); + return _Memmove_forward(_First, _Last, _Dest); } template _OutIt _Move_unchecked(_InIt _First, _InIt _Last, _OutIt _Dest) { // move [_First, _Last) to [_Dest, ...), choose optimization // 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>{}); + return _Move_unchecked1(_First, _Last, _Dest, bool_constant<_Memmove_in_move_is_safe<_InIt, _OutIt>>{}); } #endif // _HAS_IF_CONSTEXPR @@ -4714,12 +4758,12 @@ template _CONSTEXPR20 _BidIt2 _Move_backward_unchecked(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest) { // move [_First, _Last) backwards to [..., _Dest) // note: _Move_backward_unchecked has callers other than the move_backward family - if constexpr (_Ptr_move_cat<_BidIt1, _BidIt2>::_Trivially_copyable) { + if constexpr (_Memmove_in_move_is_safe<_BidIt1, _BidIt2>) { #ifdef __cpp_lib_is_constant_evaluated if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated { - return _Copy_backward_memmove(_First, _Last, _Dest); + return _Memmove_backward(_First, _Last, _Dest); } } @@ -4743,15 +4787,14 @@ _BidIt2 _Move_backward_unchecked1(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest, template _BidIt2 _Move_backward_unchecked1(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest, true_type) { // move [_First, _Last) backwards to [..., _Dest), memmove optimization - return _Copy_backward_memmove(_First, _Last, _Dest); + return _Memmove_backward(_First, _Last, _Dest); } template _BidIt2 _Move_backward_unchecked(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest) { // move [_First, _Last) backwards to [..., _Dest), choose optimization // 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>{}); + return _Move_backward_unchecked1(_First, _Last, _Dest, bool_constant<_Memmove_in_move_is_safe<_BidIt1, _BidIt2>>{}); } #endif // _HAS_IF_CONSTEXPR @@ -4804,14 +4847,14 @@ struct _Is_character_or_byte_or_bool : true_type {}; template <> struct _Is_character_or_byte_or_bool : true_type {}; -// _Fill_memset_is_safe determines if _FwdIt and _Ty are eligible for memset optimization in fill +// _Memset_in_fill_is_safe determines if _FwdIt and _Ty are eligible for memset optimization in fill template > -_INLINE_VAR constexpr bool _Fill_memset_is_safe = conjunction_v, +_INLINE_VAR constexpr bool _Memset_in_fill_is_safe = conjunction_v, _Is_character_or_byte_or_bool<_Unwrap_enum_t>>>, is_assignable<_Iter_ref_t<_FwdIt>, const _Ty&>>; template -_INLINE_VAR constexpr bool _Fill_memset_is_safe<_FwdIt, _Ty, false> = false; +_INLINE_VAR constexpr bool _Memset_in_fill_is_safe<_FwdIt, _Ty, false> = false; template void _Fill_memset(_DestTy* const _Dest, const _Ty _Val, const size_t _Count) { @@ -4829,7 +4872,7 @@ _CONSTEXPR20 void fill(const _FwdIt _First, const _FwdIt _Last, const _Ty& _Val) } else { auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); - if constexpr (_Fill_memset_is_safe) { + if constexpr (_Memset_in_fill_is_safe) { #ifdef __cpp_lib_is_constant_evaluated if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated @@ -4863,7 +4906,7 @@ template void fill(_FwdIt _First, _FwdIt _Last, const _Ty& _Val) { // copy _Val through [_First, _Last) _Adl_verify_range(_First, _Last); _Fill_unchecked1(_Get_unwrapped(_First), _Get_unwrapped(_Last), _Val, - bool_constant<_Fill_memset_is_safe<_Unwrapped_t, _Ty>>{}); + bool_constant<_Memset_in_fill_is_safe<_Unwrapped_t, _Ty>>{}); } #endif // _HAS_IF_CONSTEXPR @@ -4890,7 +4933,7 @@ _CONSTEXPR20 _OutIt fill_n(_OutIt _Dest, const _Diff _Count_raw, const _Ty& _Val return _Last; } else { auto _UDest = _Get_unwrapped_n(_Dest, _Count); - if constexpr (_Fill_memset_is_safe) { + if constexpr (_Memset_in_fill_is_safe) { #ifdef __cpp_lib_is_constant_evaluated if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated @@ -4937,7 +4980,7 @@ _OutIt fill_n(_OutIt _Dest, const _Diff _Count_raw, const _Ty& _Val) { if (0 < _Count) { auto _UDest = _Get_unwrapped_n(_Dest, _Count); _Seek_wrapped(_Dest, - _Fill_n_unchecked2(_UDest, _Count, _Val, bool_constant<_Fill_memset_is_safe>{})); + _Fill_n_unchecked2(_UDest, _Count, _Val, bool_constant<_Memset_in_fill_is_safe>{})); } return _Dest; @@ -5020,21 +5063,7 @@ template _INLINE_VAR constexpr bool _Can_memcmp_elements_with_pred = _Can_memcmp_elements<_Elem1, _Elem2> // && _Pred_is_consistent_with_memcmp<_Elem1, _Elem2, _Pr>; -// _Iterators_are_contiguous<_Iter1, _Iter2> reports whether both iterators are known to be contiguous. -// (Without concepts, this detection is limited, which will limit when we can activate the memcmp optimization.) - -#ifdef __cpp_lib_concepts -// When concepts are available, we can detect arbitrary contiguous iterators. -template -_INLINE_VAR constexpr bool _Iterators_are_contiguous = contiguous_iterator<_Iter1> // - && contiguous_iterator<_Iter2>; -#else // ^^^ defined(__cpp_lib_concepts) ^^^ / vvv !defined(__cpp_lib_concepts) vvv -// When concepts aren't available, we can detect pointers. (Iterators should be unwrapped before using this.) -template -_INLINE_VAR constexpr bool _Iterators_are_contiguous = conjunction_v, is_pointer<_Iter2>>; -#endif // ^^^ !defined(__cpp_lib_concepts) ^^^ - -// _Equal_memcmp_is_safe<_Iter1, _Iter2, _Pr> reports whether we can activate the memcmp optimization +// _Memcmp_in_equal_is_safe<_Iter1, _Iter2, _Pr> reports whether we can activate the memcmp optimization // for arbitrary iterators and predicates. // It ignores top-level constness on the iterators and on the elements. template @@ -5043,7 +5072,7 @@ _INLINE_VAR constexpr bool _Equal_memcmp_is_safe_helper = _Iterators_are_contigu remove_const_t>>, _Pr>; template -_INLINE_VAR constexpr bool _Equal_memcmp_is_safe = +_INLINE_VAR constexpr bool _Memcmp_in_equal_is_safe = _Equal_memcmp_is_safe_helper, remove_const_t<_Iter2>, _Pr>; #if _HAS_IF_CONSTEXPR @@ -5054,7 +5083,7 @@ _NODISCARD _CONSTEXPR20 bool equal(const _InIt1 _First1, const _InIt1 _Last1, co auto _UFirst1 = _Get_unwrapped(_First1); const auto _ULast1 = _Get_unwrapped(_Last1); auto _UFirst2 = _Get_unwrapped_n(_First2, _Idl_distance<_InIt1>(_UFirst1, _ULast1)); - if constexpr (_Equal_memcmp_is_safe) { + if constexpr (_Memcmp_in_equal_is_safe) { #ifdef __cpp_lib_is_constant_evaluated if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated @@ -5075,7 +5104,7 @@ _NODISCARD _CONSTEXPR20 bool equal(const _InIt1 _First1, const _InIt1 _Last1, co return true; } #else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv -template , int> = 0> +template , int> = 0> bool _Equal_unchecked(_InIt1 _First1, const _InIt1 _Last1, _InIt2 _First2, _Pr _Pred) { // compare [_First1, _Last1) to [_First2, ...), no special optimization for (; _First1 != _Last1; ++_First1, (void) ++_First2) { @@ -5087,7 +5116,7 @@ bool _Equal_unchecked(_InIt1 _First1, const _InIt1 _Last1, _InIt2 _First2, _Pr _ return true; } -template , int> = 0> +template , int> = 0> bool _Equal_unchecked(const _InIt1 _First1, const _InIt1 _Last1, const _InIt2 _First2, _Pr) { // compare [_First1, _Last1) to [_First2, ...), memcmp optimization const auto _First1_ch = reinterpret_cast(_First1); diff --git a/tests/std/test.lst b/tests/std/test.lst index 72a031644d..f2eb774af1 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -247,6 +247,7 @@ tests\P0718R2_atomic_smart_ptrs tests\P0758R1_is_nothrow_convertible tests\P0768R1_spaceship_operator tests\P0769R2_shift_left_shift_right +tests\P0784R7_library_machinery tests\P0784R7_library_support_for_more_constexpr_containers tests\P0811R3_midpoint_lerp tests\P0896R4_common_iterator diff --git a/tests/std/tests/P0784R7_library_machinery/env.lst b/tests/std/tests/P0784R7_library_machinery/env.lst new file mode 100644 index 0000000000..642f530ffa --- /dev/null +++ b/tests/std/tests/P0784R7_library_machinery/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P0784R7_library_machinery/test.cpp b/tests/std/tests/P0784R7_library_machinery/test.cpp new file mode 100644 index 0000000000..583cfd1bf9 --- /dev/null +++ b/tests/std/tests/P0784R7_library_machinery/test.cpp @@ -0,0 +1,147 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include + +#pragma warning(disable : 4582) // '%s': constructor is not implicitly called +#pragma warning(disable : 4583) // '%s': destructor is not implicitly called + +using namespace std; + +struct int_wrapper_copy { + constexpr int_wrapper_copy() = default; + constexpr int_wrapper_copy(const int v) : _val(v){}; + + constexpr int_wrapper_copy(const int_wrapper_copy& other) : _val(other._val) {} + constexpr int_wrapper_copy& operator=(const int_wrapper_copy& other) { + _val = other._val; + return *this; + } + + constexpr int_wrapper_copy(int_wrapper_copy&&) = delete; + constexpr int_wrapper_copy& operator=(int_wrapper_copy&&) = delete; + + constexpr bool operator==(const int_wrapper_copy&) const = default; + + int _val = 0; +}; + +struct int_wrapper_move { + constexpr int_wrapper_move() = default; + constexpr int_wrapper_move(const int v) : _val(v){}; + + constexpr int_wrapper_move(const int_wrapper_move&) = delete; + constexpr int_wrapper_move& operator=(const int_wrapper_move&) = delete; + + constexpr int_wrapper_move(int_wrapper_move&& other) : _val(exchange(other._val, -1)) {} + constexpr int_wrapper_move& operator=(int_wrapper_move&& other) { + _val = exchange(other._val, -1); + return *this; + } + + constexpr bool operator==(const int_wrapper_move&) const = default; + + int _val = 0; +}; + +static constexpr int_wrapper_copy expected_copy[] = {1, 2, 3, 4}; +static constexpr int_wrapper_move expected_move[] = {1, 2, 3, 4}; +static constexpr int_wrapper_move expected_after_move[] = {-1, -1, -1, -1}; + +constexpr bool test() { + { // _Copy_unchecked + int_wrapper_copy input[] = {1, 2, 3, 4}; + int_wrapper_copy output[4] = {5, 6, 7, 8}; + + const auto result = _Copy_unchecked(begin(input), end(input), begin(output)); + static_assert(is_same_v, int_wrapper_copy*>); + assert(result == end(output)); + assert(equal(begin(expected_copy), end(expected_copy), begin(output), end(output))); + } + + { // _Copy_backward_unchecked + int_wrapper_copy input[] = {1, 2, 3, 4}; + int_wrapper_copy output[4] = {5, 6, 7, 8}; + + const auto result = _Copy_backward_unchecked(begin(input), end(input), end(output)); + static_assert(is_same_v, int_wrapper_copy*>); + assert(result == begin(output)); + assert(equal(begin(expected_copy), end(expected_copy), begin(output), end(output))); + } + +#if _HAS_CXX20 && defined(__cpp_constexpr_dynamic_alloc) + { // _Uninitialized_copy_unchecked + int_wrapper_copy input[] = {1, 2, 3, 4}; + int_wrapper_copy output[4]; + + const auto result = _Uninitialized_copy_unchecked(begin(input), end(input), begin(output)); + static_assert(is_same_v, int_wrapper_copy*>); + assert(result == end(output)); + assert(equal(begin(expected_copy), end(expected_copy), begin(output), end(output))); + } +#endif // _HAS_CXX20 && defined(__cpp_constexpr_dynamic_alloc) + + { // _Move_unchecked + int_wrapper_move input[] = {1, 2, 3, 4}; + int_wrapper_move output[4] = {5, 6, 7, 8}; + + const auto result = _Move_unchecked(begin(input), end(input), begin(output)); + static_assert(is_same_v, int_wrapper_move*>); + assert(result == end(output)); + assert(equal(begin(expected_move), end(expected_move), begin(output), end(output))); + if (is_constant_evaluated()) { + assert(equal(begin(input), end(input), begin(expected_after_move), end(expected_after_move))); + } + } + + { // _Move_backward_unchecked + int_wrapper_move input[] = {1, 2, 3, 4}; + int_wrapper_move output[4] = {5, 6, 7, 8}; + + const auto result = _Move_backward_unchecked(begin(input), end(input), end(output)); + static_assert(is_same_v, int_wrapper_move*>); + assert(result == begin(output)); + assert(equal(begin(expected_move), end(expected_move), begin(output), end(output))); + if (is_constant_evaluated()) { + assert(equal(begin(input), end(input), begin(expected_after_move), end(expected_after_move))); + } + } + +#ifdef __cpp_lib_concepts + { // _Move_backward_common + int_wrapper_move input[] = {1, 2, 3, 4}; + int_wrapper_move output[4] = {5, 6, 7, 8}; + + const auto result = ranges::_Move_backward_common(begin(input), end(input), end(output)); + static_assert(is_same_v, int_wrapper_move*>); + assert(result == begin(output)); + assert(equal(begin(expected_move), end(expected_move), begin(output), end(output))); + if (is_constant_evaluated()) { + assert(equal(begin(input), end(input), begin(expected_after_move), end(expected_after_move))); + } + } +#endif // __cpp_lib_concepts + +#if _HAS_CXX20 && defined(__cpp_constexpr_dynamic_alloc) + { // _Uninitialized_move_unchecked + int_wrapper_move input[] = {1, 2, 3, 4}; + int_wrapper_move output[4]; + + const auto result = _Uninitialized_move_unchecked(begin(input), end(input), begin(output)); + static_assert(is_same_v, int_wrapper_move*>); + assert(result == end(output)); + assert(equal(begin(expected_move), end(expected_move), begin(output), end(output))); + if (is_constant_evaluated()) { + assert(equal(begin(input), end(input), begin(expected_after_move), end(expected_after_move))); + } + } +#endif // _HAS_CXX20 && defined(__cpp_constexpr_dynamic_alloc) + return true; +} + +int main() { + test(); + static_assert(test()); +} diff --git a/tests/std/tests/VSO_0180469_ptr_cat/test.cpp b/tests/std/tests/VSO_0180469_ptr_cat/test.cpp index 993ac08eca..e30b3656a9 100644 --- a/tests/std/tests/VSO_0180469_ptr_cat/test.cpp +++ b/tests/std/tests/VSO_0180469_ptr_cat/test.cpp @@ -31,13 +31,13 @@ void assert_same() { template struct test_ptr_cat_helper { - static constexpr bool CopyReallyTrivial = _Ptr_copy_cat::_Really_trivial; - static constexpr bool CopyTriviallyCopyable = _Ptr_copy_cat::_Trivially_copyable; + static constexpr bool CopyReallyTrivial = _Memmove_in_uninitialized_copy_is_safe; + static constexpr bool CopyTriviallyCopyable = _Memmove_in_copy_is_safe; STATIC_ASSERT(Expected == CopyReallyTrivial + CopyTriviallyCopyable); STATIC_ASSERT(!CopyReallyTrivial || CopyTriviallyCopyable); - static constexpr bool MoveReallyTrivial = _Ptr_move_cat::_Really_trivial; - static constexpr bool MoveTriviallyCopyable = _Ptr_move_cat::_Trivially_copyable; + static constexpr bool MoveReallyTrivial = _Memmove_in_uninitialized_move_is_safe; + static constexpr bool MoveTriviallyCopyable = _Memmove_in_move_is_safe; STATIC_ASSERT(Expected == MoveReallyTrivial + MoveTriviallyCopyable); STATIC_ASSERT(!MoveReallyTrivial || MoveTriviallyCopyable); }; @@ -186,6 +186,17 @@ void ptr_cat_test_cases() { test_ptr_cat<2, volatile int*, const volatile int*>(); test_ptr_cat<2, const volatile int*, const volatile int*>(); + // Pointer to pointer should work + test_ptr_cat<2, int**, int**>(); + test_ptr_cat<2, pod_struct**, pod_struct**>(); + test_ptr_cat<2, trivially_copyable_struct**, trivially_copyable_struct**>(); + test_ptr_cat<2, custom_copy_struct**, custom_copy_struct**>(); + + // Pointer to pointer of different types should not work + test_ptr_cat<0, int**, pod_struct**>(); + test_ptr_cat<0, pod_struct**, trivially_copyable_struct**>(); + test_ptr_cat<0, trivially_copyable_struct**, custom_copy_struct**>(); + // Pointers to derived are implicitly convertible to pointers to base, but there // may still be code required to change an offset, so we don't want to memmove them test_ptr_cat<0, derived_class, base_class>(); @@ -223,105 +234,106 @@ void ptr_cat_test_cases() { template void test_case_Equal_memcmp_is_safe_comparator() { // Default case - STATIC_ASSERT(_Equal_memcmp_is_safe == Expected); + STATIC_ASSERT(_Memcmp_in_equal_is_safe == Expected); // Adding const should not change the answer - STATIC_ASSERT(_Equal_memcmp_is_safe == Expected); - STATIC_ASSERT(_Equal_memcmp_is_safe == Expected); - STATIC_ASSERT(_Equal_memcmp_is_safe == Expected); + STATIC_ASSERT(_Memcmp_in_equal_is_safe == Expected); + STATIC_ASSERT(_Memcmp_in_equal_is_safe == Expected); + STATIC_ASSERT(_Memcmp_in_equal_is_safe == Expected); // Top level const should not change the answer - STATIC_ASSERT(_Equal_memcmp_is_safe == Expected); - STATIC_ASSERT(_Equal_memcmp_is_safe == Expected); - STATIC_ASSERT(_Equal_memcmp_is_safe == Expected); - STATIC_ASSERT(_Equal_memcmp_is_safe == Expected); - STATIC_ASSERT(_Equal_memcmp_is_safe == Expected); - STATIC_ASSERT(_Equal_memcmp_is_safe == Expected); - STATIC_ASSERT(_Equal_memcmp_is_safe == Expected); - STATIC_ASSERT(_Equal_memcmp_is_safe == Expected); - STATIC_ASSERT(_Equal_memcmp_is_safe == Expected); - STATIC_ASSERT(_Equal_memcmp_is_safe == Expected); - STATIC_ASSERT(_Equal_memcmp_is_safe == Expected); - STATIC_ASSERT(_Equal_memcmp_is_safe == Expected); + STATIC_ASSERT(_Memcmp_in_equal_is_safe == Expected); + STATIC_ASSERT(_Memcmp_in_equal_is_safe == Expected); + STATIC_ASSERT(_Memcmp_in_equal_is_safe == Expected); + STATIC_ASSERT(_Memcmp_in_equal_is_safe == Expected); + STATIC_ASSERT(_Memcmp_in_equal_is_safe == Expected); + STATIC_ASSERT(_Memcmp_in_equal_is_safe == Expected); + STATIC_ASSERT(_Memcmp_in_equal_is_safe == Expected); + STATIC_ASSERT(_Memcmp_in_equal_is_safe == Expected); + STATIC_ASSERT(_Memcmp_in_equal_is_safe == Expected); + STATIC_ASSERT(_Memcmp_in_equal_is_safe == Expected); + STATIC_ASSERT(_Memcmp_in_equal_is_safe == Expected); + STATIC_ASSERT(_Memcmp_in_equal_is_safe == Expected); // Adding volatile anywhere should explode - STATIC_ASSERT(_Equal_memcmp_is_safe == false); - STATIC_ASSERT(_Equal_memcmp_is_safe == false); - STATIC_ASSERT(_Equal_memcmp_is_safe == false); - STATIC_ASSERT(_Equal_memcmp_is_safe == false); - STATIC_ASSERT(_Equal_memcmp_is_safe == false); - STATIC_ASSERT(_Equal_memcmp_is_safe == false); - STATIC_ASSERT(_Equal_memcmp_is_safe == false); - STATIC_ASSERT(_Equal_memcmp_is_safe == false); - STATIC_ASSERT(_Equal_memcmp_is_safe == false); - STATIC_ASSERT(_Equal_memcmp_is_safe == false); - STATIC_ASSERT(_Equal_memcmp_is_safe == false); - STATIC_ASSERT(_Equal_memcmp_is_safe == false); + STATIC_ASSERT(_Memcmp_in_equal_is_safe == false); + STATIC_ASSERT(_Memcmp_in_equal_is_safe == false); + STATIC_ASSERT(_Memcmp_in_equal_is_safe == false); + STATIC_ASSERT(_Memcmp_in_equal_is_safe == false); + STATIC_ASSERT(_Memcmp_in_equal_is_safe == false); + STATIC_ASSERT(_Memcmp_in_equal_is_safe == false); + STATIC_ASSERT(_Memcmp_in_equal_is_safe == false); + STATIC_ASSERT(_Memcmp_in_equal_is_safe == false); + STATIC_ASSERT(_Memcmp_in_equal_is_safe == false); + STATIC_ASSERT(_Memcmp_in_equal_is_safe == false); + STATIC_ASSERT(_Memcmp_in_equal_is_safe == false); + STATIC_ASSERT(_Memcmp_in_equal_is_safe == false); #ifdef __cpp_lib_concepts // contiguous iterators should not change the answer if constexpr (!is_same_v && !is_same_v) { // vector::iterator is not contiguous - STATIC_ASSERT( - _Equal_memcmp_is_safe::iterator, typename vector::iterator, Pr> == Expected); - STATIC_ASSERT(_Equal_memcmp_is_safe::const_iterator, + STATIC_ASSERT(_Memcmp_in_equal_is_safe::iterator, typename vector::iterator, + Pr> == Expected); + STATIC_ASSERT(_Memcmp_in_equal_is_safe::const_iterator, typename vector::const_iterator, Pr> == Expected); } - STATIC_ASSERT( - _Equal_memcmp_is_safe::iterator, typename array::iterator, Pr> == Expected); - STATIC_ASSERT(_Equal_memcmp_is_safe::const_iterator, + STATIC_ASSERT(_Memcmp_in_equal_is_safe::iterator, typename array::iterator, + Pr> == Expected); + STATIC_ASSERT(_Memcmp_in_equal_is_safe::const_iterator, typename array::const_iterator, Pr> == Expected); // Mixing contiguous iterators should not change the answer if constexpr (!is_same_v && !is_same_v) { - STATIC_ASSERT(_Equal_memcmp_is_safe::iterator, typename vector::const_iterator, + STATIC_ASSERT(_Memcmp_in_equal_is_safe::iterator, typename vector::const_iterator, Pr> == Expected); } if constexpr (!is_same_v) { - STATIC_ASSERT(_Equal_memcmp_is_safe::const_iterator, + STATIC_ASSERT(_Memcmp_in_equal_is_safe::const_iterator, typename vector::const_iterator, Pr> == Expected); } if constexpr (!is_same_v) { - STATIC_ASSERT(_Equal_memcmp_is_safe::iterator, typename array::iterator, - Pr> == Expected); - STATIC_ASSERT(_Equal_memcmp_is_safe::iterator, typename array::const_iterator, + STATIC_ASSERT(_Memcmp_in_equal_is_safe::iterator, typename array::iterator, Pr> == Expected); + STATIC_ASSERT(_Memcmp_in_equal_is_safe::iterator, + typename array::const_iterator, Pr> == Expected); } // span iterators are contiguous STATIC_ASSERT( - _Equal_memcmp_is_safe::iterator, typename span::iterator, Pr> == Expected); + _Memcmp_in_equal_is_safe::iterator, typename span::iterator, Pr> == Expected); STATIC_ASSERT( - _Equal_memcmp_is_safe::iterator, typename span::iterator, Pr> == Expected); + _Memcmp_in_equal_is_safe::iterator, typename span::iterator, Pr> == Expected); STATIC_ASSERT( - _Equal_memcmp_is_safe::iterator, typename span::iterator, Pr> == Expected); - STATIC_ASSERT(_Equal_memcmp_is_safe::iterator, typename span::iterator, + _Memcmp_in_equal_is_safe::iterator, typename span::iterator, Pr> == Expected); + STATIC_ASSERT(_Memcmp_in_equal_is_safe::iterator, typename span::iterator, Pr> == Expected); // contiguous iterators to volatile should explode STATIC_ASSERT( - _Equal_memcmp_is_safe::iterator, typename span::iterator, Pr> == false); + _Memcmp_in_equal_is_safe::iterator, typename span::iterator, Pr> == false); STATIC_ASSERT( - _Equal_memcmp_is_safe::iterator, typename span::iterator, Pr> == false); - STATIC_ASSERT(_Equal_memcmp_is_safe::iterator, + _Memcmp_in_equal_is_safe::iterator, typename span::iterator, Pr> == false); + STATIC_ASSERT(_Memcmp_in_equal_is_safe::iterator, + typename span::iterator, Pr> == false); + STATIC_ASSERT(_Memcmp_in_equal_is_safe::iterator, + typename span::iterator, Pr> == false); + STATIC_ASSERT(_Memcmp_in_equal_is_safe::iterator, typename span::iterator, Pr> == false); - STATIC_ASSERT(_Equal_memcmp_is_safe::iterator, typename span::iterator, - Pr> == false); - STATIC_ASSERT(_Equal_memcmp_is_safe::iterator, typename span::iterator, - Pr> == false); - STATIC_ASSERT(_Equal_memcmp_is_safe::iterator, + STATIC_ASSERT(_Memcmp_in_equal_is_safe::iterator, typename span::iterator, Pr> == false); - STATIC_ASSERT(_Equal_memcmp_is_safe::iterator, typename span::iterator, - Pr> == false); - STATIC_ASSERT(_Equal_memcmp_is_safe::iterator, typename span::iterator, - Pr> == false); - STATIC_ASSERT(_Equal_memcmp_is_safe::iterator, + STATIC_ASSERT(_Memcmp_in_equal_is_safe::iterator, + typename span::iterator, Pr> == false); + STATIC_ASSERT(_Memcmp_in_equal_is_safe::iterator, typename span::iterator, Pr> == false); - STATIC_ASSERT(_Equal_memcmp_is_safe::iterator, + STATIC_ASSERT(_Memcmp_in_equal_is_safe::iterator, + typename span::iterator, Pr> == false); + STATIC_ASSERT(_Memcmp_in_equal_is_safe::iterator, typename span::iterator, Pr> == false); - STATIC_ASSERT(_Equal_memcmp_is_safe::iterator, + STATIC_ASSERT(_Memcmp_in_equal_is_safe::iterator, typename span::iterator, Pr> == false); - STATIC_ASSERT(_Equal_memcmp_is_safe::iterator, + STATIC_ASSERT(_Memcmp_in_equal_is_safe::iterator, typename span::iterator, Pr> == false); #endif // __cpp_lib_concepts // Non-contiguous iterators should explode - STATIC_ASSERT(_Equal_memcmp_is_safe::iterator, typename list::iterator, Pr> == false); + STATIC_ASSERT( + _Memcmp_in_equal_is_safe::iterator, typename list::iterator, Pr> == false); } template @@ -333,15 +345,15 @@ void test_case_Equal_memcmp_is_safe() { #endif // __cpp_lib_concepts // equal_to< some other T > should explode - STATIC_ASSERT(_Equal_memcmp_is_safe>> == false); + STATIC_ASSERT(_Memcmp_in_equal_is_safe>> == false); // Non equal_to comparison functions should explode auto lambda = [](Elem1*, Elem2*) { return false; }; - STATIC_ASSERT(_Equal_memcmp_is_safe == false); + STATIC_ASSERT(_Memcmp_in_equal_is_safe == false); // equal_to should not explode - STATIC_ASSERT(_Equal_memcmp_is_safe> == (Expected && is_same_v) ); + STATIC_ASSERT(_Memcmp_in_equal_is_safe> == (Expected && is_same_v) ); // But again, not volatile - STATIC_ASSERT(_Equal_memcmp_is_safe> == false); - STATIC_ASSERT(_Equal_memcmp_is_safe> == false); + STATIC_ASSERT(_Memcmp_in_equal_is_safe> == false); + STATIC_ASSERT(_Memcmp_in_equal_is_safe> == false); } void equal_safe_test_cases() {