diff --git a/stl/inc/algorithm b/stl/inc/algorithm index cb6147d51fa..9c40002b037 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -695,8 +695,8 @@ namespace ranges { template _NODISCARD static constexpr bool _Equal_count( _It1 _First1, _It2 _First2, _Size _Count, _Pr _Pred, _Pj1 _Proj1, _Pj2 _Proj2) { - if constexpr (_Equal_memcmp_is_safe<_It1, _It2, - _Pr> && same_as<_Pj1, identity> && same_as<_Pj2, identity>) { + if constexpr (_Memcmp_in_equal_is_safe<_It1, _It2, _Pr> // + && same_as<_Pj1, identity> && same_as<_Pj2, identity>) { if (!_STD is_constant_evaluated()) { return _Memcmp_count(_First1, _First2, static_cast(_Count)) == 0; } @@ -1313,10 +1313,10 @@ namespace ranges { requires indirectly_copyable<_It, _Out> constexpr copy_n_result<_It, _Out> operator()(_It _First, iter_difference_t<_It> _Count, _Out _Result) const { auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); - if constexpr (_Ptr_copy_cat::_Trivially_copyable) { + if constexpr (_Memmove_in_copy_is_safe) { if (!_STD is_constant_evaluated()) { auto _Final = _UFirst + _Count; - _Result = _Copy_memmove(_STD move(_UFirst), _Final, _STD move(_Result)); + _Result = _Memmove_forward(_STD move(_UFirst), _Final, _STD move(_Result)); _Seek_wrapped(_First, _STD move(_Final)); return {_STD move(_First), _STD move(_Result)}; } @@ -1460,10 +1460,10 @@ namespace ranges { requires indirectly_movable<_It, _Out> constexpr move_result<_It, _Out> _Move_unchecked(_It _First, _Se _Last, _Out _Result) { // clang-format on - if constexpr (_Ptr_move_cat<_It, _Out>::_Trivially_copyable) { + if constexpr (_Memmove_in_move_is_safe<_It, _Out>) { if (!_STD is_constant_evaluated()) { auto _Final = _RANGES next(_First, _STD move(_Last)); - _Result = _Copy_memmove(_STD move(_First), _Final, _STD move(_Result)); + _Result = _Memmove_forward(_STD move(_First), _Final, _STD move(_Result)); return {_STD move(_Final), _STD move(_Result)}; } } @@ -1516,9 +1516,9 @@ namespace ranges { template requires indirectly_movable<_It1, _It2> 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); } } @@ -1874,7 +1874,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>) { #if _HAS_CXX20 if (!_STD is_constant_evaluated()) #endif // _HAS_CXX20 @@ -1969,7 +1969,7 @@ namespace ranges { // clang-format off template concept _Equal_rev_pred_can_memcmp = is_same_v<_Pj1, identity> && is_same_v<_Pj2, identity> - && sized_sentinel_for<_Se2, _It2> && _Equal_memcmp_is_safe<_It1, _It2, _Pr>; + && sized_sentinel_for<_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> @@ -3355,12 +3355,12 @@ namespace ranges { const auto _ULast = _Get_unwrapped(_STD move(_Last)); if (!_STD is_constant_evaluated()) { if constexpr (sized_sentinel_for) { - if constexpr (_Fill_memset_is_safe) { + if constexpr (_Memset_in_fill_is_safe) { const auto _Distance = static_cast(_ULast - _UFirst); _Fill_memset(_UFirst, _Value, _Distance); _Seek_wrapped(_First, _UFirst + _Distance); return _First; - } else if constexpr (_Fill_zero_memset_is_safe) { + } else if constexpr (_Memset_in_fill_zero_is_safe) { if (_Is_all_bits_zero(_Value)) { const auto _Distance = static_cast(_ULast - _UFirst); _Fill_zero_memset(_UFirst, _Distance); diff --git a/stl/inc/memory b/stl/inc/memory index 88726d5ee67..b47c6e60cd3 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -78,15 +78,16 @@ namespace ranges { constexpr bool _Is_sized1 = sized_sentinel_for<_Se, _It>; constexpr bool _Is_sized2 = sized_sentinel_for<_OSe, _Out>; - if constexpr (_Ptr_copy_cat<_It, _Out>::_Really_trivial && _Sized_or_unreachable_sentinel_for<_Se, _It> // + if constexpr (_Memmove_in_uninitialized_copy_is_safe<_It, _Out> // + && _Sized_or_unreachable_sentinel_for<_Se, _It> // && _Sized_or_unreachable_sentinel_for<_OSe, _Out>) { if constexpr (_Is_sized1 && _Is_sized2) { - return _Copy_memcpy_common(_IFirst, _RANGES next(_IFirst, _STD move(_ILast)), _OFirst, + return _Memmove_common(_IFirst, _RANGES next(_IFirst, _STD move(_ILast)), _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); } else if constexpr (_Is_sized1) { - return _Copy_memcpy_distance(_IFirst, _OFirst, _IFirst, _RANGES next(_IFirst, _STD move(_ILast))); + return _Memmove_distance(_IFirst, _OFirst, _IFirst, _RANGES next(_IFirst, _STD move(_ILast))); } else if constexpr (_Is_sized2) { - return _Copy_memcpy_distance(_IFirst, _OFirst, _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); + return _Memmove_distance(_IFirst, _OFirst, _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); } else { _STL_ASSERT(false, "Tried to uninitialized_copy two ranges with unreachable sentinels"); } @@ -116,8 +117,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}; @@ -155,14 +156,15 @@ namespace ranges { auto _IFirst = _Get_unwrapped_n(_STD move(_First1), _Count); auto _OFirst = _Get_unwrapped(_STD move(_First2)); auto _OLast = _Get_unwrapped(_STD move(_Last2)); - if constexpr (_Ptr_copy_cat<_It, _Out>::_Really_trivial && _Sized_or_unreachable_sentinel_for<_OSe, _Out>) { + if constexpr (_Memmove_in_uninitialized_copy_is_safe<_It, + _Out> && _Sized_or_unreachable_sentinel_for<_OSe, _Out>) { if constexpr (sized_sentinel_for<_OSe, _Out>) { - auto _UResult = _Copy_memcpy_common( - _IFirst, _IFirst + _Count, _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); + auto _UResult = + _Memmove_common(_IFirst, _IFirst + _Count, _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); _IFirst = _STD move(_UResult.in); _OFirst = _STD move(_UResult.out); } else { - auto _UResult = _Copy_memcpy_count(_IFirst, _OFirst, static_cast(_Count)); + auto _UResult = _Memmove_count(_IFirst, _OFirst, static_cast(_Count)); _IFirst = _STD move(_UResult.in); _OFirst = _STD move(_UResult.out); } @@ -250,8 +252,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}; @@ -293,14 +295,15 @@ 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 && _Sized_or_unreachable_sentinel_for<_OSe, _Out>) { + if constexpr (_Memmove_in_uninitialized_move_is_safe<_It, + _Out> && _Sized_or_unreachable_sentinel_for<_OSe, _Out>) { if constexpr (sized_sentinel_for<_OSe, _Out>) { - auto _UResult = _Copy_memcpy_common( - _IFirst, _IFirst + _Count, _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); + auto _UResult = + _Memmove_common(_IFirst, _IFirst + _Count, _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); _IFirst = _STD move(_UResult.in); _OFirst = _STD move(_UResult.out); } else { - auto _UResult = _Copy_memcpy_count(_IFirst, _OFirst, static_cast(_Count)); + auto _UResult = _Memmove_count(_IFirst, _OFirst, static_cast(_Count)); _IFirst = _STD move(_UResult.in); _OFirst = _STD move(_UResult.out); } @@ -354,12 +357,12 @@ 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)); _Fill_memset(_OFirst, _Val, static_cast(_OFinal - _OFirst)); return _OFinal; } else { - if constexpr (_Fill_zero_memset_is_safe<_It, _Ty>) { + if constexpr (_Memset_in_fill_zero_is_safe<_It, _Ty>) { if (_Is_all_bits_zero(_Val)) { const auto _OFinal = _RANGES next(_OFirst, _STD move(_OLast)); _Fill_zero_memset(_OFirst, static_cast(_OFinal - _OFirst)); @@ -391,11 +394,11 @@ _NoThrowFwdIt uninitialized_fill_n(_NoThrowFwdIt _First, const _Diff _Count_raw, } auto _UFirst = _Get_unwrapped_n(_First, _Count); - if constexpr (_Fill_memset_is_safe) { + if constexpr (_Memset_in_fill_is_safe) { _Fill_memset(_UFirst, _Val, static_cast(_Count)); _UFirst += _Count; } else { - if constexpr (_Fill_zero_memset_is_safe) { + if constexpr (_Memset_in_fill_zero_is_safe) { if (_Is_all_bits_zero(_Val)) { _Fill_zero_memset(_UFirst, static_cast(_Count)); _Seek_wrapped(_First, _UFirst + _Count); @@ -432,11 +435,11 @@ namespace ranges { } auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); - if constexpr (_Fill_memset_is_safe) { + if constexpr (_Memset_in_fill_is_safe<_It, _Ty>) { _Fill_memset(_UFirst, _Val, static_cast(_Count)); _Seek_wrapped(_First, _UFirst + _Count); } else { - if constexpr (_Fill_zero_memset_is_safe) { + if constexpr (_Memset_in_fill_zero_is_safe) { if (_Is_all_bits_zero(_Val)) { _Fill_zero_memset(_UFirst, static_cast(_Count)); _Seek_wrapped(_First, _UFirst + _Count); @@ -2165,7 +2168,7 @@ struct _NODISCARD _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) { @@ -2228,10 +2231,10 @@ 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 { - if constexpr (_Fill_zero_memset_is_safe<_Ty*, _Ty>) { + if constexpr (_Memset_in_fill_zero_is_safe<_Ty*, _Ty>) { if (_Is_all_bits_zero(_Val)) { _Fill_zero_memset(_Out, _Size); return; @@ -2530,7 +2533,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) { @@ -2574,11 +2577,12 @@ 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 { - if constexpr (_Fill_zero_memset_is_safe<_Ty*, - _Ty> && _Uses_default_construct<_Alloc, _Ty*, const _Ty&>::value) { + if constexpr (_Memset_in_fill_zero_is_safe<_Ty*, _Ty> // + && _Uses_default_construct<_Alloc, _Ty*, const _Ty&>::value) { if (_Is_all_bits_zero(_Val)) { _Fill_zero_memset(_Out, _Size); return; diff --git a/stl/inc/vector b/stl/inc/vector index 503a506f83f..21c820172d8 100644 --- a/stl/inc/vector +++ b/stl/inc/vector @@ -1031,7 +1031,7 @@ private: _My_data._Orphan_all(); - if constexpr (conjunction_v::_Trivially_copyable>, + if constexpr (conjunction_v>, _Uses_default_construct<_Alty, _Ty*, decltype(*_First)>, _Uses_default_destroy<_Alty, _Ty*>>) { #if _HAS_CXX20 @@ -1043,7 +1043,7 @@ private: _Clear_and_reserve_geometric(_Newsize); } - _Mylast = _Refancy(_Copy_memmove(_First, _Last, _Unfancy(_Myfirst))); + _Mylast = _Refancy(_Memmove_forward(_First, _Last, _Unfancy(_Myfirst))); return; } } diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 29f2c2afb3a..570ac39f8f0 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1477,12 +1477,12 @@ struct _NODISCARD _Uninitialized_backout { template _CONSTEXPR20 _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) { + if constexpr (_Memmove_in_uninitialized_move_is_safe<_InIt, _NoThrowFwdIt>) { #if _HAS_CXX20 if (!_STD is_constant_evaluated()) #endif // _HAS_CXX20 { - return _Copy_memmove(_First, _Last, _Dest); + return _Memmove_forward(_First, _Last, _Dest); } } _Uninitialized_backout<_NoThrowFwdIt> _Backout{_Dest}; @@ -1520,7 +1520,7 @@ namespace ranges { // clang-format on template - in_out_result<_InIt, _OutIt> _Copy_memcpy_count(_InIt _IFirst, _OutIt _OFirst, const size_t _Count) noexcept { + in_out_result<_InIt, _OutIt> _Memmove_count(_InIt _IFirst, _OutIt _OFirst, const size_t _Count) noexcept { const auto _IFirstPtr = _To_address(_IFirst); const auto _OFirstPtr = _To_address(_OFirst); const auto _IFirst_ch = const_cast(reinterpret_cast(_IFirstPtr)); @@ -1542,9 +1542,9 @@ namespace ranges { } template - in_out_result<_InIt, _OutIt> _Copy_memcpy_distance( + in_out_result<_InIt, _OutIt> _Memmove_distance( _InIt _IFirst, _OutIt _OFirst, const _DistIt _DFirst, const _DistIt _DLast) noexcept { - // equivalent to _Copy_memcpy_count(_IFirst, _OFirst, _DLast - _DFirst) but computes distance more efficiently + // equivalent to _Memmove_count(_IFirst, _OFirst, _DLast - _DFirst) but computes distance more efficiently const auto _IFirstPtr = _To_address(_IFirst); const auto _OFirstPtr = _To_address(_OFirst); const auto _DFirstPtr = _To_address(_DFirst); @@ -1570,8 +1570,7 @@ namespace ranges { } template - in_out_result<_InIt, _OutIt> _Copy_memcpy_common( - _InIt _IFirst, _InIt _ILast, _OutIt _OFirst, _OutIt _OLast) noexcept { + in_out_result<_InIt, _OutIt> _Memmove_common(_InIt _IFirst, _InIt _ILast, _OutIt _OFirst, _OutIt _OLast) noexcept { const auto _IFirstPtr = _To_address(_IFirst); const auto _ILastPtr = _To_address(_ILast); const auto _OFirstPtr = _To_address(_OFirst); @@ -1675,13 +1674,13 @@ _CONSTEXPR20 _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)>>) { #if _HAS_CXX20 if (!_STD is_constant_evaluated()) #endif // _HAS_CXX20 { - _Copy_memmove(_UFirst, _ULast, _Unfancy(_Dest)); + _Memmove_forward(_UFirst, _ULast, _Unfancy(_Dest)); _Dest += _ULast - _UFirst; return _Dest; } @@ -1698,12 +1697,12 @@ _CONSTEXPR20 _Alloc_ptr_t<_Alloc> _Uninitialized_copy( template _CONSTEXPR20 _NoThrowFwdIt _Uninitialized_copy_unchecked(_InIt _First, const _InIt _Last, _NoThrowFwdIt _Dest) { // copy [_First, _Last) to raw [_Dest, ...) - if constexpr (_Ptr_copy_cat<_InIt, _NoThrowFwdIt>::_Really_trivial) { + if constexpr (_Memmove_in_uninitialized_copy_is_safe<_InIt, _NoThrowFwdIt>) { #if _HAS_CXX20 if (!_STD is_constant_evaluated()) #endif // _HAS_CXX20 { - return _Copy_memmove(_First, _Last, _Dest); + return _Memmove_forward(_First, _Last, _Dest); } } @@ -1734,13 +1733,13 @@ _CONSTEXPR20 _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))>>) { #if _HAS_CXX20 if (!_STD is_constant_evaluated()) #endif // _HAS_CXX20 { - _Copy_memmove(_UFirst, _ULast, _Unfancy(_Dest)); + _Memmove_forward(_UFirst, _ULast, _Unfancy(_Dest)); return _Dest + (_ULast - _UFirst); } } @@ -1758,7 +1757,7 @@ _CONSTEXPR20 _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) { #if _HAS_CXX20 if (!_STD is_constant_evaluated()) #endif // _HAS_CXX20 @@ -1766,7 +1765,7 @@ _CONSTEXPR20 _Alloc_ptr_t<_Alloc> _Uninitialized_fill_n( _Fill_memset(_Unfancy(_First), _Val, static_cast(_Count)); return _First + _Count; } - } else if constexpr (_Fill_zero_memset_is_safe<_Ty*, _Ty> && _Uses_default_construct<_Alloc, _Ty*, _Ty>::value) { + } else if constexpr (_Memset_in_fill_zero_is_safe<_Ty*, _Ty> && _Uses_default_construct<_Alloc, _Ty*, _Ty>::value) { #if _HAS_CXX20 if (!_STD is_constant_evaluated()) #endif // _HAS_CXX20 @@ -1792,10 +1791,10 @@ 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 { - if constexpr (_Fill_zero_memset_is_safe<_Unwrapped_t, _Tval>) { + if constexpr (_Memset_in_fill_zero_is_safe<_Unwrapped_t, _Tval>) { if (_Is_all_bits_zero(_Val)) { _Fill_zero_memset(_UFirst, static_cast(_ULast - _UFirst)); return; diff --git a/stl/inc/xutility b/stl/inc/xutility index 6d3906aae83..389d7837e05 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -3912,73 +3912,102 @@ template _INLINE_VAR constexpr bool _Iterators_are_contiguous = _Iterator_is_contiguous<_Iter1>&& _Iterator_is_contiguous<_Iter2>; -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; +enum class _Memop_cat { + _Copy, + _Copy_uninitialized, + _Move, + _Move_uninitialized, }; -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>; -}; +// 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*, 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 +_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*, 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; -}; +// Matching integer type are eligible for memcpy +template , _Unwrap_enum_t<_Dest>>> +_INLINE_VAR constexpr bool _Can_memop_elements = _Result; -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; -}; +// 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>>; -struct _False_copy_cat { - static constexpr bool _Really_trivial = false; - static constexpr bool _Trivially_copyable = false; -}; +// 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>; -// NOTE: pointer is not a contiguous iterator if it points to volatile type -template > -struct _Ptr_move_cat : _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_move_cat<_Source, _Dest, false> - : conditional_t, remove_reference_t<_Iter_ref_t<_Source>>>, - _Ptr_cat_helper<_Iter_value_t<_Source>, _Iter_value_t<_Dest>>, _False_copy_cat> {}; +// 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, _Dest, true> : _Ptr_move_cat<_Source, _Dest> {}; +template +_INLINE_VAR constexpr bool + _Can_memop_elements<_Ty, enable_if_t, _Ty>, _Memop_cat::_Move_uninitialized, false> = + is_trivial_v<_Ty>; -template > -struct _Ptr_copy_cat : _False_copy_cat {}; +// 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_copy_cat<_Source, _Dest, false> - : conditional_t, _Iter_ref_t<_Source>>, - _Ptr_cat_helper<_Iter_value_t<_Source>, _Iter_value_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_copy_cat, _Dest, true> : _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 -_OutCtgIt _Copy_memmove(_CtgIt _First, _CtgIt _Last, _OutCtgIt _Dest) { +_OutCtgIt _Memmove_forward(_CtgIt _First, _CtgIt _Last, _OutCtgIt _Dest) { auto _FirstPtr = _To_address(_First); auto _LastPtr = _To_address(_Last); auto _DestPtr = _To_address(_Dest); @@ -3994,24 +4023,25 @@ _OutCtgIt _Copy_memmove(_CtgIt _First, _CtgIt _Last, _OutCtgIt _Dest) { } } -template -_OutIt _Copy_memmove(move_iterator<_InIt> _First, move_iterator<_InIt> _Last, _OutIt _Dest) { - return _Copy_memmove(_First.base(), _Last.base(), _Dest); +template +_OutCtgIt _Memmove_forward(move_iterator<_CtgIt> _First, move_iterator<_CtgIt> _Last, _OutCtgIt _Dest) { + return _Memmove_forward(_First.base(), _Last.base(), _Dest); } template _INLINE_VAR constexpr bool _Is_vb_iterator = false; +// FUNCTION TEMPLATE copy 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>) { #if _HAS_CXX20 if (!_STD is_constant_evaluated()) #endif // _HAS_CXX20 { - return _Copy_memmove(_First, _Last, _Dest); + return _Memmove_forward(_First, _Last, _Dest); } } @@ -4072,10 +4102,10 @@ namespace ranges { requires indirectly_copyable<_It, _Out> _NODISCARD constexpr copy_result<_It, _Out> _Copy_unchecked(_It _First, _Se _Last, _Out _Result) { // clang-format on - if constexpr (_Ptr_copy_cat<_It, _Out>::_Trivially_copyable && sized_sentinel_for<_Se, _It>) { + if constexpr (_Memmove_in_copy_is_safe<_It, _Out> && sized_sentinel_for<_Se, _It>) { if (!_STD is_constant_evaluated()) { auto _Final = _RANGES next(_First, _STD move(_Last)); - _Result = _Copy_memmove(_STD move(_First), _Final, _STD move(_Result)); + _Result = _Memmove_forward(_STD move(_First), _Final, _STD move(_Result)); return {_STD move(_Final), _STD move(_Result)}; } } @@ -4125,12 +4155,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) { #if _HAS_CXX20 if (!_STD is_constant_evaluated()) #endif // _HAS_CXX20 { - _UDest = _Copy_memmove(_UFirst, _UFirst + _Count, _UDest); + _UDest = _Memmove_forward(_UFirst, _UFirst + _Count, _UDest); _Seek_wrapped(_Dest, _UDest); return _Dest; } @@ -4165,8 +4195,8 @@ _FwdIt2 copy_n(_ExPo&&, _FwdIt1 _First, _Diff _Count_raw, _FwdIt2 _Dest) noexcep } #endif // _HAS_CXX17 -template -_CtgIt2 _Copy_backward_memmove(_CtgIt1 _First, _CtgIt1 _Last, _CtgIt2 _Dest) { +template +_OutCtgIt _Memmove_backward(_CtgIt _First, _CtgIt _Last, _OutCtgIt _Dest) { // implement copy_backward-like function as memmove auto _FirstPtr = _To_address(_First); auto _LastPtr = _To_address(_Last); @@ -4176,27 +4206,27 @@ _CtgIt2 _Copy_backward_memmove(_CtgIt1 _First, _CtgIt1 _Last, _CtgIt2 _Dest) { char* const _Dest_ch = const_cast(reinterpret_cast(_DestPtr)); const auto _Count = static_cast(_Last_ch - _First_ch); auto _Result = _CSTD memmove(_Dest_ch - _Count, _First_ch, _Count); - if constexpr (is_pointer_v<_CtgIt2>) { - return static_cast<_CtgIt2>(_Result); + if constexpr (is_pointer_v<_OutCtgIt>) { + return static_cast<_OutCtgIt>(_Result); } else { return _Dest - (_LastPtr - _FirstPtr); } } -template -_BidIt2 _Copy_backward_memmove(move_iterator<_BidIt1> _First, move_iterator<_BidIt1> _Last, _BidIt2 _Dest) { - return _Copy_backward_memmove(_First.base(), _Last.base(), _Dest); +template +_OutCtgIt _Memmove_backward(move_iterator<_CtgIt> _First, move_iterator<_CtgIt> _Last, _OutCtgIt _Dest) { + return _Memmove_backward(_First.base(), _Last.base(), _Dest); } 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>) { #if _HAS_CXX20 if (!_STD is_constant_evaluated()) #endif // _HAS_CXX20 { - return _Copy_backward_memmove(_First, _Last, _Dest); + return _Memmove_backward(_First, _Last, _Dest); } } @@ -4231,12 +4261,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>) { #if _HAS_CXX20 if (!_STD is_constant_evaluated()) #endif // _HAS_CXX20 { - return _Copy_memmove(_First, _Last, _Dest); + return _Memmove_forward(_First, _Last, _Dest); } } @@ -4273,12 +4303,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>) { #if _HAS_CXX20 if (!_STD is_constant_evaluated()) #endif // _HAS_CXX20 { - return _Copy_backward_memmove(_First, _Last, _Dest); + return _Memmove_backward(_First, _Last, _Dest); } } @@ -4309,7 +4339,6 @@ _BidIt2 move_backward(_ExPo&&, _BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest) noe } #endif // _HAS_CXX17 - template struct _Is_character : false_type {}; // by default, not a character type @@ -4341,23 +4370,23 @@ template <> struct _Is_character_or_byte_or_bool : true_type {}; #endif // __cpp_lib_byte -// _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. // Need to explicitly test for volatile because _Unwrap_enum_t discards qualifiers. 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>>>, negation>>>, 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 > -_INLINE_VAR constexpr bool _Fill_zero_memset_is_safe = +_INLINE_VAR constexpr bool _Memset_in_fill_zero_is_safe = conjunction_v, is_scalar<_Iter_value_t<_FwdIt>>, negation>>, negation>>>, is_assignable<_Iter_ref_t<_FwdIt>, const _Ty&>>; template -_INLINE_VAR constexpr bool _Fill_zero_memset_is_safe<_FwdIt, _Ty, false> = false; +_INLINE_VAR constexpr bool _Memset_in_fill_zero_is_safe<_FwdIt, _Ty, false> = false; template void _Fill_memset(_CtgIt _Dest, const _Ty _Val, const size_t _Count) { @@ -4392,10 +4421,10 @@ _CONSTEXPR20 void fill(const _FwdIt _First, const _FwdIt _Last, const _Ty& _Val) if (!_STD is_constant_evaluated()) #endif // _HAS_CXX20 { - if constexpr (_Fill_memset_is_safe) { + if constexpr (_Memset_in_fill_is_safe) { _Fill_memset(_UFirst, _Val, static_cast(_ULast - _UFirst)); return; - } else if constexpr (_Fill_zero_memset_is_safe) { + } else if constexpr (_Memset_in_fill_zero_is_safe) { if (_Is_all_bits_zero(_Val)) { _Fill_zero_memset(_UFirst, static_cast(_ULast - _UFirst)); return; @@ -4434,11 +4463,11 @@ _CONSTEXPR20 _OutIt fill_n(_OutIt _Dest, const _Diff _Count_raw, const _Ty& _Val if (!_STD is_constant_evaluated()) #endif // _HAS_CXX20 { - if constexpr (_Fill_memset_is_safe) { + if constexpr (_Memset_in_fill_is_safe) { _Fill_memset(_UDest, _Val, static_cast(_Count)); _Seek_wrapped(_Dest, _UDest + _Count); return _Dest; - } else if constexpr (_Fill_zero_memset_is_safe) { + } else if constexpr (_Memset_in_fill_zero_is_safe) { if (_Is_all_bits_zero(_Val)) { _Fill_zero_memset(_UDest, static_cast(_Count)); _Seek_wrapped(_Dest, _UDest + _Count); @@ -4478,11 +4507,11 @@ namespace ranges { if (_Count > 0) { auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); if (!_STD is_constant_evaluated()) { - if constexpr (_Fill_memset_is_safe) { + if constexpr (_Memset_in_fill_is_safe) { _Fill_memset(_UFirst, _Value, static_cast(_Count)); _Seek_wrapped(_First, _UFirst + _Count); // no need to move since _UFirst is a pointer return _First; - } else if constexpr (_Fill_zero_memset_is_safe) { + } else if constexpr (_Memset_in_fill_zero_is_safe) { if (_Is_all_bits_zero(_Value)) { _Fill_zero_memset(_UFirst, static_cast(_Count)); _Seek_wrapped(_First, _UFirst + _Count); // no need to move since _UFirst is a pointer @@ -4571,17 +4600,17 @@ template _INLINE_VAR constexpr bool _Can_memcmp_elements_with_pred = _Can_memcmp_elements<_Elem1, _Elem2> // && _Pred_is_consistent_with_memcmp<_Elem1, _Elem2, _Pr>; -// _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 -_INLINE_VAR constexpr bool _Equal_memcmp_is_safe_helper = _Iterators_are_contiguous<_Iter1, _Iter2> // +_INLINE_VAR constexpr bool _Memcmp_in_equal_is_safe_helper = _Iterators_are_contiguous<_Iter1, _Iter2> // && _Can_memcmp_elements_with_pred>>, remove_const_t>>, _Pr>; template -_INLINE_VAR constexpr bool _Equal_memcmp_is_safe = - _Equal_memcmp_is_safe_helper, remove_const_t<_Iter2>, _Pr>; +_INLINE_VAR constexpr bool _Memcmp_in_equal_is_safe = + _Memcmp_in_equal_is_safe_helper, remove_const_t<_Iter2>, _Pr>; template _NODISCARD int _Memcmp_ranges(_CtgIt1 _First1, _CtgIt1 _Last1, _CtgIt2 _First2) { @@ -4607,7 +4636,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) { #if _HAS_CXX20 if (!_STD is_constant_evaluated()) #endif // _HAS_CXX20 diff --git a/tests/std/tests/VSO_0180469_ptr_cat/test.compile.pass.cpp b/tests/std/tests/VSO_0180469_ptr_cat/test.compile.pass.cpp index 0f8716cf6b7..674d35cf1fa 100644 --- a/tests/std/tests/VSO_0180469_ptr_cat/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0180469_ptr_cat/test.compile.pass.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); }; @@ -176,6 +176,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>(); @@ -211,217 +222,218 @@ void ptr_cat_test_cases() { } template -void test_case_Equal_memcmp_is_safe_comparator() { +void test_case_Memcmp_in_equal_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 -void test_case_Equal_memcmp_is_safe() { - test_case_Equal_memcmp_is_safe_comparator, Elem1, Elem2, equal_to>(); - test_case_Equal_memcmp_is_safe_comparator>(); +void test_case_Memcmp_in_equal_is_safe() { + test_case_Memcmp_in_equal_is_safe_comparator, Elem1, Elem2, equal_to>(); + test_case_Memcmp_in_equal_is_safe_comparator>(); #ifdef __cpp_lib_concepts - test_case_Equal_memcmp_is_safe_comparator(); + test_case_Memcmp_in_equal_is_safe_comparator(); #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() { // memcmp is safe for integral types - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); // unless their sizes differ - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); // signedness must be the same if usual arithmetic conversions are not bits-preserving - test_case_Equal_memcmp_is_safe, char, signed char>(); - test_case_Equal_memcmp_is_safe, signed char, char>(); - test_case_Equal_memcmp_is_safe, char, unsigned char>(); - test_case_Equal_memcmp_is_safe, unsigned char, char>(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); + test_case_Memcmp_in_equal_is_safe, char, signed char>(); + test_case_Memcmp_in_equal_is_safe, signed char, char>(); + test_case_Memcmp_in_equal_is_safe, char, unsigned char>(); + test_case_Memcmp_in_equal_is_safe, unsigned char, char>(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); // but if UACs don't change bits the signedness can differ - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); // memcmp is safe between bool and other integral types with the same size because we don't care about // representations other than 0 and 1 - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); // No enums - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); // No user-defined types - test_case_Equal_memcmp_is_safe(); + test_case_Memcmp_in_equal_is_safe(); #ifdef __cpp_lib_byte // memcmp is safe for std::byte, but it can't be compared to integral types - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); #endif // __cpp_lib_byte // Pointers to cv T are OK (they *point to* volatile stuff, they aren't volatile themselves) typedef void (*funcptr_t)(int); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); // Pointers to not-the-same-type need to go to the general algorithm - test_case_Equal_memcmp_is_safe(); + test_case_Memcmp_in_equal_is_safe(); // Technically pointers to cv-void and any other object pointer should be OK, but the // metaprogramming shouldn't attempt to handle that case because detecting function pointer // types is not worth it - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); + test_case_Memcmp_in_equal_is_safe(); + test_case_Memcmp_in_equal_is_safe(); } template @@ -432,7 +444,7 @@ void test_case_Lex_compare_optimize_helper() { template void test_case_Lex_compare_optimize() { - // same cv-qualifiers song and dance as test_case_Equal_memcmp_is_safe + // same cv-qualifiers song and dance as test_case_Memcmp_in_equal_is_safe test_case_Lex_compare_optimize_helper(); test_case_Lex_compare_optimize_helper(); test_case_Lex_compare_optimize_helper();