From 4549d9d9aca00c81f165e50deddeae4dea151b58 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Tue, 6 Apr 2021 17:42:58 +0200 Subject: [PATCH 01/12] Optimizations for unreachable sentinels --- stl/inc/algorithm | 36 ++++++++-- stl/inc/memory | 63 ++++++++++++----- stl/inc/xmemory | 67 ++++++++++++++++++- stl/inc/xutility | 19 +++++- .../tests/P0896R4_ranges_alg_equal/test.cpp | 11 ++- .../tests/P0896R4_ranges_alg_find/test.cpp | 17 +++-- .../test.cpp | 20 +++++- .../test.cpp | 12 ++++ .../test.cpp | 12 ++++ 9 files changed, 220 insertions(+), 37 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index e128b93569c..2cbc236ea9f 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -785,6 +785,16 @@ namespace ranges { template _NODISCARD static constexpr bool _Equal_4( _It1 _First1, _Se1 _Last1, _It2 _First2, _Se2 _Last2, _Pr _Pred, _Pj1 _Proj1, _Pj2 _Proj2) { + if constexpr ( + _Equal_memcmp_is_safe<_It1, _It2, + _Pr> && same_as<_Pj1, identity> && same_as<_Pj2, identity> + && (same_as<_Se1, unreachable_sentinel_t> || same_as<_Se2, unreachable_sentinel_t>) ) { + if constexpr (same_as<_Se1, _Se2>) { + _STL_ASSERT(false, "Tried to compare ranges with both sentinels being unreachable"); + } + return false; // If any of sentinels is unreachable the ranges are not equal + } + for (;;) { if (_First1 == _Last1) { return _First2 == _Last2; @@ -10394,12 +10404,28 @@ namespace ranges { using _Memcmp_classification_pred = typename decltype(_Lex_compare_memcmp_classify(_First1, _First2, _Pred))::_Pred; - if constexpr (!is_void_v<_Memcmp_classification_pred> && sized_sentinel_for<_Se1, _It1> // - && sized_sentinel_for<_Se2, _It2> && same_as<_Pj1, identity> && same_as<_Pj2, identity>) { + constexpr bool _Is_sized1 = sized_sentinel_for<_Se1, _It1>; + constexpr bool _Is_sized2 = sized_sentinel_for<_Se2, _It2>; + if constexpr (!is_void_v<_Memcmp_classification_pred> // + && (_Is_sized1 || same_as<_Se1, unreachable_sentinel_t>) // +#pragma warning(suppress : 6287) // Redundant code: the left and right subexpressions are identical + &&(_Is_sized2 || same_as<_Se2, unreachable_sentinel_t>) // + &&same_as<_Pj1, identity> && same_as<_Pj2, identity>) { if (!_STD is_constant_evaluated()) { - const auto _Num1 = static_cast(_Last1 - _First1); - const auto _Num2 = static_cast(_Last2 - _First2); - const int _Ans = _Memcmp_count(_First1, _First2, (_STD min)(_Num1, _Num2)); + size_t _Num1, _Num2; + if constexpr (_Is_sized1) { + _Num1 = static_cast(_Last1 - _First1); + } else { + _Num1 = SIZE_MAX; + } + + if constexpr (_Is_sized2) { + _Num2 = static_cast(_Last2 - _First2); + } else { + _Num2 = SIZE_MAX; + } + + const int _Ans = _Memcmp_count(_First1, _First2, (_STD min)(_Num1, _Num2)); return _Memcmp_classification_pred{}(_Ans, 0) || (_Ans == 0 && _Num1 < _Num2); } } diff --git a/stl/inc/memory b/stl/inc/memory index 9eca0290cee..9cd034c65af 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -78,10 +78,22 @@ namespace ranges { _STL_INTERNAL_STATIC_ASSERT(_No_throw_sentinel_for<_OSe, _Out>); _STL_INTERNAL_STATIC_ASSERT(constructible_from, iter_reference_t<_It>>); + 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_sentinel_for<_Se, _It> && sized_sentinel_for<_OSe, _Out>) { - return _Copy_memcpy_common(_IFirst, _RANGES next(_IFirst, _STD move(_ILast)), _OFirst, - _RANGES next(_OFirst, _STD move(_OLast))); + && (_Is_sized1 || same_as<_Se, unreachable_sentinel_t>) // +#pragma warning(suppress : 6287) // Redundant code: the left and right subexpressions are identical + &&(_Is_sized2 || same_as<_OSe, unreachable_sentinel_t>) ) { + if constexpr (_Is_sized1 && _Is_sized2) { + return _Copy_memcpy_common(_IFirst, _RANGES next(_IFirst, _STD move(_ILast)), _OFirst, + _RANGES next(_OFirst, _STD move(_OLast))); + } else if constexpr (_Is_sized1) { + return _Copy_memcpy_distance(_IFirst, _OFirst, _IFirst, _RANGES next(_IFirst, _STD move(_ILast))); + } else if constexpr (_Is_sized2) { + return _Copy_memcpy_distance(_IFirst, _OFirst, _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); + } else { + _STL_ASSERT(false, "Tried to uninitialized copy two ranges with unreachable sentinels"); + } } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; @@ -147,13 +159,22 @@ namespace ranges { } _Adl_verify_range(_First2, _Last2); - 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) { - auto _UResult = _Copy_memcpy_common(_IFirst, _IFirst + _Count, _OFirst, _OLast); - _IFirst = _UResult.in; - _OFirst = _UResult.out; + auto _IFirst = _Get_unwrapped_n(_STD move(_First1), _Count); + auto _OFirst = _Get_unwrapped(_STD move(_First2)); + auto _OLast = _Get_unwrapped(_STD move(_Last2)); + constexpr bool _Is_sized = sized_sentinel_for<_OSe, _Out>; + if constexpr (_Ptr_copy_cat<_It, _Out>::_Really_trivial + && (_Is_sized || same_as<_OSe, unreachable_sentinel_t>) ) { + if constexpr (_Is_sized) { + auto _UResult = _Copy_memcpy_common( + _IFirst, _IFirst + _Count, _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); + _IFirst = _UResult.in; + _OFirst = _UResult.out; + } else { + auto _UResult = _Copy_memcpy_count(_IFirst, _OFirst, static_cast(_Count)); + _IFirst = _UResult.in; + _OFirst = _UResult.out; + } } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; @@ -283,13 +304,21 @@ namespace ranges { } _Adl_verify_range(_First2, _Last2); - 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) { - auto _UResult = _Copy_memcpy_common(_IFirst, _IFirst + _Count, _OFirst, _OLast); - _IFirst = _UResult.in; - _OFirst = _UResult.out; + auto _IFirst = _Get_unwrapped_n(_STD move(_First1), _Count); + auto _OFirst = _Get_unwrapped(_STD move(_First2)); + const auto _OLast = _Get_unwrapped(_STD move(_Last2)); + constexpr bool _Is_sized = sized_sentinel_for<_OSe, _Out>; + if constexpr (_Ptr_move_cat<_It, _Out>::_Really_trivial + && (_Is_sized || same_as<_OSe, unreachable_sentinel_t>) ) { + if constexpr (_Is_sized) { + auto _UResult = _Copy_memcpy_common(_IFirst, _IFirst + _Count, _OFirst, _OLast); + _IFirst = _UResult.in; + _OFirst = _UResult.out; + } else { + auto _UResult = _Copy_memcpy_count(_IFirst, _OFirst, static_cast(_Count)); + _IFirst = _UResult.in; + _OFirst = _UResult.out; + } } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 49828d83b0e..f98d8bebd37 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1554,6 +1554,55 @@ namespace ranges { && _No_throw_forward_iterator>; // clang-format on + template + in_out_result<_InIt, _OutIt> _Copy_memcpy_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)); + const auto _OFirst_ch = const_cast(reinterpret_cast(_OFirstPtr)); + const size_t _Count_bytes = _Count * sizeof(iter_value_t<_InIt>); + _CSTD memcpy(_OFirst_ch, _IFirst_ch, _Count_bytes); + if constexpr (is_pointer_v<_InIt>) { + _IFirst = reinterpret_cast<_InIt>(_IFirst_ch + _Count_bytes); + } else { + _IFirst += _Count; + } + + if constexpr (is_pointer_v<_OutIt>) { + _OFirst = reinterpret_cast<_OutIt>(_OFirst_ch + _Count_bytes); + } else { + _OFirst += _Count; + } + return {_STD move(_IFirst), _STD move(_OFirst)}; + } + + template + in_out_result<_InIt, _OutIt> _Copy_memcpy_distance( + _InIt _IFirst, _OutIt _OFirst, _DistIt _DFirst, _DistIt _DLast) noexcept { + const auto _IFirstPtr = _To_address(_IFirst); + const auto _OFirstPtr = _To_address(_OFirst); + const auto _DFirstPtr = _To_address(_DFirst); + const auto _DLastPtr = _To_address(_DLast); + const auto _IFirst_ch = const_cast(reinterpret_cast(_IFirstPtr)); + const auto _OFirst_ch = const_cast(reinterpret_cast(_OFirstPtr)); + const auto _DFirst_ch = const_cast(reinterpret_cast(_DFirstPtr)); + const auto _DLast_ch = const_cast(reinterpret_cast(_DLastPtr)); + const auto _Count = static_cast(_DLast_ch - _DFirst_ch); + _CSTD memcpy(_OFirst_ch, _IFirst_ch, _Count); + if constexpr (is_pointer_v<_InIt>) { + _IFirst = reinterpret_cast<_InIt>(_IFirst_ch + _Count); + } else { + _IFirst += _Count / sizeof(iter_value_t<_InIt>); + } + + if constexpr (is_pointer_v<_OutIt>) { + _OFirst = reinterpret_cast<_OutIt>(_OFirst_ch + _Count); + } else { + _OFirst += _Count / sizeof(iter_value_t<_OutIt>); + } + return {_STD move(_IFirst), _STD move(_OFirst)}; + } + template in_out_result<_InIt, _OutIt> _Copy_memcpy_common( _InIt _IFirst, _InIt _ILast, _OutIt _OFirst, _OutIt _OLast) noexcept { @@ -1593,10 +1642,22 @@ namespace ranges { uninitialized_move_result<_It, _Out> _Uninitialized_move_unchecked( _It _IFirst, _Se _ILast, _Out _OFirst, _OSe _OLast) { // clang-format on + constexpr bool _Is_sized1 = sized_sentinel_for<_Se, _It>; + constexpr bool _Is_sized2 = sized_sentinel_for<_OSe, _Out>; 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, _STD move(_ILast)), _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); + && (_Is_sized1 || same_as<_Se, unreachable_sentinel_t>) +#pragma warning(suppress : 6287) // Redundant code: the left and right subexpressions are identical + && (_Is_sized2 || same_as<_OSe, unreachable_sentinel_t>)) { + if constexpr (_Is_sized1 && _Is_sized2) { + return _Copy_memcpy_common(_IFirst, _RANGES next(_IFirst, _STD move(_ILast)), _OFirst, + _RANGES next(_OFirst, _STD move(_OLast))); + } else if constexpr (_Is_sized1) { + return _Copy_memcpy_distance(_IFirst, _OFirst, _IFirst, _RANGES next(_IFirst, _STD move(_ILast))); + } else if constexpr (_Is_sized2) { + return _Copy_memcpy_distance(_IFirst, _OFirst, _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); + } else { + _STL_ASSERT(false, "Tried to uninitialized move two ranges with unreachable sentinels"); + } } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; diff --git a/stl/inc/xutility b/stl/inc/xutility index 728c332e48e..49cc5829692 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -5220,15 +5220,28 @@ namespace ranges { template _Se, class _Ty, class _Pj = identity> requires indirect_binary_predicate, const _Ty*> _NODISCARD constexpr _It _Find_unchecked(_It _First, const _Se _Last, const _Ty& _Val, _Pj _Proj = {}) { - if constexpr (_Memchr_in_find_is_safe<_It, _Ty> && sized_sentinel_for<_Se, _It> && same_as<_Pj, identity>) { + constexpr bool _Is_sized = sized_sentinel_for<_Se, _It>; + if constexpr (_Memchr_in_find_is_safe<_It, _Ty> && (_Is_sized || same_as<_Se, unreachable_sentinel_t>) + && same_as<_Pj, identity>) { if (!_STD is_constant_evaluated()) { if (!_Within_limits(_First, _Val)) { - return _RANGES next(_STD move(_First), _Last); + if constexpr (_Is_sized) { + return _RANGES next(_STD move(_First), _Last); + } else { + _STL_ASSERT(false, "Tried to find a value in a range with unreachable sentinel" + " that is not within limits of range's value type"); + } } + size_t _Count; + if constexpr (_Is_sized) { + _Count = static_cast(_Last - _First); + } else { + _Count = SIZE_MAX; + } const auto _First_ptr = _STD to_address(_First); const auto _Result = static_cast>*>(_CSTD memchr(_First_ptr, - static_cast(_Val), static_cast(_Last - _First))); + static_cast(_Val), _Count)); if (_Result) { if constexpr (is_pointer_v<_It>) { return _Result; diff --git a/tests/std/tests/P0896R4_ranges_alg_equal/test.cpp b/tests/std/tests/P0896R4_ranges_alg_equal/test.cpp index 9ff968ec58b..f8fe477abeb 100644 --- a/tests/std/tests/P0896R4_ranges_alg_equal/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_equal/test.cpp @@ -11,8 +11,8 @@ #include constexpr void smoke_test() { - using ranges::equal, ranges::equal_to; - using std::abort, std::array, std::pair, std::same_as; + using ranges::equal, ranges::equal_to, ranges::begin, ranges::end; + using std::abort, std::array, std::pair, std::same_as, std::unreachable_sentinel; array, 3> const x = {{{0, 42}, {2, 42}, {4, 42}}}; array, 3> const y = {{{13, -1}, {13, 1}, {13, 3}}}; @@ -71,6 +71,13 @@ constexpr void smoke_test() { arr2[1] = 7; assert(!equal(arr1, arr2)); } + { + // Validate memcmp + unreachable_sentinel cases + int arr1[3]{0, 2, 5}; + int arr2[3]{0, 2, 5}; + assert(!equal(begin(arr1), unreachable_sentinel, begin(arr2), end(arr2))); + assert(!equal(begin(arr1), end(arr1), begin(arr2), unreachable_sentinel)); + } } int main() { diff --git a/tests/std/tests/P0896R4_ranges_alg_find/test.cpp b/tests/std/tests/P0896R4_ranges_alg_find/test.cpp index f364a6823d2..3ea0e547545 100644 --- a/tests/std/tests/P0896R4_ranges_alg_find/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_find/test.cpp @@ -20,7 +20,7 @@ struct instantiator { template static constexpr void call() { - using ranges::find, ranges::iterator_t; + using ranges::find, ranges::iterator_t, ranges::begin, ranges::end; for (const auto& [value, _] : haystack) { { // Validate range overload [found case] @@ -48,15 +48,20 @@ struct instantiator { STATIC_ASSERT(same_as>); assert(result == wrapped_input.end()); } - { // Validate memchr case [found case] + { // Validate memchr case char arr[5]{4, 8, 1, -15, 125}; + + // found case auto result = find(arr, 1); assert(*result == 1); - } - { // Validate memchr case [not found case] - char arr[5]{4, 8, 1, -15, 125}; - auto result = find(arr, 10); + + // not found case + result = find(arr, 10); assert(result == end(arr)); + + // unreachable_sentinel case + result = find(begin(arr), unreachable_sentinel, 1); + assert(*result == 1); } } }; diff --git a/tests/std/tests/P0896R4_ranges_alg_lexicographical_compare/test.cpp b/tests/std/tests/P0896R4_ranges_alg_lexicographical_compare/test.cpp index 5bc0e34358b..d3fcc5dedc9 100644 --- a/tests/std/tests/P0896R4_ranges_alg_lexicographical_compare/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_lexicographical_compare/test.cpp @@ -26,7 +26,7 @@ struct instantiator { template static constexpr void call() { - using ranges::lexicographical_compare, ranges::less; + using ranges::lexicographical_compare, ranges::less, ranges::begin, ranges::end; // Validate range overload { @@ -202,6 +202,24 @@ struct instantiator { arr2[2] = 1; assert(!lexicographical_compare(arr1, arr2)); } + { // Validate memcmp + unreachable_sentinel cases + unsigned char arr1[3]{0, 1, 2}; + unsigned char arr2[3]{0, 1, 3}; + + assert(lexicographical_compare(begin(arr1), end(arr1), begin(arr1), unreachable_sentinel)); + assert(!lexicographical_compare(begin(arr1), unreachable_sentinel, begin(arr1), end(arr1))); + + assert(lexicographical_compare(begin(arr1), unreachable_sentinel, begin(arr2), unreachable_sentinel)); + assert(lexicographical_compare(begin(arr1), unreachable_sentinel, begin(arr2), end(arr2))); + assert(lexicographical_compare(begin(arr1), end(arr1), begin(arr2), unreachable_sentinel)); + arr2[2] = 2; + assert(!lexicographical_compare(begin(arr1), unreachable_sentinel, begin(arr2), end(arr2))); + assert(lexicographical_compare(begin(arr1), end(arr1), begin(arr2), unreachable_sentinel)); + arr2[2] = 1; + assert(!lexicographical_compare(begin(arr1), unreachable_sentinel, begin(arr2), unreachable_sentinel)); + assert(!lexicographical_compare(begin(arr1), unreachable_sentinel, begin(arr2), end(arr2))); + assert(!lexicographical_compare(begin(arr1), end(arr1), begin(arr2), unreachable_sentinel)); + } } }; diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp index 3096d91b16a..a60bb43e67c 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp @@ -209,6 +209,18 @@ struct memcpy_test { assert(equal(input, expected_input)); assert(equal(output, expected_input_short)); } + + { // Validate unreachable_sentinel + vector input = {13, 55, 12345, 42}; + vector output = {-1, -1, -1, -1}; + + const same_as>, iterator_t>>> auto result = + uninitialized_copy_n(input.begin(), 3, output.begin(), unreachable_sentinel); + assert(next(result.in) == input.end()); + assert(next(result.out) == output.end()); + assert(equal(input, expected_input)); + assert(equal(output, expected_output)); + } } }; diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp index 60d6a79c732..787320c668d 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp @@ -210,6 +210,18 @@ struct memcpy_test { assert(equal(input, expected_input)); assert(equal(output, expected_input_short)); } + + { // Validate unreachable_sentinel + vector input = {13, 55, 12345, 42}; + vector output = {-1, -1, -1, -1}; + + const same_as>, iterator_t>>> auto result = + uninitialized_move_n(input.begin(), 3, output.begin(), unreachable_sentinel); + assert(next(result.in) == input.end()); + assert(next(result.out) == output.end()); + assert(equal(input, expected_input)); + assert(equal(output, expected_output)); + } } }; From d20d5485325b3c46c3171e0c75752d6848dc4baa Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Tue, 6 Apr 2021 18:15:42 +0200 Subject: [PATCH 02/12] clang-format --- stl/inc/algorithm | 7 +++---- stl/inc/memory | 6 +++--- stl/inc/xmemory | 4 ++-- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 2cbc236ea9f..2acefd63343 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -785,10 +785,9 @@ namespace ranges { template _NODISCARD static constexpr bool _Equal_4( _It1 _First1, _Se1 _Last1, _It2 _First2, _Se2 _Last2, _Pr _Pred, _Pj1 _Proj1, _Pj2 _Proj2) { - if constexpr ( - _Equal_memcmp_is_safe<_It1, _It2, - _Pr> && same_as<_Pj1, identity> && same_as<_Pj2, identity> - && (same_as<_Se1, unreachable_sentinel_t> || same_as<_Se2, unreachable_sentinel_t>) ) { + if constexpr (_Equal_memcmp_is_safe<_It1, _It2, _Pr> && same_as<_Pj1, identity> // + && same_as<_Pj2, identity> // + && (same_as<_Se1, unreachable_sentinel_t> || same_as<_Se2, unreachable_sentinel_t>) ) { if constexpr (same_as<_Se1, _Se2>) { _STL_ASSERT(false, "Tried to compare ranges with both sentinels being unreachable"); } diff --git a/stl/inc/memory b/stl/inc/memory index 9cd034c65af..479861d2739 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -161,7 +161,7 @@ namespace ranges { _Adl_verify_range(_First2, _Last2); auto _IFirst = _Get_unwrapped_n(_STD move(_First1), _Count); auto _OFirst = _Get_unwrapped(_STD move(_First2)); - auto _OLast = _Get_unwrapped(_STD move(_Last2)); + auto _OLast = _Get_unwrapped(_STD move(_Last2)); constexpr bool _Is_sized = sized_sentinel_for<_OSe, _Out>; if constexpr (_Ptr_copy_cat<_It, _Out>::_Really_trivial && (_Is_sized || same_as<_OSe, unreachable_sentinel_t>) ) { @@ -172,8 +172,8 @@ namespace ranges { _OFirst = _UResult.out; } else { auto _UResult = _Copy_memcpy_count(_IFirst, _OFirst, static_cast(_Count)); - _IFirst = _UResult.in; - _OFirst = _UResult.out; + _IFirst = _UResult.in; + _OFirst = _UResult.out; } } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; diff --git a/stl/inc/xmemory b/stl/inc/xmemory index f98d8bebd37..c7f34a0f5ce 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1575,7 +1575,7 @@ namespace ranges { } return {_STD move(_IFirst), _STD move(_OFirst)}; } - + template in_out_result<_InIt, _OutIt> _Copy_memcpy_distance( _InIt _IFirst, _OutIt _OFirst, _DistIt _DFirst, _DistIt _DLast) noexcept { @@ -1647,7 +1647,7 @@ namespace ranges { if constexpr (_Ptr_move_cat<_It, _Out>::_Really_trivial && (_Is_sized1 || same_as<_Se, unreachable_sentinel_t>) #pragma warning(suppress : 6287) // Redundant code: the left and right subexpressions are identical - && (_Is_sized2 || same_as<_OSe, unreachable_sentinel_t>)) { + &&(_Is_sized2 || same_as<_OSe, unreachable_sentinel_t>) ) { if constexpr (_Is_sized1 && _Is_sized2) { return _Copy_memcpy_common(_IFirst, _RANGES next(_IFirst, _STD move(_ILast)), _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); From a161a9a78bdab8394ddfe4c8f72a0403908cbbe4 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Wed, 7 Apr 2021 09:56:00 +0200 Subject: [PATCH 03/12] Code review --- stl/inc/algorithm | 10 +++++----- stl/inc/memory | 23 +++++++++-------------- stl/inc/xmemory | 5 ++--- stl/inc/xutility | 5 ++++- 4 files changed, 20 insertions(+), 23 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 2acefd63343..708e20dbf1a 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -10405,19 +10405,19 @@ namespace ranges { typename decltype(_Lex_compare_memcmp_classify(_First1, _First2, _Pred))::_Pred; constexpr bool _Is_sized1 = sized_sentinel_for<_Se1, _It1>; constexpr bool _Is_sized2 = sized_sentinel_for<_Se2, _It2>; - if constexpr (!is_void_v<_Memcmp_classification_pred> // - && (_Is_sized1 || same_as<_Se1, unreachable_sentinel_t>) // + if constexpr (!is_void_v<_Memcmp_classification_pred> && _Sized_or_unreachable_sentinel_for<_Se1, _It1> #pragma warning(suppress : 6287) // Redundant code: the left and right subexpressions are identical - &&(_Is_sized2 || same_as<_Se2, unreachable_sentinel_t>) // - &&same_as<_Pj1, identity> && same_as<_Pj2, identity>) { + && _Sized_or_unreachable_sentinel_for<_Se2, _It2> // + && same_as<_Pj1, identity> && same_as<_Pj2, identity>) { if (!_STD is_constant_evaluated()) { - size_t _Num1, _Num2; + size_t _Num1; if constexpr (_Is_sized1) { _Num1 = static_cast(_Last1 - _First1); } else { _Num1 = SIZE_MAX; } + size_t _Num2; if constexpr (_Is_sized2) { _Num2 = static_cast(_Last2 - _First2); } else { diff --git a/stl/inc/memory b/stl/inc/memory index 479861d2739..a57556a025e 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -80,10 +80,9 @@ 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 - && (_Is_sized1 || same_as<_Se, unreachable_sentinel_t>) // + if constexpr (_Ptr_copy_cat<_It, _Out>::_Really_trivial && _Sized_or_unreachable_sentinel_for<_Se, _It> #pragma warning(suppress : 6287) // Redundant code: the left and right subexpressions are identical - &&(_Is_sized2 || same_as<_OSe, unreachable_sentinel_t>) ) { + && _Sized_or_unreachable_sentinel_for<_OSe, _Out>) { if constexpr (_Is_sized1 && _Is_sized2) { return _Copy_memcpy_common(_IFirst, _RANGES next(_IFirst, _STD move(_ILast)), _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); @@ -162,10 +161,8 @@ 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)); - constexpr bool _Is_sized = sized_sentinel_for<_OSe, _Out>; - if constexpr (_Ptr_copy_cat<_It, _Out>::_Really_trivial - && (_Is_sized || same_as<_OSe, unreachable_sentinel_t>) ) { - if constexpr (_Is_sized) { + if constexpr (_Ptr_copy_cat<_It, _Out>::_Really_trivial && _Sized_or_unreachable_sentinel_for<_OSe, _Out>) { + if constexpr (sized_sentinel_for<_OSe, _Out>) { auto _UResult = _Copy_memcpy_common( _IFirst, _IFirst + _Count, _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); _IFirst = _UResult.in; @@ -304,13 +301,11 @@ namespace ranges { } _Adl_verify_range(_First2, _Last2); - auto _IFirst = _Get_unwrapped_n(_STD move(_First1), _Count); - auto _OFirst = _Get_unwrapped(_STD move(_First2)); - const auto _OLast = _Get_unwrapped(_STD move(_Last2)); - constexpr bool _Is_sized = sized_sentinel_for<_OSe, _Out>; - if constexpr (_Ptr_move_cat<_It, _Out>::_Really_trivial - && (_Is_sized || same_as<_OSe, unreachable_sentinel_t>) ) { - if constexpr (_Is_sized) { + 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 (sized_sentinel_for<_OSe, _Out>) { auto _UResult = _Copy_memcpy_common(_IFirst, _IFirst + _Count, _OFirst, _OLast); _IFirst = _UResult.in; _OFirst = _UResult.out; diff --git a/stl/inc/xmemory b/stl/inc/xmemory index c7f34a0f5ce..05710b4d2da 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1644,10 +1644,9 @@ namespace ranges { // clang-format on constexpr bool _Is_sized1 = sized_sentinel_for<_Se, _It>; constexpr bool _Is_sized2 = sized_sentinel_for<_OSe, _Out>; - if constexpr (_Ptr_move_cat<_It, _Out>::_Really_trivial - && (_Is_sized1 || same_as<_Se, unreachable_sentinel_t>) + if constexpr (_Ptr_move_cat<_It, _Out>::_Really_trivial && _Sized_or_unreachable_sentinel_for<_Se, _It> #pragma warning(suppress : 6287) // Redundant code: the left and right subexpressions are identical - &&(_Is_sized2 || same_as<_OSe, unreachable_sentinel_t>) ) { + && _Sized_or_unreachable_sentinel_for<_OSe, _Out>) { if constexpr (_Is_sized1 && _Is_sized2) { return _Copy_memcpy_common(_IFirst, _RANGES next(_IFirst, _STD move(_ILast)), _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); diff --git a/stl/inc/xutility b/stl/inc/xutility index 49cc5829692..58fac24536a 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -5216,12 +5216,15 @@ _NODISCARD _FwdIt find(_ExPo&& _Exec, _FwdIt _First, const _FwdIt _Last, const _ #ifdef __cpp_lib_concepts namespace ranges { // clang-format off + template + concept _Sized_or_unreachable_sentinel_for = sized_sentinel_for<_Se, _It> || same_as<_Se, unreachable_sentinel_t>; + // concept-constrained for strict enforcement as it is used by several algorithms template _Se, class _Ty, class _Pj = identity> requires indirect_binary_predicate, const _Ty*> _NODISCARD constexpr _It _Find_unchecked(_It _First, const _Se _Last, const _Ty& _Val, _Pj _Proj = {}) { constexpr bool _Is_sized = sized_sentinel_for<_Se, _It>; - if constexpr (_Memchr_in_find_is_safe<_It, _Ty> && (_Is_sized || same_as<_Se, unreachable_sentinel_t>) + if constexpr (_Memchr_in_find_is_safe<_It, _Ty> && _Sized_or_unreachable_sentinel_for<_Se, _It> && same_as<_Pj, identity>) { if (!_STD is_constant_evaluated()) { if (!_Within_limits(_First, _Val)) { From fbb5cc2595180a9702576f895373ff04dd3609a6 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Wed, 7 Apr 2021 10:22:43 +0200 Subject: [PATCH 04/12] clang-format --- stl/inc/memory | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index a57556a025e..c417b95e28b 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -158,9 +158,9 @@ namespace ranges { } _Adl_verify_range(_First2, _Last2); - auto _IFirst = _Get_unwrapped_n(_STD move(_First1), _Count); - auto _OFirst = _Get_unwrapped(_STD move(_First2)); - auto _OLast = _Get_unwrapped(_STD move(_Last2)); + 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 (sized_sentinel_for<_OSe, _Out>) { auto _UResult = _Copy_memcpy_common( From 1de209e1ce24af4a83fa198231757138dc53aa42 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Fri, 21 May 2021 08:10:58 +0200 Subject: [PATCH 05/12] Apply suggestions from code review Co-authored-by: Casey Carter --- stl/inc/memory | 3 ++- stl/inc/xmemory | 3 ++- stl/inc/xutility | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index c417b95e28b..31e836d5287 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -91,7 +91,8 @@ namespace ranges { } else if constexpr (_Is_sized2) { return _Copy_memcpy_distance(_IFirst, _OFirst, _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); } else { - _STL_ASSERT(false, "Tried to uninitialized copy two ranges with unreachable sentinels"); + _STL_ASSERT(false, "Tried to uninitialized_copy two ranges with unreachable sentinels"); + } } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 05710b4d2da..24f683a81dc 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1655,7 +1655,8 @@ namespace ranges { } else if constexpr (_Is_sized2) { return _Copy_memcpy_distance(_IFirst, _OFirst, _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); } else { - _STL_ASSERT(false, "Tried to uninitialized move two ranges with unreachable sentinels"); + _STL_ASSERT(false, "Tried to uninitialized_move two ranges with unreachable sentinels"); + } } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; diff --git a/stl/inc/xutility b/stl/inc/xutility index 58fac24536a..07896fa71bf 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -5232,7 +5232,7 @@ namespace ranges { return _RANGES next(_STD move(_First), _Last); } else { _STL_ASSERT(false, "Tried to find a value in a range with unreachable sentinel" - " that is not within limits of range's value type"); + " that cannot be represented by the range's value type"); } } From 571509022c2dbcf7f90412f6e5e3b86f5f2c4c62 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Fri, 21 May 2021 10:47:04 +0200 Subject: [PATCH 06/12] Code review --- stl/inc/algorithm | 9 --- stl/inc/memory | 4 +- stl/inc/xmemory | 58 +++++++++---------- .../tests/P0896R4_ranges_alg_equal/test.cpp | 2 +- .../test.cpp | 13 +++++ .../test.cpp | 13 +++++ 6 files changed, 58 insertions(+), 41 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 708e20dbf1a..eb8a8a31c10 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -785,15 +785,6 @@ namespace ranges { template _NODISCARD static constexpr bool _Equal_4( _It1 _First1, _Se1 _Last1, _It2 _First2, _Se2 _Last2, _Pr _Pred, _Pj1 _Proj1, _Pj2 _Proj2) { - if constexpr (_Equal_memcmp_is_safe<_It1, _It2, _Pr> && same_as<_Pj1, identity> // - && same_as<_Pj2, identity> // - && (same_as<_Se1, unreachable_sentinel_t> || same_as<_Se2, unreachable_sentinel_t>) ) { - if constexpr (same_as<_Se1, _Se2>) { - _STL_ASSERT(false, "Tried to compare ranges with both sentinels being unreachable"); - } - return false; // If any of sentinels is unreachable the ranges are not equal - } - for (;;) { if (_First1 == _Last1) { return _First2 == _Last2; diff --git a/stl/inc/memory b/stl/inc/memory index 31e836d5287..51c493a9d09 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -92,7 +92,6 @@ namespace ranges { return _Copy_memcpy_distance(_IFirst, _OFirst, _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); } else { _STL_ASSERT(false, "Tried to uninitialized_copy two ranges with unreachable sentinels"); - } } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; @@ -307,7 +306,8 @@ namespace ranges { 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 (sized_sentinel_for<_OSe, _Out>) { - auto _UResult = _Copy_memcpy_common(_IFirst, _IFirst + _Count, _OFirst, _OLast); + auto _UResult = _Copy_memcpy_common( + _IFirst, _IFirst + _Count, _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); _IFirst = _UResult.in; _OFirst = _UResult.out; } else { diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 24f683a81dc..330c66d4c86 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1579,26 +1579,27 @@ namespace ranges { template in_out_result<_InIt, _OutIt> _Copy_memcpy_distance( _InIt _IFirst, _OutIt _OFirst, _DistIt _DFirst, _DistIt _DLast) noexcept { - const auto _IFirstPtr = _To_address(_IFirst); - const auto _OFirstPtr = _To_address(_OFirst); - const auto _DFirstPtr = _To_address(_DFirst); - const auto _DLastPtr = _To_address(_DLast); - const auto _IFirst_ch = const_cast(reinterpret_cast(_IFirstPtr)); - const auto _OFirst_ch = const_cast(reinterpret_cast(_OFirstPtr)); - const auto _DFirst_ch = const_cast(reinterpret_cast(_DFirstPtr)); - const auto _DLast_ch = const_cast(reinterpret_cast(_DLastPtr)); - const auto _Count = static_cast(_DLast_ch - _DFirst_ch); - _CSTD memcpy(_OFirst_ch, _IFirst_ch, _Count); + // equivalent to _Copy_memcpy_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); + const auto _DLastPtr = _To_address(_DLast); + const auto _IFirst_ch = const_cast(reinterpret_cast(_IFirstPtr)); + const auto _OFirst_ch = const_cast(reinterpret_cast(_OFirstPtr)); + const auto _DFirst_ch = const_cast(reinterpret_cast(_DFirstPtr)); + const auto _DLast_ch = const_cast(reinterpret_cast(_DLastPtr)); + const auto _Count_bytes = static_cast(_DLast_ch - _DFirst_ch); + _CSTD memcpy(_OFirst_ch, _IFirst_ch, _Count_bytes); if constexpr (is_pointer_v<_InIt>) { - _IFirst = reinterpret_cast<_InIt>(_IFirst_ch + _Count); + _IFirst = reinterpret_cast<_InIt>(_IFirst_ch + _Count_bytes); } else { - _IFirst += _Count / sizeof(iter_value_t<_InIt>); + _IFirst += _Count_bytes / sizeof(iter_value_t<_InIt>); } if constexpr (is_pointer_v<_OutIt>) { - _OFirst = reinterpret_cast<_OutIt>(_OFirst_ch + _Count); + _OFirst = reinterpret_cast<_OutIt>(_OFirst_ch + _Count_bytes); } else { - _OFirst += _Count / sizeof(iter_value_t<_OutIt>); + _OFirst += _Count_bytes / sizeof(iter_value_t<_OutIt>); } return {_STD move(_IFirst), _STD move(_OFirst)}; } @@ -1606,26 +1607,26 @@ namespace ranges { template in_out_result<_InIt, _OutIt> _Copy_memcpy_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); - 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); + 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_bytes = static_cast((_STD min)(_ILast_ch - _IFirst_ch, _OLast_ch - _OFirst_ch)); + _CSTD memcpy(_OFirst_ch, _IFirst_ch, _Count_bytes); if constexpr (is_pointer_v<_InIt>) { - _IFirst = reinterpret_cast<_InIt>(_IFirst_ch + _Count); + _IFirst = reinterpret_cast<_InIt>(_IFirst_ch + _Count_bytes); } else { - _IFirst += _Count / sizeof(iter_value_t<_InIt>); + _IFirst += _Count_bytes / sizeof(iter_value_t<_InIt>); } if constexpr (is_pointer_v<_OutIt>) { - _OFirst = reinterpret_cast<_OutIt>(_OFirst_ch + _Count); + _OFirst = reinterpret_cast<_OutIt>(_OFirst_ch + _Count_bytes); } else { - _OFirst += _Count / sizeof(iter_value_t<_OutIt>); + _OFirst += _Count_bytes / sizeof(iter_value_t<_OutIt>); } return {_STD move(_IFirst), _STD move(_OFirst)}; } @@ -1656,7 +1657,6 @@ namespace ranges { return _Copy_memcpy_distance(_IFirst, _OFirst, _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); } else { _STL_ASSERT(false, "Tried to uninitialized_move two ranges with unreachable sentinels"); - } } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; diff --git a/tests/std/tests/P0896R4_ranges_alg_equal/test.cpp b/tests/std/tests/P0896R4_ranges_alg_equal/test.cpp index f8fe477abeb..6d5d00c1cb7 100644 --- a/tests/std/tests/P0896R4_ranges_alg_equal/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_equal/test.cpp @@ -72,7 +72,7 @@ constexpr void smoke_test() { assert(!equal(arr1, arr2)); } { - // Validate memcmp + unreachable_sentinel cases + // Validate unreachable_sentinel cases int arr1[3]{0, 2, 5}; int arr2[3]{0, 2, 5}; assert(!equal(begin(arr1), unreachable_sentinel, begin(arr2), end(arr2))); diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp index a60bb43e67c..d648315e590 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp @@ -221,6 +221,19 @@ struct memcpy_test { assert(equal(input, expected_input)); assert(equal(output, expected_output)); } + + { // Validate non-common range + vector input = {13, 55, 12345, 42}; + vector output = {-1, -1, -1, -1}; + + auto wrapped_output = output | views::take_while([](const auto&) { return true; }); + const same_as>, iterator_t>>> auto result = + uninitialized_copy_n(input.begin(), 3, wrapped_output.begin(), wrapped_output.end()); + assert(next(result.in) == input.end()); + assert(next(result.out) == output.end()); + assert(equal(input, expected_input)); + assert(equal(output, expected_output)); + } } }; diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp index 787320c668d..ecc0f60e578 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp @@ -222,6 +222,19 @@ struct memcpy_test { assert(equal(input, expected_input)); assert(equal(output, expected_output)); } + + { // Validate non-common range + vector input = {13, 55, 12345, 42}; + vector output = {-1, -1, -1, -1}; + + auto wrapped_output = output | views::take_while([](const auto&) { return true; }); + const same_as>, iterator_t>>> auto result = + uninitialized_move_n(input.begin(), 3, wrapped_output.begin(), wrapped_output.end()); + assert(next(result.in) == input.end()); + assert(next(result.out) == output.end()); + assert(equal(input, expected_input)); + assert(equal(output, expected_output)); + } } }; From 79750b23bb3aace2ad19b275842877c36a95edfd Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Fri, 21 May 2021 10:58:02 +0200 Subject: [PATCH 07/12] const --- stl/inc/xmemory | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 451855e8e3d..beaebdb09ee 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1557,7 +1557,7 @@ namespace ranges { template in_out_result<_InIt, _OutIt> _Copy_memcpy_distance( - _InIt _IFirst, _OutIt _OFirst, _DistIt _DFirst, _DistIt _DLast) noexcept { + _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 const auto _IFirstPtr = _To_address(_IFirst); const auto _OFirstPtr = _To_address(_OFirst); From 46bbdc9b5d1b0d23871ec01047af17ecfd22cd2a Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Fri, 21 May 2021 10:59:53 +0200 Subject: [PATCH 08/12] clang-format --- stl/inc/memory | 4 ++-- stl/inc/xutility | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index 51c493a9d09..e42730cfe43 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -308,8 +308,8 @@ namespace ranges { if constexpr (sized_sentinel_for<_OSe, _Out>) { auto _UResult = _Copy_memcpy_common( _IFirst, _IFirst + _Count, _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); - _IFirst = _UResult.in; - _OFirst = _UResult.out; + _IFirst = _UResult.in; + _OFirst = _UResult.out; } else { auto _UResult = _Copy_memcpy_count(_IFirst, _OFirst, static_cast(_Count)); _IFirst = _UResult.in; diff --git a/stl/inc/xutility b/stl/inc/xutility index 00af9e5261b..f7bb3a33b2e 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -5361,15 +5361,15 @@ namespace ranges { _NODISCARD constexpr _It _Find_unchecked(_It _First, const _Se _Last, const _Ty& _Val, _Pj _Proj = {}) { // clang-format on constexpr bool _Is_sized = sized_sentinel_for<_Se, _It>; - if constexpr (_Memchr_in_find_is_safe<_It, _Ty> && _Sized_or_unreachable_sentinel_for<_Se, _It> - && same_as<_Pj, identity>) { + if constexpr (_Memchr_in_find_is_safe<_It, + _Ty> && _Sized_or_unreachable_sentinel_for<_Se, _It> && same_as<_Pj, identity>) { if (!_STD is_constant_evaluated()) { if (!_Within_limits(_First, _Val)) { if constexpr (_Is_sized) { return _RANGES next(_STD move(_First), _Last); } else { _STL_ASSERT(false, "Tried to find a value in a range with unreachable sentinel" - " that cannot be represented by the range's value type"); + " that cannot be represented by the range's value type"); } } From 6f39c5b83bed5a6290ae9a892b6ed5a05ee38b9b Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Sun, 23 May 2021 12:16:19 +0200 Subject: [PATCH 09/12] remove warning suppressions --- stl/inc/algorithm | 1 - stl/inc/memory | 1 - stl/inc/xmemory | 1 - 3 files changed, 3 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index f941dd3074f..9afb5ff1c7d 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -10260,7 +10260,6 @@ namespace ranges { constexpr bool _Is_sized1 = sized_sentinel_for<_Se1, _It1>; constexpr bool _Is_sized2 = sized_sentinel_for<_Se2, _It2>; if constexpr (!is_void_v<_Memcmp_classification_pred> && _Sized_or_unreachable_sentinel_for<_Se1, _It1> -#pragma warning(suppress : 6287) // Redundant code: the left and right subexpressions are identical && _Sized_or_unreachable_sentinel_for<_Se2, _It2> // && same_as<_Pj1, identity> && same_as<_Pj2, identity>) { if (!_STD is_constant_evaluated()) { diff --git a/stl/inc/memory b/stl/inc/memory index e42730cfe43..a7ba039f100 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -81,7 +81,6 @@ 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> -#pragma warning(suppress : 6287) // Redundant code: the left and right subexpressions are identical && _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, diff --git a/stl/inc/xmemory b/stl/inc/xmemory index beaebdb09ee..e950a342cb4 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1625,7 +1625,6 @@ namespace ranges { constexpr bool _Is_sized1 = sized_sentinel_for<_Se, _It>; constexpr bool _Is_sized2 = sized_sentinel_for<_OSe, _Out>; if constexpr (_Ptr_move_cat<_It, _Out>::_Really_trivial && _Sized_or_unreachable_sentinel_for<_Se, _It> -#pragma warning(suppress : 6287) // Redundant code: the left and right subexpressions are identical && _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, From 97917892a371527c20c5fa67b36de1811849c1f6 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Sun, 23 May 2021 12:24:54 +0200 Subject: [PATCH 10/12] workaround clang-format --- stl/inc/algorithm | 2 +- stl/inc/memory | 2 +- stl/inc/xmemory | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 9afb5ff1c7d..eadeb2daefb 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -10259,7 +10259,7 @@ namespace ranges { typename decltype(_Lex_compare_memcmp_classify(_First1, _First2, _Pred))::_Pred; constexpr bool _Is_sized1 = sized_sentinel_for<_Se1, _It1>; constexpr bool _Is_sized2 = sized_sentinel_for<_Se2, _It2>; - if constexpr (!is_void_v<_Memcmp_classification_pred> && _Sized_or_unreachable_sentinel_for<_Se1, _It1> + if constexpr (!is_void_v<_Memcmp_classification_pred> && _Sized_or_unreachable_sentinel_for<_Se1, _It1> // && _Sized_or_unreachable_sentinel_for<_Se2, _It2> // && same_as<_Pj1, identity> && same_as<_Pj2, identity>) { if (!_STD is_constant_evaluated()) { diff --git a/stl/inc/memory b/stl/inc/memory index a7ba039f100..70f9bff73de 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -80,7 +80,7 @@ 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 (_Ptr_copy_cat<_It, _Out>::_Really_trivial && _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, diff --git a/stl/inc/xmemory b/stl/inc/xmemory index e950a342cb4..c2f5bf6f866 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1624,7 +1624,7 @@ namespace ranges { // clang-format on constexpr bool _Is_sized1 = sized_sentinel_for<_Se, _It>; constexpr bool _Is_sized2 = sized_sentinel_for<_OSe, _Out>; - if constexpr (_Ptr_move_cat<_It, _Out>::_Really_trivial && _Sized_or_unreachable_sentinel_for<_Se, _It> + if constexpr (_Ptr_move_cat<_It, _Out>::_Really_trivial && _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, From 8a720b0277b1d34981667b2778c71b5fc907a4f6 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 9 Jun 2021 19:12:54 -0700 Subject: [PATCH 11/12] Code review feedback. --- stl/inc/memory | 16 ++++++++-------- stl/inc/xmemory | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index 70f9bff73de..de4addfbe74 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -164,12 +164,12 @@ namespace ranges { if constexpr (sized_sentinel_for<_OSe, _Out>) { auto _UResult = _Copy_memcpy_common( _IFirst, _IFirst + _Count, _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); - _IFirst = _UResult.in; - _OFirst = _UResult.out; + _IFirst = _STD move(_UResult.in); + _OFirst = _STD move(_UResult.out); } else { auto _UResult = _Copy_memcpy_count(_IFirst, _OFirst, static_cast(_Count)); - _IFirst = _UResult.in; - _OFirst = _UResult.out; + _IFirst = _STD move(_UResult.in); + _OFirst = _STD move(_UResult.out); } } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; @@ -307,12 +307,12 @@ namespace ranges { if constexpr (sized_sentinel_for<_OSe, _Out>) { auto _UResult = _Copy_memcpy_common( _IFirst, _IFirst + _Count, _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); - _IFirst = _UResult.in; - _OFirst = _UResult.out; + _IFirst = _STD move(_UResult.in); + _OFirst = _STD move(_UResult.out); } else { auto _UResult = _Copy_memcpy_count(_IFirst, _OFirst, static_cast(_Count)); - _IFirst = _UResult.in; - _OFirst = _UResult.out; + _IFirst = _STD move(_UResult.in); + _OFirst = _STD move(_UResult.out); } } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; diff --git a/stl/inc/xmemory b/stl/inc/xmemory index c2f5bf6f866..a267c452c1c 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1555,7 +1555,7 @@ namespace ranges { return {_STD move(_IFirst), _STD move(_OFirst)}; } - template + template in_out_result<_InIt, _OutIt> _Copy_memcpy_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 From 9d840b6bde7d6a5c0d7accf4dbd4d28cfe8d793f Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 9 Jun 2021 19:37:15 -0700 Subject: [PATCH 12/12] Need concepts_latest_matrix.lst for views::take_while. --- tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/env.lst | 2 +- tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/env.lst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/env.lst b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/env.lst index d6d824b5879..18e2d7c71ec 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/env.lst +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\concepts_20_matrix.lst +RUNALL_INCLUDE ..\concepts_latest_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/env.lst b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/env.lst index d6d824b5879..18e2d7c71ec 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/env.lst +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\concepts_20_matrix.lst +RUNALL_INCLUDE ..\concepts_latest_matrix.lst