From e3fc01ccfcab0f8c4a9efad1cb6be43932a4fde2 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Tue, 23 Mar 2021 15:13:30 +0100 Subject: [PATCH 1/6] Implement more optimizations --- stl/inc/algorithm | 24 +++++++++ stl/inc/memory | 13 +++-- stl/inc/xmemory | 29 +++++++--- stl/inc/xutility | 132 ++++++++++++++++++++++++++-------------------- 4 files changed, 131 insertions(+), 67 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 506234cbf3a..c7035fc45ed 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -1389,6 +1389,14 @@ namespace ranges { template _Se, weakly_incrementable _Out> requires indirectly_copyable<_It, _Out> _NODISCARD constexpr copy_result<_It, _Out> _Copy_unchecked(_It _First, const _Se _Last, _Out _Result) { + if constexpr (_Ptr_copy_cat<_It, _Out>::_Trivially_copyable) { + if (!_STD is_constant_evaluated()) { + auto _LastIt = _RANGES next(_First, _Last); + _Result = _Copy_memmove(_STD move(_First), _LastIt, _STD move(_Result)); + return {_STD move(_LastIt), _STD move(_Result)}; + } + } + for (; _First != _Last; ++_First, (void) ++_Result) { *_Result = *_First; } @@ -1440,6 +1448,15 @@ 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 (!_STD is_constant_evaluated()) { + auto _LastIt = _UFirst + _Count; + _Result = _Copy_memmove(_STD move(_UFirst), _LastIt, _STD move(_Result)); + _Seek_wrapped(_First, _STD move(_LastIt)); + return {_STD move(_First), _STD move(_Result)}; + } + } + for (; _Count > 0; ++_UFirst, (void) ++_Result, --_Count) { *_Result = *_UFirst; } @@ -1585,6 +1602,13 @@ namespace ranges { requires indirectly_movable<_It, _Out> constexpr move_result<_It, _Out> _Move_unchecked(_It _First, const _Se _Last, _Out _Result) { // clang-format on + if constexpr (_Ptr_move_cat<_It, _Out>::_Trivially_copyable) { + if (!_STD is_constant_evaluated()) { + auto _LastIt = _RANGES next(_First, _Last); + _Result = _Copy_memmove(_STD move(_First), _LastIt, _STD move(_Result)); + return {_STD move(_LastIt), _STD move(_Result)}; + } + } for (; _First != _Last; ++_First, (void) ++_Result) { *_Result = _RANGES iter_move(_First); diff --git a/stl/inc/memory b/stl/inc/memory index f35574a2580..aa6671d7149 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -78,8 +78,9 @@ 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> && is_same_v<_OSe, _Out> && _Ptr_copy_cat<_It, _Out>::_Really_trivial) { - return _Copy_memcpy_common(_IFirst, _ILast, _OFirst, _OLast); + if constexpr (_Ptr_copy_cat<_It, _Out>::_Really_trivial && sized_sentinel_for<_Se, _It> + && sized_sentinel_for<_OSe, _Out>) { + return _Copy_memcpy_common(_IFirst, _RANGES next(_IFirst, _ILast), _OFirst, _RANGES next(_OFirst, _OLast)); } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; @@ -508,8 +509,12 @@ namespace ranges { requires destructible> _NODISCARD _CONSTEXPR20_DYNALLOC _It _Destroy_unchecked(_It _First, const _Se _Last) noexcept { // clang-format on - for (; _First != _Last; ++_First) { - _RANGES destroy_at(_STD addressof(*_First)); + if constexpr (is_trivially_destructible_v>) { + _RANGES advance(_First, _Last); + } else { + for (; _First != _Last; ++_First) { + _RANGES destroy_at(_STD addressof(*_First)); + } } return _First; diff --git a/stl/inc/xmemory b/stl/inc/xmemory index a8667203c54..319e3c3ea07 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1557,13 +1557,27 @@ namespace ranges { template in_out_result<_InIt, _OutIt> _Copy_memcpy_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 _IFirstPtr = _To_address(_IFirst); + const auto _ILastPtr = _To_address(_ILast); + const auto _OFirstPtr = _To_address(_OFirst); + const auto _OLastPtr = _To_address(_OLast); + const auto _IFirst_ch = const_cast(reinterpret_cast(_IFirstPtr)); + const auto _ILast_ch = const_cast(reinterpret_cast(_ILastPtr)); + const auto _OFirst_ch = const_cast(reinterpret_cast(_OFirstPtr)); + const auto _OLast_ch = const_cast(reinterpret_cast(_OLastPtr)); const auto _Count = static_cast((_STD min)(_ILast_ch - _IFirst_ch, _OLast_ch - _OFirst_ch)); _CSTD memcpy(_OFirst_ch, _IFirst_ch, _Count); - return {reinterpret_cast<_InIt>(_IFirst_ch + _Count), reinterpret_cast<_OutIt>(_OFirst_ch + _Count)}; + if constexpr (is_pointer_v<_InIt>) { + _IFirst = reinterpret_cast<_InIt>(_IFirst_ch + _Count); + } else { + _IFirst += reinterpret_cast(_IFirst_ch + _Count) - _IFirstPtr; + } + if constexpr (is_pointer_v<_OutIt>) { + _OFirst = reinterpret_cast<_OutIt>(_OFirst_ch + _Count); + } else { + _OFirst += reinterpret_cast(_OFirst_ch + _Count) - _OFirstPtr; + } + return {_IFirst, _OFirst}; } // ALIAS TEMPLATE uninitialized_move_result @@ -1578,8 +1592,9 @@ namespace ranges { uninitialized_move_result<_It, _Out> _Uninitialized_move_unchecked( _It _IFirst, const _Se _ILast, _Out _OFirst, const _OSe _OLast) { // clang-format on - if constexpr (is_same_v<_Se, _It> && is_same_v<_OSe, _Out> && _Ptr_move_cat<_It, _Out>::_Really_trivial) { - return _Copy_memcpy_common(_IFirst, _ILast, _OFirst, _OLast); + if constexpr (_Ptr_move_cat<_It, _Out>::_Really_trivial && sized_sentinel_for<_Se, _It> + && sized_sentinel_for<_OSe, _Out>) { + return _Copy_memcpy_common(_IFirst, _RANGES next(_IFirst, _ILast), _OFirst, _RANGES next(_OFirst, _OLast)); } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; diff --git a/stl/inc/xutility b/stl/inc/xutility index d6381da9c20..718e9a888db 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4041,6 +4041,37 @@ struct unreachable_sentinel_t : _Unreachable_sentinel_detail::_Base {}; // TRANS inline constexpr unreachable_sentinel_t unreachable_sentinel{}; #endif // __cpp_lib_concepts +// _Iterator_is_contiguous<_Iter> reports whether an iterator is known to be contiguous. +// (Without concepts, this detection is limited, which will limit when we can activate optimizations.) + +#ifdef __cpp_lib_concepts +// When concepts are available, we can detect arbitrary contiguous iterators. +template +inline constexpr bool _Iterator_is_contiguous = contiguous_iterator<_Iter>; + +template +_NODISCARD constexpr auto _To_address(const _Iter& _Val) noexcept { + _STL_INTERNAL_STATIC_ASSERT(contiguous_iterator<_Iter>); + return _STD to_address(_Val); +} +#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 _Iterator_is_contiguous = is_pointer_v<_Iter>; + +template +_NODISCARD constexpr auto _To_address(const _Iter& _Val) noexcept { + _STL_INTERNAL_STATIC_ASSERT(is_pointer_v<_Iter>); + return _Val; +} +#endif // ^^^ !defined(__cpp_lib_concepts) ^^^ + +// _Iterators_are_contiguous<_Iter1, _Iter2> reports whether both iterators are known to be contiguous. + +template +_INLINE_VAR constexpr bool _Iterators_are_contiguous = + _Iterator_is_contiguous<_Iter1>&& _Iterator_is_contiguous<_Iter2>; + // FUNCTION TEMPLATE copy template struct _Ptr_cat_helper { @@ -4084,36 +4115,48 @@ struct _False_copy_cat { static constexpr bool _Trivially_copyable = false; }; -template -struct _Ptr_copy_cat : _False_copy_cat {}; // unwrap the pointer-like type and dispatch to _Ptr_cat_helper for copy +// NOTE: pointer is not a contiguous iterator if it points to volatile type +template || is_pointer_v<_Source>) &&( + _Iterator_is_contiguous<_Dest> || is_pointer_v<_Dest>)> +struct _Ptr_move_cat : _False_copy_cat {}; template -struct _Ptr_copy_cat<_Source*, _Dest*> - : conditional_t, - _Ptr_cat_helper, remove_cv_t<_Dest>>, _False_copy_cat> {}; +struct _Ptr_move_cat<_Source, _Dest, true> + : conditional_t, remove_reference_t<_Iter_ref_t<_Source>>>, + _Ptr_cat_helper<_Iter_value_t<_Source>, _Iter_value_t<_Dest>>, _False_copy_cat> {}; template -struct _Ptr_copy_cat, _Dest*> : _Ptr_copy_cat<_Source*, _Dest*> {}; +struct _Ptr_move_cat, _Dest, false> : _Ptr_move_cat<_Source, _Dest> {}; -template -struct _Ptr_move_cat : _False_copy_cat {}; // unwrap the pointer-like type and dispatch to _Ptr_cat_helper for move +template || is_pointer_v<_Source>) &&( + _Iterator_is_contiguous<_Dest> || is_pointer_v<_Dest>)> +struct _Ptr_copy_cat : _False_copy_cat {}; template -struct _Ptr_move_cat<_Source*, _Dest*> - : conditional_t, - _Ptr_cat_helper, remove_cv_t<_Dest>>, _False_copy_cat> {}; +struct _Ptr_copy_cat<_Source, _Dest, true> + : conditional_t, _Iter_ref_t<_Source>>, + _Ptr_cat_helper<_Iter_value_t<_Source>, _Iter_value_t<_Dest>>, _False_copy_cat> {}; template -struct _Ptr_move_cat, _Dest*> : _Ptr_move_cat<_Source*, _Dest*> {}; - -template -_OutIt _Copy_memmove(_InIt _First, _InIt _Last, _OutIt _Dest) { - 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)); +struct _Ptr_copy_cat, _Dest, false> : _Ptr_move_cat<_Source, _Dest> {}; + +template +_OutCtgIt _Copy_memmove(_CtgIt _First, _CtgIt _Last, _OutCtgIt _Dest) { + auto _FirstPtr = _To_address(_First); + auto _LastPtr = _To_address(_Last); + auto _DestPtr = _To_address(_Dest); + const char* const _First_ch = const_cast(reinterpret_cast(_FirstPtr)); + const char* const _Last_ch = const_cast(reinterpret_cast(_LastPtr)); + char* const _Dest_ch = const_cast(reinterpret_cast(_DestPtr)); const auto _Count = static_cast(_Last_ch - _First_ch); _CSTD memmove(_Dest_ch, _First_ch, _Count); - return reinterpret_cast<_OutIt>(_Dest_ch + _Count); + if constexpr (is_pointer_v<_OutCtgIt>) { + return reinterpret_cast<_OutCtgIt>(_Dest_ch + _Count); + } else { + return _Dest + (_LastPtr - _FirstPtr); + } } template @@ -4215,14 +4258,22 @@ _FwdIt2 copy_n(_ExPo&&, _FwdIt1 _First, _Diff _Count_raw, _FwdIt2 _Dest) noexcep #endif // _HAS_CXX17 // FUNCTION TEMPLATE copy_backward -template -_BidIt2 _Copy_backward_memmove(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest) { +template +_CtgIt2 _Copy_backward_memmove(_CtgIt1 _First, _CtgIt1 _Last, _CtgIt2 _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)); - char* const _Dest_ch = const_cast(reinterpret_cast(_Dest)); + auto _FirstPtr = _To_address(_First); + auto _LastPtr = _To_address(_Last); + auto _DestPtr = _To_address(_Dest); + const char* const _First_ch = const_cast(reinterpret_cast(_FirstPtr)); + const char* const _Last_ch = const_cast(reinterpret_cast(_LastPtr)); + char* const _Dest_ch = const_cast(reinterpret_cast(_DestPtr)); const auto _Count = static_cast(_Last_ch - _First_ch); - return static_cast<_BidIt2>(_CSTD memmove(_Dest_ch - _Count, _First_ch, _Count)); + auto _Result = _CSTD memmove(_Dest_ch - _Count, _First_ch, _Count); + if constexpr (is_pointer_v<_CtgIt2>) { + return static_cast<_CtgIt2>(_Result); + } else { + return _Dest - (_LastPtr - _FirstPtr); + } } template @@ -4355,37 +4406,6 @@ _BidIt2 move_backward(_ExPo&&, _BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest) noe // FUNCTION TEMPLATE fill -// _Iterator_is_contiguous<_Iter> reports whether an iterator is known to be contiguous. -// (Without concepts, this detection is limited, which will limit when we can activate optimizations.) - -#ifdef __cpp_lib_concepts -// When concepts are available, we can detect arbitrary contiguous iterators. -template -inline constexpr bool _Iterator_is_contiguous = contiguous_iterator<_Iter>; - -template -_NODISCARD constexpr auto _To_address(const _Iter& _Val) noexcept { - _STL_INTERNAL_STATIC_ASSERT(contiguous_iterator<_Iter>); - return _STD to_address(_Val); -} -#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 _Iterator_is_contiguous = is_pointer_v<_Iter>; - -template -_NODISCARD constexpr auto _To_address(const _Iter& _Val) noexcept { - _STL_INTERNAL_STATIC_ASSERT(is_pointer_v<_Iter>); - return _Val; -} -#endif // ^^^ !defined(__cpp_lib_concepts) ^^^ - -// _Iterators_are_contiguous<_Iter1, _Iter2> reports whether both iterators are known to be contiguous. - -template -_INLINE_VAR constexpr bool _Iterators_are_contiguous = - _Iterator_is_contiguous<_Iter1>&& _Iterator_is_contiguous<_Iter2>; - template struct _Is_character : false_type {}; // by default, not a character type From 8fb4b7a22f61161ffc1339676190b109af24cc63 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Tue, 23 Mar 2021 15:54:21 +0100 Subject: [PATCH 2/6] clang-format --- stl/inc/algorithm | 2 +- stl/inc/memory | 7 ++++--- stl/inc/xmemory | 6 +++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index c7035fc45ed..f462e6eb81b 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -1605,7 +1605,7 @@ namespace ranges { if constexpr (_Ptr_move_cat<_It, _Out>::_Trivially_copyable) { if (!_STD is_constant_evaluated()) { auto _LastIt = _RANGES next(_First, _Last); - _Result = _Copy_memmove(_STD move(_First), _LastIt, _STD move(_Result)); + _Result = _Copy_memmove(_STD move(_First), _LastIt, _STD move(_Result)); return {_STD move(_LastIt), _STD move(_Result)}; } } diff --git a/stl/inc/memory b/stl/inc/memory index aa6671d7149..b8e683f2b28 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -78,9 +78,10 @@ namespace ranges { _STL_INTERNAL_STATIC_ASSERT(_No_throw_sentinel_for<_OSe, _Out>); _STL_INTERNAL_STATIC_ASSERT(constructible_from, iter_reference_t<_It>>); - if constexpr (_Ptr_copy_cat<_It, _Out>::_Really_trivial && sized_sentinel_for<_Se, _It> - && sized_sentinel_for<_OSe, _Out>) { - return _Copy_memcpy_common(_IFirst, _RANGES next(_IFirst, _ILast), _OFirst, _RANGES next(_OFirst, _OLast)); + if constexpr (_Ptr_copy_cat<_It, _Out>::_Really_trivial + && sized_sentinel_for<_Se, _It> && sized_sentinel_for<_OSe, _Out>) { + return _Copy_memcpy_common( + _IFirst, _RANGES next(_IFirst, _ILast), _OFirst, _RANGES next(_OFirst, _OLast)); } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 319e3c3ea07..12474feba00 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1592,9 +1592,9 @@ namespace ranges { uninitialized_move_result<_It, _Out> _Uninitialized_move_unchecked( _It _IFirst, const _Se _ILast, _Out _OFirst, const _OSe _OLast) { // clang-format on - if constexpr (_Ptr_move_cat<_It, _Out>::_Really_trivial && sized_sentinel_for<_Se, _It> - && sized_sentinel_for<_OSe, _Out>) { - return _Copy_memcpy_common(_IFirst, _RANGES next(_IFirst, _ILast), _OFirst, _RANGES next(_OFirst, _OLast)); + if constexpr (_Ptr_move_cat<_It, _Out>::_Really_trivial + && sized_sentinel_for<_Se, _It> && sized_sentinel_for<_OSe, _Out>) { + return _Copy_memcpy_common(_IFirst, _RANGES next(_IFirst, _ILast), _OFirst, _RANGES next(_OFirst, _OLast)); } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; From a579ddadce7993ca2cea010ebc527c2c421ad076 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Tue, 23 Mar 2021 19:48:29 +0100 Subject: [PATCH 3/6] Code review --- stl/inc/algorithm | 22 +++++++++---------- stl/inc/xutility | 8 ++----- .../VSO_0180469_ptr_cat/test.compile.pass.cpp | 16 +++----------- 3 files changed, 16 insertions(+), 30 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index f462e6eb81b..2a294ed1296 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -1388,12 +1388,12 @@ namespace ranges { // clang-format off template _Se, weakly_incrementable _Out> requires indirectly_copyable<_It, _Out> - _NODISCARD constexpr copy_result<_It, _Out> _Copy_unchecked(_It _First, const _Se _Last, _Out _Result) { + _NODISCARD constexpr copy_result<_It, _Out> _Copy_unchecked(_It _First, _Se _Last, _Out _Result) { if constexpr (_Ptr_copy_cat<_It, _Out>::_Trivially_copyable) { if (!_STD is_constant_evaluated()) { - auto _LastIt = _RANGES next(_First, _Last); - _Result = _Copy_memmove(_STD move(_First), _LastIt, _STD move(_Result)); - return {_STD move(_LastIt), _STD move(_Result)}; + auto _Final = _RANGES next(_First, _STD move(_Last)); + _Result = _Copy_memmove(_STD move(_First), _Final, _STD move(_Result)); + return {_STD move(_Final), _STD move(_Result)}; } } @@ -1450,9 +1450,9 @@ namespace ranges { auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); if constexpr (_Ptr_copy_cat::_Trivially_copyable) { if (!_STD is_constant_evaluated()) { - auto _LastIt = _UFirst + _Count; - _Result = _Copy_memmove(_STD move(_UFirst), _LastIt, _STD move(_Result)); - _Seek_wrapped(_First, _STD move(_LastIt)); + auto _Final = _UFirst + _Count; + _Result = _Copy_memmove(_STD move(_UFirst), _Final, _STD move(_Result)); + _Seek_wrapped(_First, _STD move(_Final)); return {_STD move(_First), _STD move(_Result)}; } } @@ -1600,13 +1600,13 @@ namespace ranges { // clang-format off template _Se, weakly_incrementable _Out> requires indirectly_movable<_It, _Out> - constexpr move_result<_It, _Out> _Move_unchecked(_It _First, const _Se _Last, _Out _Result) { + 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 (!_STD is_constant_evaluated()) { - auto _LastIt = _RANGES next(_First, _Last); - _Result = _Copy_memmove(_STD move(_First), _LastIt, _STD move(_Result)); - return {_STD move(_LastIt), _STD move(_Result)}; + auto _Final = _RANGES next(_First, _STD move(_Last)); + _Result = _Copy_memmove(_STD move(_First), _Final, _STD move(_Result)); + return {_STD move(_Final), _STD move(_Result)}; } } diff --git a/stl/inc/xutility b/stl/inc/xutility index 718e9a888db..09e7c24680d 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4116,9 +4116,7 @@ struct _False_copy_cat { }; // NOTE: pointer is not a contiguous iterator if it points to volatile type -template || is_pointer_v<_Source>) &&( - _Iterator_is_contiguous<_Dest> || is_pointer_v<_Dest>)> +template > struct _Ptr_move_cat : _False_copy_cat {}; template @@ -4129,9 +4127,7 @@ struct _Ptr_move_cat<_Source, _Dest, true> template struct _Ptr_move_cat, _Dest, false> : _Ptr_move_cat<_Source, _Dest> {}; -template || is_pointer_v<_Source>) &&( - _Iterator_is_contiguous<_Dest> || is_pointer_v<_Dest>)> +template > struct _Ptr_copy_cat : _False_copy_cat {}; template 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 1862d65e7d8..0f8716cf6b7 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 @@ -42,7 +42,7 @@ struct test_ptr_cat_helper { STATIC_ASSERT(!MoveReallyTrivial || MoveTriviallyCopyable); }; -template +template void test_ptr_cat() { (void) test_ptr_cat_helper{}; // Also make sure that the source being const doesn't change the answer @@ -59,16 +59,6 @@ void test_ptr_cat() { (void) test_ptr_cat_helper<0, const volatile Source*, const Dest*>{}; (void) test_ptr_cat_helper<0, const Source*, const volatile Dest*>{}; (void) test_ptr_cat_helper<0, const volatile Source*, const volatile Dest*>{}; - // volatile anywhere should go to the trivial implementation for builtin types, but - // the general implementation for PODs, since the compiler-generated copy assign has signature: - // Meow& operator=(const Meow&); - // which hates volatile on both the source and the target - (void) test_ptr_cat_helper{}; - (void) test_ptr_cat_helper{}; - (void) test_ptr_cat_helper{}; - (void) test_ptr_cat_helper{}; - (void) test_ptr_cat_helper{}; - (void) test_ptr_cat_helper{}; // Also make sure _Ptr_cat listens to the iterator type (void) test_ptr_cat_helper<0, typename list::iterator, typename list::iterator>{}; @@ -131,8 +121,8 @@ void ptr_cat_test_cases() { // Identity cases: test_ptr_cat<2, int, int>(); test_ptr_cat<2, bool, bool>(); - test_ptr_cat<2, pod_struct, pod_struct, 0>(); - test_ptr_cat<1, trivially_copyable_struct, trivially_copyable_struct, 0>(); + test_ptr_cat<2, pod_struct, pod_struct>(); + test_ptr_cat<1, trivially_copyable_struct, trivially_copyable_struct>(); test_ptr_cat<0, custom_copy_struct, custom_copy_struct>(); test_ptr_cat<2, int_enum, int_enum>(); test_ptr_cat<2, short_enum, short_enum>(); From 3827926f2009503540a0d255946cd2c0c1e1a11f Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Tue, 23 Mar 2021 20:41:24 +0100 Subject: [PATCH 4/6] Code review --- stl/inc/algorithm | 2 +- stl/inc/xutility | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 2a294ed1296..e128b93569c 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -1389,7 +1389,7 @@ namespace ranges { template _Se, weakly_incrementable _Out> requires indirectly_copyable<_It, _Out> _NODISCARD constexpr copy_result<_It, _Out> _Copy_unchecked(_It _First, _Se _Last, _Out _Result) { - if constexpr (_Ptr_copy_cat<_It, _Out>::_Trivially_copyable) { + if constexpr (_Ptr_copy_cat<_It, _Out>::_Trivially_copyable && 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)); diff --git a/stl/inc/xutility b/stl/inc/xutility index 09e7c24680d..e7d38772892 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4116,27 +4116,27 @@ struct _False_copy_cat { }; // NOTE: pointer is not a contiguous iterator if it points to volatile type -template > +template > struct _Ptr_move_cat : _False_copy_cat {}; template -struct _Ptr_move_cat<_Source, _Dest, true> +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> {}; template -struct _Ptr_move_cat, _Dest, false> : _Ptr_move_cat<_Source, _Dest> {}; +struct _Ptr_move_cat, _Dest, true> : _Ptr_move_cat<_Source, _Dest> {}; -template > +template > struct _Ptr_copy_cat : _False_copy_cat {}; template -struct _Ptr_copy_cat<_Source, _Dest, true> +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> {}; template -struct _Ptr_copy_cat, _Dest, false> : _Ptr_move_cat<_Source, _Dest> {}; +struct _Ptr_copy_cat, _Dest, true> : _Ptr_move_cat<_Source, _Dest> {}; template _OutCtgIt _Copy_memmove(_CtgIt _First, _CtgIt _Last, _OutCtgIt _Dest) { From 94213f5f965301f34090309c23e312d3a6c1b853 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Fri, 26 Mar 2021 08:21:42 +0100 Subject: [PATCH 5/6] Code review --- stl/inc/memory | 6 +++--- stl/inc/xmemory | 14 ++++++++------ stl/inc/xutility | 4 ++-- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index b8e683f2b28..3c8394c6ee8 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -71,7 +71,7 @@ namespace ranges { private: template _NODISCARD static uninitialized_copy_result<_It, _Out> _Uninitialized_copy_unchecked( - _It _IFirst, const _Se _ILast, _Out _OFirst, const _OSe _OLast) { + _It _IFirst, _Se _ILast, _Out _OFirst, _OSe _OLast) { _STL_INTERNAL_STATIC_ASSERT(input_iterator<_It>); _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>); _STL_INTERNAL_STATIC_ASSERT(_No_throw_forward_iterator<_Out>); @@ -80,8 +80,8 @@ namespace ranges { if constexpr (_Ptr_copy_cat<_It, _Out>::_Really_trivial && sized_sentinel_for<_Se, _It> && sized_sentinel_for<_OSe, _Out>) { - return _Copy_memcpy_common( - _IFirst, _RANGES next(_IFirst, _ILast), _OFirst, _RANGES next(_OFirst, _OLast)); + return _Copy_memcpy_common(_IFirst, _RANGES next(_IFirst, _STD move(_ILast)), _OFirst, + _RANGES next(_OFirst, _STD move(_OLast))); } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 12474feba00..49828d83b0e 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1563,21 +1563,22 @@ namespace ranges { const auto _OLastPtr = _To_address(_OLast); const auto _IFirst_ch = const_cast(reinterpret_cast(_IFirstPtr)); const auto _ILast_ch = const_cast(reinterpret_cast(_ILastPtr)); - const auto _OFirst_ch = const_cast(reinterpret_cast(_OFirstPtr)); + const auto _OFirst_ch = const_cast(reinterpret_cast(_OFirstPtr)); const auto _OLast_ch = const_cast(reinterpret_cast(_OLastPtr)); const auto _Count = static_cast((_STD min)(_ILast_ch - _IFirst_ch, _OLast_ch - _OFirst_ch)); _CSTD memcpy(_OFirst_ch, _IFirst_ch, _Count); if constexpr (is_pointer_v<_InIt>) { _IFirst = reinterpret_cast<_InIt>(_IFirst_ch + _Count); } else { - _IFirst += reinterpret_cast(_IFirst_ch + _Count) - _IFirstPtr; + _IFirst += _Count / sizeof(iter_value_t<_InIt>); } + if constexpr (is_pointer_v<_OutIt>) { _OFirst = reinterpret_cast<_OutIt>(_OFirst_ch + _Count); } else { - _OFirst += reinterpret_cast(_OFirst_ch + _Count) - _OFirstPtr; + _OFirst += _Count / sizeof(iter_value_t<_OutIt>); } - return {_IFirst, _OFirst}; + return {_STD move(_IFirst), _STD move(_OFirst)}; } // ALIAS TEMPLATE uninitialized_move_result @@ -1590,11 +1591,12 @@ namespace ranges { _No_throw_sentinel_for<_Out> _OSe> requires constructible_from, iter_rvalue_reference_t<_It>> uninitialized_move_result<_It, _Out> _Uninitialized_move_unchecked( - _It _IFirst, const _Se _ILast, _Out _OFirst, const _OSe _OLast) { + _It _IFirst, _Se _ILast, _Out _OFirst, _OSe _OLast) { // clang-format on if constexpr (_Ptr_move_cat<_It, _Out>::_Really_trivial && sized_sentinel_for<_Se, _It> && sized_sentinel_for<_OSe, _Out>) { - return _Copy_memcpy_common(_IFirst, _RANGES next(_IFirst, _ILast), _OFirst, _RANGES next(_OFirst, _OLast)); + return _Copy_memcpy_common( + _IFirst, _RANGES next(_IFirst, _STD move(_ILast)), _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; diff --git a/stl/inc/xutility b/stl/inc/xutility index e7d38772892..9c5ee95a96f 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4145,7 +4145,7 @@ _OutCtgIt _Copy_memmove(_CtgIt _First, _CtgIt _Last, _OutCtgIt _Dest) { auto _DestPtr = _To_address(_Dest); const char* const _First_ch = const_cast(reinterpret_cast(_FirstPtr)); const char* const _Last_ch = const_cast(reinterpret_cast(_LastPtr)); - char* const _Dest_ch = const_cast(reinterpret_cast(_DestPtr)); + char* const _Dest_ch = const_cast(reinterpret_cast(_DestPtr)); const auto _Count = static_cast(_Last_ch - _First_ch); _CSTD memmove(_Dest_ch, _First_ch, _Count); if constexpr (is_pointer_v<_OutCtgIt>) { @@ -4262,7 +4262,7 @@ _CtgIt2 _Copy_backward_memmove(_CtgIt1 _First, _CtgIt1 _Last, _CtgIt2 _Dest) { auto _DestPtr = _To_address(_Dest); const char* const _First_ch = const_cast(reinterpret_cast(_FirstPtr)); const char* const _Last_ch = const_cast(reinterpret_cast(_LastPtr)); - char* const _Dest_ch = const_cast(reinterpret_cast(_DestPtr)); + 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>) { From 3c635e4cf254203a958939f1b946d7f63d5b5bda Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Fri, 26 Mar 2021 08:23:12 +0100 Subject: [PATCH 6/6] Forgot to save --- stl/inc/memory | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index 3c8394c6ee8..9eca0290cee 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -508,10 +508,10 @@ namespace ranges { // clang-format off template <_No_throw_input_iterator _It, _No_throw_sentinel_for<_It> _Se> requires destructible> - _NODISCARD _CONSTEXPR20_DYNALLOC _It _Destroy_unchecked(_It _First, const _Se _Last) noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC _It _Destroy_unchecked(_It _First, _Se _Last) noexcept { // clang-format on if constexpr (is_trivially_destructible_v>) { - _RANGES advance(_First, _Last); + _RANGES advance(_First, _STD move(_Last)); } else { for (; _First != _Last; ++_First) { _RANGES destroy_at(_STD addressof(*_First));