From e3ce51845b4a23297584583e01a8361852dd1735 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Mon, 16 Jun 2025 09:19:23 +0300 Subject: [PATCH 1/6] Restore wmemchr optimization --- stl/inc/xutility | 44 ++++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index dbfbad6ce35..03233783d89 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -6266,12 +6266,13 @@ 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 = {}) { - constexpr bool _Elements_are_1_byte = sizeof(_Iter_value_t<_It>) == 1; - constexpr bool _Is_sized = sized_sentinel_for<_Se, _It>; + constexpr bool _Elements_are_1_byte = sizeof(_Iter_value_t<_It>) == 1; + constexpr bool _Elements_are_2_bytes = sizeof(_Iter_value_t<_It>) == 2; + constexpr bool _Is_sized = sized_sentinel_for<_Se, _It>; if constexpr (_Vector_alg_in_find_is_safe<_It, _Ty> && (_Elements_are_1_byte ? _Is_sized || same_as<_Se, unreachable_sentinel_t> - : _Is_sized && _USE_STD_VECTOR_ALGORITHMS) + : _Is_sized && (_Elements_are_2_bytes || _USE_STD_VECTOR_ALGORITHMS)) && same_as<_Pj, identity>) { if (!_STD is_constant_evaluated()) { if (!_STD _Could_compare_equal_to_value_type<_It>(_Val)) { @@ -6295,23 +6296,30 @@ namespace ranges { } else #endif // ^^^ _USE_STD_VECTOR_ALGORITHMS ^^^ { - _STL_INTERNAL_STATIC_ASSERT(_Elements_are_1_byte); - size_t _Count; - if constexpr (_Is_sized) { - _Count = static_cast(_Last - _First); + if constexpr (_Elements_are_2_bytes) { + _STL_INTERNAL_STATIC_ASSERT(_Is_sized); + _Result = + _CSTD wmemchr(_First_ptr, static_cast(_Val), static_cast(_Last - _First)); } else { - _Count = SIZE_MAX; - } - - // C23 7.27.5.2 "The memchr generic function"/2 says "The implementation shall behave as if - // it reads the characters sequentially and stops as soon as a matching character is found." - // C23 7.32.4.6.9 "The wmemchr generic function"/2 lacks such wording, - // so we don't use wmemchr(), avoiding issues with unreachable_sentinel_t. - _Result = static_cast<_Ptr_t>(_CSTD memchr(_First_ptr, static_cast(_Val), _Count)); + _STL_INTERNAL_STATIC_ASSERT(_Elements_are_1_byte); + size_t _Count; + if constexpr (_Is_sized) { + _Count = static_cast(_Last - _First); + } else { + _Count = SIZE_MAX; + } - if constexpr (_Is_sized) { - if (_Result == nullptr) { - return _RANGES next(_STD move(_First), _Last); + // C23 7.27.5.2 "The memchr generic function"/2 says "The implementation shall behave as if + // it reads the characters sequentially and stops as soon as a matching character is found." + // C23 7.32.4.6.9 "The wmemchr generic function"/2 lacks such wording, + // so we don't use wmemchr(), avoiding issues with unreachable_sentinel_t. + _Result = + static_cast<_Ptr_t>(_CSTD memchr(_First_ptr, static_cast(_Val), _Count)); + + if constexpr (_Is_sized) { + if (_Result == nullptr) { + return _RANGES next(_STD move(_First), _Last); + } } } } From cf3a333265436cfee1a48db647458f7da3163ecd Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Tue, 1 Jul 2025 21:31:58 +0300 Subject: [PATCH 2/6] casts --- stl/inc/xutility | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 03233783d89..7befa48a22d 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -6298,8 +6298,9 @@ namespace ranges { { if constexpr (_Elements_are_2_bytes) { _STL_INTERNAL_STATIC_ASSERT(_Is_sized); - _Result = - _CSTD wmemchr(_First_ptr, static_cast(_Val), static_cast(_Last - _First)); + _Result = reinterpret_cast<_Ptr_t>( + const_cast(_CSTD wmemchr(reinterpret_cast(_First_ptr), + static_cast(_Val), static_cast(_Last - _First)))); } else { _STL_INTERNAL_STATIC_ASSERT(_Elements_are_1_byte); size_t _Count; From 3f1923267b7343aaa28a1a7624e77b5ee5de84a5 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Wed, 2 Jul 2025 09:35:59 +0300 Subject: [PATCH 3/6] fix nullptr --- stl/inc/xutility | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/stl/inc/xutility b/stl/inc/xutility index 7befa48a22d..7d76e64a9c3 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -6301,6 +6301,10 @@ namespace ranges { _Result = reinterpret_cast<_Ptr_t>( const_cast(_CSTD wmemchr(reinterpret_cast(_First_ptr), static_cast(_Val), static_cast(_Last - _First)))); + + if (_Result == nullptr) { + return _RANGES next(_STD move(_First), _Last); + } } else { _STL_INTERNAL_STATIC_ASSERT(_Elements_are_1_byte); size_t _Count; From 296b0e21975f5c5948424dc9703372a4116d5f25 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 10 Jul 2025 12:40:05 -0700 Subject: [PATCH 4/6] Refactor for clarity: 1 byte, 2 bytes, more bytes. --- stl/inc/xutility | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 7d76e64a9c3..42333d0b5c8 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -6270,10 +6270,10 @@ namespace ranges { constexpr bool _Elements_are_2_bytes = sizeof(_Iter_value_t<_It>) == 2; constexpr bool _Is_sized = sized_sentinel_for<_Se, _It>; - if constexpr (_Vector_alg_in_find_is_safe<_It, _Ty> - && (_Elements_are_1_byte ? _Is_sized || same_as<_Se, unreachable_sentinel_t> - : _Is_sized && (_Elements_are_2_bytes || _USE_STD_VECTOR_ALGORITHMS)) - && same_as<_Pj, identity>) { + if constexpr (_Vector_alg_in_find_is_safe<_It, _Ty> && same_as<_Pj, identity> + && (_Elements_are_1_byte ? _Is_sized || same_as<_Se, unreachable_sentinel_t> + : _Elements_are_2_bytes ? _Is_sized + : _Is_sized && _USE_STD_VECTOR_ALGORITHMS)) { if (!_STD is_constant_evaluated()) { if (!_STD _Could_compare_equal_to_value_type<_It>(_Val)) { if constexpr (_Is_sized) { From 69564439fab6f79b23e50840cd3b246958d4e080 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 10 Jul 2025 12:47:58 -0700 Subject: [PATCH 5/6] Update comment for memchr()/wmemchr(). --- stl/inc/xutility | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 42333d0b5c8..f25c86b7f1d 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -6290,7 +6290,7 @@ namespace ranges { _Ptr_t _Result; #if _USE_STD_VECTOR_ALGORITHMS if constexpr (_Is_sized) { - // When _Is_sized && _Elements_are_1_byte, prefer this over memchr() for performance + // Prefer this over memchr()/wmemchr() below for performance const auto _Last_ptr = _First_ptr + static_cast(_Last - _First); _Result = _STD _Find_vectorized(_First_ptr, _Last_ptr, _Val); } else From 1b0758ee2eb6257bb0020b364ad3f8601137b147 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 10 Jul 2025 12:56:00 -0700 Subject: [PATCH 6/6] Extract null handling. --- stl/inc/xutility | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index f25c86b7f1d..c38cab33263 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -6301,10 +6301,6 @@ namespace ranges { _Result = reinterpret_cast<_Ptr_t>( const_cast(_CSTD wmemchr(reinterpret_cast(_First_ptr), static_cast(_Val), static_cast(_Last - _First)))); - - if (_Result == nullptr) { - return _RANGES next(_STD move(_First), _Last); - } } else { _STL_INTERNAL_STATIC_ASSERT(_Elements_are_1_byte); size_t _Count; @@ -6320,11 +6316,11 @@ namespace ranges { // so we don't use wmemchr(), avoiding issues with unreachable_sentinel_t. _Result = static_cast<_Ptr_t>(_CSTD memchr(_First_ptr, static_cast(_Val), _Count)); + } - if constexpr (_Is_sized) { - if (_Result == nullptr) { - return _RANGES next(_STD move(_First), _Last); - } + if constexpr (_Is_sized) { + if (_Result == nullptr) { + return _RANGES next(_STD move(_First), _Last); } } }