From f85a9d01de4be76aed96beb184238e4b35e3b829 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 23 Jun 2024 11:18:51 +0300 Subject: [PATCH 01/26] benchmark basic_string::find_first_of --- benchmarks/src/find_first_of.cpp | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/benchmarks/src/find_first_of.cpp b/benchmarks/src/find_first_of.cpp index 05731a18938..6457e28424f 100644 --- a/benchmarks/src/find_first_of.cpp +++ b/benchmarks/src/find_first_of.cpp @@ -7,19 +7,25 @@ #include #include #include +#include +#include #include using namespace std; -template +enum class AlgType : bool { std, str_member }; + +template void bm(benchmark::State& state) { const size_t Pos = static_cast(state.range(0)); const size_t NSize = static_cast(state.range(1)); const size_t HSize = Pos * 2; const size_t Which = 0; - vector h(HSize, T{'.'}); - vector n(NSize); + using container = conditional_t, vector>; + + container h(HSize, T{'.'}); + container n(NSize, T{0}); iota(n.begin(), n.end(), T{'a'}); if (Pos >= HSize || Which >= NSize) { @@ -29,7 +35,13 @@ void bm(benchmark::State& state) { h[Pos] = n[Which]; for (auto _ : state) { - benchmark::DoNotOptimize(find_first_of(h.begin(), h.end(), n.begin(), n.end())); + benchmark::DoNotOptimize(h); + benchmark::DoNotOptimize(n); + if constexpr (Alg == AlgType::str_member) { + benchmark::DoNotOptimize(h.find_first_of(n.data(), n.size())); + } else { + benchmark::DoNotOptimize(find_first_of(h.begin(), h.end(), n.begin(), n.end())); + } } } @@ -38,9 +50,12 @@ void common_args(auto bm) { bm->Args({102, 4})->Args({325, 1})->Args({1011, 11})->Args({3056, 7}); } -BENCHMARK(bm)->Apply(common_args); -BENCHMARK(bm)->Apply(common_args); -BENCHMARK(bm)->Apply(common_args); -BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); + +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); BENCHMARK_MAIN(); From 20f9f873e15cc44523e17bb16d4604c895ec56cf Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 23 Jun 2024 11:19:51 +0300 Subject: [PATCH 02/26] move `_Find_first_of_vectorized` to `` --- stl/inc/algorithm | 33 --------------------------------- stl/inc/xutility | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 5510edb3d97..db35ebc6233 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -59,15 +59,6 @@ const void* __stdcall __std_find_last_trivial_2(const void* _First, const void* const void* __stdcall __std_find_last_trivial_4(const void* _First, const void* _Last, uint32_t _Val) noexcept; const void* __stdcall __std_find_last_trivial_8(const void* _First, const void* _Last, uint64_t _Val) noexcept; -const void* __stdcall __std_find_first_of_trivial_1( - const void* _First1, const void* _Last1, const void* _First2, const void* _Last2) noexcept; -const void* __stdcall __std_find_first_of_trivial_2( - const void* _First1, const void* _Last1, const void* _First2, const void* _Last2) noexcept; -const void* __stdcall __std_find_first_of_trivial_4( - const void* _First1, const void* _Last1, const void* _First2, const void* _Last2) noexcept; -const void* __stdcall __std_find_first_of_trivial_8( - const void* _First1, const void* _Last1, const void* _First2, const void* _Last2) noexcept; - __declspec(noalias) _Min_max_1i __stdcall __std_minmax_1i(const void* _First, const void* _Last) noexcept; __declspec(noalias) _Min_max_1u __stdcall __std_minmax_1u(const void* _First, const void* _Last) noexcept; __declspec(noalias) _Min_max_2i __stdcall __std_minmax_2i(const void* _First, const void* _Last) noexcept; @@ -198,27 +189,6 @@ _Ty* _Find_last_vectorized(_Ty* const _First, _Ty* const _Last, const _TVal _Val } } -template -_Ty1* _Find_first_of_vectorized( - _Ty1* const _First1, _Ty1* const _Last1, _Ty2* const _First2, _Ty2* const _Last2) noexcept { - _STL_INTERNAL_STATIC_ASSERT(sizeof(_Ty1) == sizeof(_Ty2)); - if constexpr (sizeof(_Ty1) == 1) { - return const_cast<_Ty1*>( - static_cast(::__std_find_first_of_trivial_1(_First1, _Last1, _First2, _Last2))); - } else if constexpr (sizeof(_Ty1) == 2) { - return const_cast<_Ty1*>( - static_cast(::__std_find_first_of_trivial_2(_First1, _Last1, _First2, _Last2))); - } else if constexpr (sizeof(_Ty1) == 4) { - return const_cast<_Ty1*>( - static_cast(::__std_find_first_of_trivial_4(_First1, _Last1, _First2, _Last2))); - } else if constexpr (sizeof(_Ty1) == 8) { - return const_cast<_Ty1*>( - static_cast(::__std_find_first_of_trivial_8(_First1, _Last1, _First2, _Last2))); - } else { - _STL_INTERNAL_STATIC_ASSERT(false); // unexpected size - } -} - template __declspec(noalias) void _Replace_vectorized( _Ty* const _First, _Ty* const _Last, const _TVal1 _Old_val, const _TVal2 _New_val) noexcept { @@ -237,9 +207,6 @@ __declspec(noalias) void _Replace_vectorized( } } -// find_first_of vectorization is likely to be a win after this size (in elements) -_INLINE_VAR constexpr ptrdiff_t _Threshold_find_first_of = 16; - // Can we activate the vector algorithms for find_first_of? template constexpr bool _Vector_alg_in_find_first_of_is_safe = _Equal_memcmp_is_safe<_It1, _It2, _Pr>; diff --git a/stl/inc/xutility b/stl/inc/xutility index ee83e903b9e..48ed7db05f0 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -90,6 +90,15 @@ const void* __stdcall __std_find_trivial_2(const void* _First, const void* _Last const void* __stdcall __std_find_trivial_4(const void* _First, const void* _Last, uint32_t _Val) noexcept; const void* __stdcall __std_find_trivial_8(const void* _First, const void* _Last, uint64_t _Val) noexcept; +const void* __stdcall __std_find_first_of_trivial_1( + const void* _First1, const void* _Last1, const void* _First2, const void* _Last2) noexcept; +const void* __stdcall __std_find_first_of_trivial_2( + const void* _First1, const void* _Last1, const void* _First2, const void* _Last2) noexcept; +const void* __stdcall __std_find_first_of_trivial_4( + const void* _First1, const void* _Last1, const void* _First2, const void* _Last2) noexcept; +const void* __stdcall __std_find_first_of_trivial_8( + const void* _First1, const void* _Last1, const void* _First2, const void* _Last2) noexcept; + const void* __stdcall __std_min_element_1(const void* _First, const void* _Last, bool _Signed) noexcept; const void* __stdcall __std_min_element_2(const void* _First, const void* _Last, bool _Signed) noexcept; const void* __stdcall __std_min_element_4(const void* _First, const void* _Last, bool _Signed) noexcept; @@ -195,6 +204,30 @@ _Ty* _Find_vectorized(_Ty* const _First, _Ty* const _Last, const _TVal _Val) noe } } +// find_first_of vectorization is likely to be a win after this size (in elements) +_INLINE_VAR constexpr ptrdiff_t _Threshold_find_first_of = 16; + +template +_Ty1* _Find_first_of_vectorized( + _Ty1* const _First1, _Ty1* const _Last1, _Ty2* const _First2, _Ty2* const _Last2) noexcept { + _STL_INTERNAL_STATIC_ASSERT(sizeof(_Ty1) == sizeof(_Ty2)); + if constexpr (sizeof(_Ty1) == 1) { + return const_cast<_Ty1*>( + static_cast(::__std_find_first_of_trivial_1(_First1, _Last1, _First2, _Last2))); + } else if constexpr (sizeof(_Ty1) == 2) { + return const_cast<_Ty1*>( + static_cast(::__std_find_first_of_trivial_2(_First1, _Last1, _First2, _Last2))); + } else if constexpr (sizeof(_Ty1) == 4) { + return const_cast<_Ty1*>( + static_cast(::__std_find_first_of_trivial_4(_First1, _Last1, _First2, _Last2))); + } else if constexpr (sizeof(_Ty1) == 8) { + return const_cast<_Ty1*>( + static_cast(::__std_find_first_of_trivial_8(_First1, _Last1, _First2, _Last2))); + } else { + _STL_INTERNAL_STATIC_ASSERT(false); // unexpected size + } +} + template _Ty* _Min_element_vectorized(_Ty* const _First, _Ty* const _Last) noexcept { constexpr bool _Signed = is_signed_v<_Ty>; From 3ba668a2b6f4d1ddaa924328b69aa869a98d70f8 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 23 Jun 2024 11:20:42 +0300 Subject: [PATCH 03/26] attach the optimization --- stl/inc/__msvc_string_view.hpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/stl/inc/__msvc_string_view.hpp b/stl/inc/__msvc_string_view.hpp index 52daaedbaf5..11449991914 100644 --- a/stl/inc/__msvc_string_view.hpp +++ b/stl/inc/__msvc_string_view.hpp @@ -695,6 +695,18 @@ constexpr size_t _Traits_find_first_of(_In_reads_(_Hay_size) const _Traits_ptr_t // in [_Haystack, _Haystack + _Hay_size), look for one of [_Needle, _Needle + _Needle_size), at/after _Start_at if (_Needle_size != 0 && _Start_at < _Hay_size) { // room for match, look for it if constexpr (_Special) { +#if _USE_STD_VECTOR_ALGORITHMS + if (!_STD _Is_constant_evaluated() && _Hay_size - _Start_at > _Threshold_find_first_of) { + const _Traits_ptr_t<_Traits> _Found = _STD _Find_first_of_vectorized( + _Haystack + _Start_at, _Haystack + _Hay_size, _Needle, _Needle + _Needle_size); + + if (_Found != _Haystack + _Hay_size) { + return _Found - _Haystack; + } else { + return static_cast(-1); // no match + } + } +#endif // _USE_STD_VECTOR_ALGORITHMS _String_bitmap _Matches; if (!_Matches._Mark(_Needle, _Needle + _Needle_size)) { // couldn't put one of the characters into the // bitmap, fall back to the serial algorithm From 7a5a7bff72b100bd253afc3ed5f2a6284c859e6f Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 23 Jun 2024 11:48:02 +0300 Subject: [PATCH 04/26] unsigned --- stl/inc/__msvc_string_view.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/__msvc_string_view.hpp b/stl/inc/__msvc_string_view.hpp index 11449991914..33aceb7a40d 100644 --- a/stl/inc/__msvc_string_view.hpp +++ b/stl/inc/__msvc_string_view.hpp @@ -701,7 +701,7 @@ constexpr size_t _Traits_find_first_of(_In_reads_(_Hay_size) const _Traits_ptr_t _Haystack + _Start_at, _Haystack + _Hay_size, _Needle, _Needle + _Needle_size); if (_Found != _Haystack + _Hay_size) { - return _Found - _Haystack; + return static_cast(_Found - _Haystack); } else { return static_cast(-1); // no match } From 72d3d2227add0f7c0e9e049abb3b108dafc49c8f Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 23 Jun 2024 13:13:42 +0300 Subject: [PATCH 05/26] benchmark out-of-table case --- benchmarks/src/find_first_of.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/benchmarks/src/find_first_of.cpp b/benchmarks/src/find_first_of.cpp index 6457e28424f..d08b5cf7cf7 100644 --- a/benchmarks/src/find_first_of.cpp +++ b/benchmarks/src/find_first_of.cpp @@ -15,7 +15,7 @@ using namespace std; enum class AlgType : bool { std, str_member }; -template +template void bm(benchmark::State& state) { const size_t Pos = static_cast(state.range(0)); const size_t NSize = static_cast(state.range(1)); @@ -26,7 +26,7 @@ void bm(benchmark::State& state) { container h(HSize, T{'.'}); container n(NSize, T{0}); - iota(n.begin(), n.end(), T{'a'}); + iota(n.begin(), n.end(), Start); if (Pos >= HSize || Which >= NSize) { abort(); @@ -47,7 +47,7 @@ void bm(benchmark::State& state) { void common_args(auto bm) { bm->Args({2, 3})->Args({7, 4})->Args({9, 3})->Args({22, 5})->Args({58, 2}); - bm->Args({102, 4})->Args({325, 1})->Args({1011, 11})->Args({3056, 7}); + bm->Args({102, 4})->Args({325, 1})->Args({1011, 11})->Args({1502, 23})->Args({3056, 7}); } BENCHMARK(bm)->Apply(common_args); @@ -57,5 +57,6 @@ BENCHMARK(bm)->Apply(common_args); BENCHMARK(bm)->Apply(common_args); BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); BENCHMARK_MAIN(); From 2608a58d52c69d039b264280ede3c12aa77bba14 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 23 Jun 2024 13:14:48 +0300 Subject: [PATCH 06/26] Vectorize large char type only for small needle --- stl/inc/__msvc_string_view.hpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/stl/inc/__msvc_string_view.hpp b/stl/inc/__msvc_string_view.hpp index 33aceb7a40d..66f8bf49a4d 100644 --- a/stl/inc/__msvc_string_view.hpp +++ b/stl/inc/__msvc_string_view.hpp @@ -696,7 +696,11 @@ constexpr size_t _Traits_find_first_of(_In_reads_(_Hay_size) const _Traits_ptr_t if (_Needle_size != 0 && _Start_at < _Hay_size) { // room for match, look for it if constexpr (_Special) { #if _USE_STD_VECTOR_ALGORITHMS - if (!_STD _Is_constant_evaluated() && _Hay_size - _Start_at > _Threshold_find_first_of) { + bool _Try_vectorize = !_STD _Is_constant_evaluated() && _Hay_size - _Start_at > _Threshold_find_first_of; + constexpr size_t _Elem_size = sizeof(*_Haystack); + + // Additional condition for the case where the table lookup outperforms the vectorization + if (_Try_vectorize && (_Elem_size == 1 || _Elem_size * _Needle_size <= 16)) { const _Traits_ptr_t<_Traits> _Found = _STD _Find_first_of_vectorized( _Haystack + _Start_at, _Haystack + _Hay_size, _Needle, _Needle + _Needle_size); @@ -710,6 +714,19 @@ constexpr size_t _Traits_find_first_of(_In_reads_(_Hay_size) const _Traits_ptr_t _String_bitmap _Matches; if (!_Matches._Mark(_Needle, _Needle + _Needle_size)) { // couldn't put one of the characters into the // bitmap, fall back to the serial algorithm +#if _USE_STD_VECTOR_ALGORITHMS + if (_Try_vectorize) { + const _Traits_ptr_t<_Traits> _Found = _STD _Find_first_of_vectorized( + _Haystack + _Start_at, _Haystack + _Hay_size, _Needle, _Needle + _Needle_size); + + if (_Found != _Haystack + _Hay_size) { + return static_cast(_Found - _Haystack); + } else { + return static_cast(-1); // no match + } + } +#endif // _USE_STD_VECTOR_ALGORITHMS + return _Traits_find_first_of<_Traits, false>(_Haystack, _Hay_size, _Start_at, _Needle, _Needle_size); } From 22b3494378d04e40498cd2f25907684c95fbe273 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 23 Jun 2024 16:06:27 +0300 Subject: [PATCH 07/26] coverage --- .../VSO_0000000_vector_algorithms/test.cpp | 70 +++++++++++++++++-- 1 file changed, 64 insertions(+), 6 deletions(-) diff --git a/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp b/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp index 5a7a1520412..e292b36235b 100644 --- a/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp +++ b/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp @@ -286,11 +286,12 @@ void test_case_find_first_of(const vector& input_haystack, const vector& i #endif // _HAS_CXX20 } +constexpr size_t haystackDataCount = 200; +constexpr size_t needleDataCount = 35; + template void test_find_first_of(mt19937_64& gen) { - constexpr size_t haystackDataCount = 200; - constexpr size_t needleDataCount = 35; - using TD = conditional_t; + using TD = conditional_t; uniform_int_distribution dis('a', 'z'); vector input_haystack; vector input_needle; @@ -350,9 +351,7 @@ void test_case_search(const vector& input_haystack, const vector& input_ne template void test_search(mt19937_64& gen) { - constexpr size_t haystackDataCount = 200; - constexpr size_t needleDataCount = 35; - using TD = conditional_t; + using TD = conditional_t; uniform_int_distribution dis('0', '9'); vector input_haystack; vector input_needle; @@ -1093,6 +1092,61 @@ void test_bitset(mt19937_64& gen) { test_randomized_bitset_base_count<512 - 5, 32 + 10>(gen); } +template +void test_case_string_find_first_of(const basic_string& input_haystack, const basic_string& input_needle) { + auto expected_ptr = last_known_good_find_first_of( + input_haystack.begin(), input_haystack.end(), input_needle.begin(), input_needle.end()); + auto expected = (expected_ptr != input_haystack.end()) ? expected_ptr - input_haystack.begin() : ptrdiff_t{-1}; + auto actual = static_cast(input_haystack.find_first_of(input_needle.data(), 0, input_needle.size())); + assert(expected == actual); +} + +template +void test_basic_string_dis(mt19937_64& gen, D& dis) { + basic_string input_haystack; + basic_string input_needle; + input_haystack.reserve(haystackDataCount); + input_needle.reserve(needleDataCount); + + for (;;) { + input_needle.clear(); + + test_case_string_find_first_of(input_haystack, input_needle); + for (size_t attempts = 0; attempts < needleDataCount; ++attempts) { + input_needle.push_back(static_cast(dis(gen))); + test_case_string_find_first_of(input_haystack, input_needle); + } + + if (input_haystack.size() == haystackDataCount) { + break; + } + + input_haystack.push_back(static_cast(dis(gen))); + } +} + +template +void test_basic_string(mt19937_64& gen) { + using dis_int_type = conditional_t, int32_t, uint32_t>; + + uniform_int_distribution dis_latin('a', 'z'); + test_basic_string_dis(gen, dis_latin); + if constexpr (sizeof(T) >= 2) { + uniform_int_distribution dis_greek(0x0391, 0x003C9); + test_basic_string_dis(gen, dis_greek); + } +} + +void test_string(mt19937_64& gen) { + test_basic_string(gen); + test_basic_string(gen); +#ifdef __cpp_lib_char8_t + test_basic_string(gen); +#endif // __cpp_lib_char8_t + test_basic_string(gen); + test_basic_string(gen); +} + void test_various_containers() { test_one_container>(); // contiguous, vectorizable test_one_container>(); // random-access, not vectorizable @@ -1158,6 +1212,7 @@ static_assert(test_constexpr()); #endif // _HAS_CXX20 int main() { + _set_abort_behavior(_CALL_REPORTFAULT, _CALL_REPORTFAULT); #if _HAS_CXX20 assert(test_constexpr()); #endif // _HAS_CXX20 @@ -1168,17 +1223,20 @@ int main() { test_vector_algorithms(gen); test_various_containers(); test_bitset(gen); + test_string(gen); #ifndef _M_CEE_PURE #if defined(_M_IX86) || defined(_M_X64) disable_instructions(__ISA_AVAILABLE_AVX2); test_vector_algorithms(gen); test_various_containers(); test_bitset(gen); + test_string(gen); disable_instructions(__ISA_AVAILABLE_SSE42); test_vector_algorithms(gen); test_various_containers(); test_bitset(gen); + test_string(gen); #endif // defined(_M_IX86) || defined(_M_X64) #endif // _M_CEE_PURE } From 6928323b81be7301b077d20917560a3daf17741b Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 23 Jun 2024 16:12:26 +0300 Subject: [PATCH 08/26] fix benchmark bug --- benchmarks/src/find_first_of.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/src/find_first_of.cpp b/benchmarks/src/find_first_of.cpp index d08b5cf7cf7..514c1959b83 100644 --- a/benchmarks/src/find_first_of.cpp +++ b/benchmarks/src/find_first_of.cpp @@ -38,7 +38,7 @@ void bm(benchmark::State& state) { benchmark::DoNotOptimize(h); benchmark::DoNotOptimize(n); if constexpr (Alg == AlgType::str_member) { - benchmark::DoNotOptimize(h.find_first_of(n.data(), n.size())); + benchmark::DoNotOptimize(h.find_first_of(n.data(), 0, n.size())); } else { benchmark::DoNotOptimize(find_first_of(h.begin(), h.end(), n.begin(), n.end())); } From cd2ce427fe4c6b69de5d7c5c2716815bfd57c888 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 23 Jun 2024 22:35:43 +0300 Subject: [PATCH 09/26] stray --- tests/std/tests/VSO_0000000_vector_algorithms/test.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp b/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp index e292b36235b..a800a170cef 100644 --- a/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp +++ b/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp @@ -1212,7 +1212,6 @@ static_assert(test_constexpr()); #endif // _HAS_CXX20 int main() { - _set_abort_behavior(_CALL_REPORTFAULT, _CALL_REPORTFAULT); #if _HAS_CXX20 assert(test_constexpr()); #endif // _HAS_CXX20 From c477fbb8fa106217e7fd54cb6c16f9362ad32b4a Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 25 Aug 2024 23:21:41 +0300 Subject: [PATCH 10/26] add `if constexpr` warning suppression --- tests/std/tests/VSO_0000000_vector_algorithms/test.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp b/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp index b2bd6531128..b6b56d5a2ba 100644 --- a/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp +++ b/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp @@ -28,6 +28,11 @@ using namespace std; +#pragma warning(disable : 4984) // 'if constexpr' is a C++17 language extension +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wc++17-extensions" // constexpr if is a C++17 extension +#endif // __clang__ + template ptrdiff_t last_known_good_count(FwdIt first, FwdIt last, T v) { ptrdiff_t result = 0; From ff285ad21d8748283825f7e4095ee50c62a79cdf Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Aug 2024 13:01:22 -0700 Subject: [PATCH 11/26] Step 1: Copy the "return no match" upwards. We were falling through to this. --- stl/inc/__msvc_string_view.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/stl/inc/__msvc_string_view.hpp b/stl/inc/__msvc_string_view.hpp index cf393dfa4e8..934b0438b67 100644 --- a/stl/inc/__msvc_string_view.hpp +++ b/stl/inc/__msvc_string_view.hpp @@ -750,6 +750,7 @@ constexpr size_t _Traits_find_first_of(_In_reads_(_Hay_size) const _Traits_ptr_t return static_cast(_Match_try - _Haystack); // found a match } } + return static_cast(-1); // no match } else { const auto _End = _Haystack + _Hay_size; for (auto _Match_try = _Haystack + _Start_at; _Match_try < _End; ++_Match_try) { From 2cf1f277d838c95a3e710f0837ca4a59a634d9f6 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Aug 2024 13:12:18 -0700 Subject: [PATCH 12/26] Step 2: Flip `_Matches._Mark` control flow. Now that the "use the bitmap" and "couldn't use the bitmap" codepaths always return, we can positively test for "use the bitmap". This is a clarity improvement all by itself - it's easier to understand "if we can do cool thing, do it". --- stl/inc/__msvc_string_view.hpp | 39 +++++++++++++++++----------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/stl/inc/__msvc_string_view.hpp b/stl/inc/__msvc_string_view.hpp index 934b0438b67..52bc766a10d 100644 --- a/stl/inc/__msvc_string_view.hpp +++ b/stl/inc/__msvc_string_view.hpp @@ -726,31 +726,32 @@ constexpr size_t _Traits_find_first_of(_In_reads_(_Hay_size) const _Traits_ptr_t } #endif // _USE_STD_VECTOR_ALGORITHMS _String_bitmap _Matches; - if (!_Matches._Mark(_Needle, _Needle + _Needle_size)) { // couldn't put one of the characters into the - // bitmap, fall back to the serial algorithm -#if _USE_STD_VECTOR_ALGORITHMS - if (_Try_vectorize) { - const _Traits_ptr_t<_Traits> _Found = _STD _Find_first_of_vectorized( - _Haystack + _Start_at, _Haystack + _Hay_size, _Needle, _Needle + _Needle_size); - - if (_Found != _Haystack + _Hay_size) { - return static_cast(_Found - _Haystack); - } else { - return static_cast(-1); // no match + if (_Matches._Mark(_Needle, _Needle + _Needle_size)) { + const auto _End = _Haystack + _Hay_size; + for (auto _Match_try = _Haystack + _Start_at; _Match_try < _End; ++_Match_try) { + if (_Matches._Match(*_Match_try)) { + return static_cast(_Match_try - _Haystack); // found a match } } -#endif // _USE_STD_VECTOR_ALGORITHMS - - return _Traits_find_first_of<_Traits, false>(_Haystack, _Hay_size, _Start_at, _Needle, _Needle_size); + return static_cast(-1); // no match } - const auto _End = _Haystack + _Hay_size; - for (auto _Match_try = _Haystack + _Start_at; _Match_try < _End; ++_Match_try) { - if (_Matches._Match(*_Match_try)) { - return static_cast(_Match_try - _Haystack); // found a match + // couldn't put one of the characters into the bitmap, fall back to the serial algorithm + +#if _USE_STD_VECTOR_ALGORITHMS + if (_Try_vectorize) { + const _Traits_ptr_t<_Traits> _Found = _STD _Find_first_of_vectorized( + _Haystack + _Start_at, _Haystack + _Hay_size, _Needle, _Needle + _Needle_size); + + if (_Found != _Haystack + _Hay_size) { + return static_cast(_Found - _Haystack); + } else { + return static_cast(-1); // no match } } - return static_cast(-1); // no match +#endif // _USE_STD_VECTOR_ALGORITHMS + + return _Traits_find_first_of<_Traits, false>(_Haystack, _Hay_size, _Start_at, _Needle, _Needle_size); } else { const auto _End = _Haystack + _Hay_size; for (auto _Match_try = _Haystack + _Start_at; _Match_try < _End; ++_Match_try) { From ac5a88e645831691543f026e5716955ea00a3781 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Aug 2024 13:54:04 -0700 Subject: [PATCH 13/26] Step 3: `_Use_bitmap` avoids code duplication. The assignment `_Use_bitmap = false;` is guarded by `_Try_vectorize && (STUFF)`. So when we skip using the bitmap, the later condition `if (_Try_vectorize)` is guaranteed to be active. --- stl/inc/__msvc_string_view.hpp | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/stl/inc/__msvc_string_view.hpp b/stl/inc/__msvc_string_view.hpp index 52bc766a10d..1bcbfba60e3 100644 --- a/stl/inc/__msvc_string_view.hpp +++ b/stl/inc/__msvc_string_view.hpp @@ -709,34 +709,33 @@ constexpr size_t _Traits_find_first_of(_In_reads_(_Hay_size) const _Traits_ptr_t // in [_Haystack, _Haystack + _Hay_size), look for one of [_Needle, _Needle + _Needle_size), at/after _Start_at if (_Needle_size != 0 && _Start_at < _Hay_size) { // room for match, look for it if constexpr (_Special) { + bool _Use_bitmap = true; + #if _USE_STD_VECTOR_ALGORITHMS bool _Try_vectorize = !_STD _Is_constant_evaluated() && _Hay_size - _Start_at > _Threshold_find_first_of; constexpr size_t _Elem_size = sizeof(*_Haystack); // Additional condition for the case where the table lookup outperforms the vectorization if (_Try_vectorize && (_Elem_size == 1 || _Elem_size * _Needle_size <= 16)) { - const _Traits_ptr_t<_Traits> _Found = _STD _Find_first_of_vectorized( - _Haystack + _Start_at, _Haystack + _Hay_size, _Needle, _Needle + _Needle_size); - - if (_Found != _Haystack + _Hay_size) { - return static_cast(_Found - _Haystack); - } else { - return static_cast(-1); // no match - } + _Use_bitmap = false; } #endif // _USE_STD_VECTOR_ALGORITHMS - _String_bitmap _Matches; - if (_Matches._Mark(_Needle, _Needle + _Needle_size)) { - const auto _End = _Haystack + _Hay_size; - for (auto _Match_try = _Haystack + _Start_at; _Match_try < _End; ++_Match_try) { - if (_Matches._Match(*_Match_try)) { - return static_cast(_Match_try - _Haystack); // found a match + + if (_Use_bitmap) { + _String_bitmap _Matches; + + if (_Matches._Mark(_Needle, _Needle + _Needle_size)) { + const auto _End = _Haystack + _Hay_size; + for (auto _Match_try = _Haystack + _Start_at; _Match_try < _End; ++_Match_try) { + if (_Matches._Match(*_Match_try)) { + return static_cast(_Match_try - _Haystack); // found a match + } } + return static_cast(-1); // no match } - return static_cast(-1); // no match - } - // couldn't put one of the characters into the bitmap, fall back to the serial algorithm + // couldn't put one of the characters into the bitmap, fall back to the serial algorithm + } #if _USE_STD_VECTOR_ALGORITHMS if (_Try_vectorize) { From e6b015d35c18b300bea000cd25edf988ba213c51 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Aug 2024 14:10:48 -0700 Subject: [PATCH 14/26] Extract `_Elem` instead of `_Elem_size`. And silence warning C4127: conditional expression is constant. --- stl/inc/__msvc_string_view.hpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/stl/inc/__msvc_string_view.hpp b/stl/inc/__msvc_string_view.hpp index 1bcbfba60e3..cee41be4ce7 100644 --- a/stl/inc/__msvc_string_view.hpp +++ b/stl/inc/__msvc_string_view.hpp @@ -709,20 +709,24 @@ constexpr size_t _Traits_find_first_of(_In_reads_(_Hay_size) const _Traits_ptr_t // in [_Haystack, _Haystack + _Hay_size), look for one of [_Needle, _Needle + _Needle_size), at/after _Start_at if (_Needle_size != 0 && _Start_at < _Hay_size) { // room for match, look for it if constexpr (_Special) { + using _Elem = typename _Traits::char_type; + bool _Use_bitmap = true; #if _USE_STD_VECTOR_ALGORITHMS bool _Try_vectorize = !_STD _Is_constant_evaluated() && _Hay_size - _Start_at > _Threshold_find_first_of; - constexpr size_t _Elem_size = sizeof(*_Haystack); +#pragma warning(push) +#pragma warning(disable : 4127) // conditional expression is constant // Additional condition for the case where the table lookup outperforms the vectorization - if (_Try_vectorize && (_Elem_size == 1 || _Elem_size * _Needle_size <= 16)) { + if (_Try_vectorize && (sizeof(_Elem) == 1 || sizeof(_Elem) * _Needle_size <= 16)) { _Use_bitmap = false; } +#pragma warning(pop) #endif // _USE_STD_VECTOR_ALGORITHMS if (_Use_bitmap) { - _String_bitmap _Matches; + _String_bitmap<_Elem> _Matches; if (_Matches._Mark(_Needle, _Needle + _Needle_size)) { const auto _End = _Haystack + _Hay_size; From 849092d2a0082ad44a5241ee235162e844532dbc Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Aug 2024 14:26:01 -0700 Subject: [PATCH 15/26] Fall through to "not special" instead of calling self with `_Special = false`. --- stl/inc/__msvc_string_view.hpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/stl/inc/__msvc_string_view.hpp b/stl/inc/__msvc_string_view.hpp index cee41be4ce7..e3d5b781aee 100644 --- a/stl/inc/__msvc_string_view.hpp +++ b/stl/inc/__msvc_string_view.hpp @@ -753,14 +753,12 @@ constexpr size_t _Traits_find_first_of(_In_reads_(_Hay_size) const _Traits_ptr_t } } #endif // _USE_STD_VECTOR_ALGORITHMS + } - return _Traits_find_first_of<_Traits, false>(_Haystack, _Hay_size, _Start_at, _Needle, _Needle_size); - } else { - const auto _End = _Haystack + _Hay_size; - for (auto _Match_try = _Haystack + _Start_at; _Match_try < _End; ++_Match_try) { - if (_Traits::find(_Needle, _Needle_size, *_Match_try)) { - return static_cast(_Match_try - _Haystack); // found a match - } + const auto _End = _Haystack + _Hay_size; + for (auto _Match_try = _Haystack + _Start_at; _Match_try < _End; ++_Match_try) { + if (_Traits::find(_Needle, _Needle_size, *_Match_try)) { + return static_cast(_Match_try - _Haystack); // found a match } } } From 5dfadec038fc5c3ca1908ab470cc18d46139e81f Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Aug 2024 15:14:52 -0700 Subject: [PATCH 16/26] Extract `_Hay_start`, `_Hay_end`. --- stl/inc/__msvc_string_view.hpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/stl/inc/__msvc_string_view.hpp b/stl/inc/__msvc_string_view.hpp index e3d5b781aee..41f0752f734 100644 --- a/stl/inc/__msvc_string_view.hpp +++ b/stl/inc/__msvc_string_view.hpp @@ -708,6 +708,9 @@ constexpr size_t _Traits_find_first_of(_In_reads_(_Hay_size) const _Traits_ptr_t const size_t _Needle_size) noexcept { // in [_Haystack, _Haystack + _Hay_size), look for one of [_Needle, _Needle + _Needle_size), at/after _Start_at if (_Needle_size != 0 && _Start_at < _Hay_size) { // room for match, look for it + const auto _Hay_start = _Haystack + _Start_at; + const auto _Hay_end = _Haystack + _Hay_size; + if constexpr (_Special) { using _Elem = typename _Traits::char_type; @@ -729,8 +732,7 @@ constexpr size_t _Traits_find_first_of(_In_reads_(_Hay_size) const _Traits_ptr_t _String_bitmap<_Elem> _Matches; if (_Matches._Mark(_Needle, _Needle + _Needle_size)) { - const auto _End = _Haystack + _Hay_size; - for (auto _Match_try = _Haystack + _Start_at; _Match_try < _End; ++_Match_try) { + for (auto _Match_try = _Hay_start; _Match_try < _Hay_end; ++_Match_try) { if (_Matches._Match(*_Match_try)) { return static_cast(_Match_try - _Haystack); // found a match } @@ -743,10 +745,10 @@ constexpr size_t _Traits_find_first_of(_In_reads_(_Hay_size) const _Traits_ptr_t #if _USE_STD_VECTOR_ALGORITHMS if (_Try_vectorize) { - const _Traits_ptr_t<_Traits> _Found = _STD _Find_first_of_vectorized( - _Haystack + _Start_at, _Haystack + _Hay_size, _Needle, _Needle + _Needle_size); + const _Traits_ptr_t<_Traits> _Found = + _STD _Find_first_of_vectorized(_Hay_start, _Hay_end, _Needle, _Needle + _Needle_size); - if (_Found != _Haystack + _Hay_size) { + if (_Found != _Hay_end) { return static_cast(_Found - _Haystack); } else { return static_cast(-1); // no match @@ -755,8 +757,7 @@ constexpr size_t _Traits_find_first_of(_In_reads_(_Hay_size) const _Traits_ptr_t #endif // _USE_STD_VECTOR_ALGORITHMS } - const auto _End = _Haystack + _Hay_size; - for (auto _Match_try = _Haystack + _Start_at; _Match_try < _End; ++_Match_try) { + for (auto _Match_try = _Hay_start; _Match_try < _Hay_end; ++_Match_try) { if (_Traits::find(_Needle, _Needle_size, *_Match_try)) { return static_cast(_Match_try - _Haystack); // found a match } From 82ffddf962b2ec1cdac1402f3d502f0dd53abc97 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Aug 2024 14:35:33 -0700 Subject: [PATCH 17/26] Comment: Mention "vectorized or serial" fallbacks. --- stl/inc/__msvc_string_view.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/__msvc_string_view.hpp b/stl/inc/__msvc_string_view.hpp index 41f0752f734..c9bc501cacb 100644 --- a/stl/inc/__msvc_string_view.hpp +++ b/stl/inc/__msvc_string_view.hpp @@ -740,7 +740,7 @@ constexpr size_t _Traits_find_first_of(_In_reads_(_Hay_size) const _Traits_ptr_t return static_cast(-1); // no match } - // couldn't put one of the characters into the bitmap, fall back to the serial algorithm + // couldn't put one of the characters into the bitmap, fall back to the vectorized or serial algorithms } #if _USE_STD_VECTOR_ALGORITHMS From 44e8f8c169a972b5b6fb08e927dfb8ec05c30638 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Aug 2024 14:56:34 -0700 Subject: [PATCH 18/26] Comment: Reverse to "vectorization outperforms" (and slightly reduce verbosity). --- stl/inc/__msvc_string_view.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/__msvc_string_view.hpp b/stl/inc/__msvc_string_view.hpp index c9bc501cacb..735f9614c1d 100644 --- a/stl/inc/__msvc_string_view.hpp +++ b/stl/inc/__msvc_string_view.hpp @@ -721,7 +721,7 @@ constexpr size_t _Traits_find_first_of(_In_reads_(_Hay_size) const _Traits_ptr_t #pragma warning(push) #pragma warning(disable : 4127) // conditional expression is constant - // Additional condition for the case where the table lookup outperforms the vectorization + // Additional condition for when the vectorization outperforms the table lookup if (_Try_vectorize && (sizeof(_Elem) == 1 || sizeof(_Elem) * _Needle_size <= 16)) { _Use_bitmap = false; } From 757d784bf9c9fd4a4fa4ffa5148b8dda466bb408 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Aug 2024 15:25:49 -0700 Subject: [PATCH 19/26] Comment: Add "found a match". --- stl/inc/__msvc_string_view.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/__msvc_string_view.hpp b/stl/inc/__msvc_string_view.hpp index 735f9614c1d..ffe4ed328b8 100644 --- a/stl/inc/__msvc_string_view.hpp +++ b/stl/inc/__msvc_string_view.hpp @@ -749,7 +749,7 @@ constexpr size_t _Traits_find_first_of(_In_reads_(_Hay_size) const _Traits_ptr_t _STD _Find_first_of_vectorized(_Hay_start, _Hay_end, _Needle, _Needle + _Needle_size); if (_Found != _Hay_end) { - return static_cast(_Found - _Haystack); + return static_cast(_Found - _Haystack); // found a match } else { return static_cast(-1); // no match } From 04d95f2472cdfd96228c7cc30afc89ed8aa57bc3 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Aug 2024 15:34:34 -0700 Subject: [PATCH 20/26] Benchmark: `AlgType::std` => `AlgType::std_func` --- benchmarks/src/find_first_of.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/benchmarks/src/find_first_of.cpp b/benchmarks/src/find_first_of.cpp index 514c1959b83..19ee1a340fc 100644 --- a/benchmarks/src/find_first_of.cpp +++ b/benchmarks/src/find_first_of.cpp @@ -13,7 +13,7 @@ using namespace std; -enum class AlgType : bool { std, str_member }; +enum class AlgType : bool { std_func, str_member }; template void bm(benchmark::State& state) { @@ -50,10 +50,10 @@ void common_args(auto bm) { bm->Args({102, 4})->Args({325, 1})->Args({1011, 11})->Args({1502, 23})->Args({3056, 7}); } -BENCHMARK(bm)->Apply(common_args); -BENCHMARK(bm)->Apply(common_args); -BENCHMARK(bm)->Apply(common_args); -BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); BENCHMARK(bm)->Apply(common_args); BENCHMARK(bm)->Apply(common_args); From c8f93e7cf32b615178268a09ba6b4c04265e9b4d Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Aug 2024 15:43:57 -0700 Subject: [PATCH 21/26] Test: `expected_ptr` => `expected_iter` --- tests/std/tests/VSO_0000000_vector_algorithms/test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp b/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp index b6b56d5a2ba..88d8098cf23 100644 --- a/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp +++ b/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp @@ -1030,9 +1030,9 @@ void test_bitset(mt19937_64& gen) { template void test_case_string_find_first_of(const basic_string& input_haystack, const basic_string& input_needle) { - auto expected_ptr = last_known_good_find_first_of( + auto expected_iter = last_known_good_find_first_of( input_haystack.begin(), input_haystack.end(), input_needle.begin(), input_needle.end()); - auto expected = (expected_ptr != input_haystack.end()) ? expected_ptr - input_haystack.begin() : ptrdiff_t{-1}; + auto expected = (expected_iter != input_haystack.end()) ? expected_iter - input_haystack.begin() : ptrdiff_t{-1}; auto actual = static_cast(input_haystack.find_first_of(input_needle.data(), 0, input_needle.size())); assert(expected == actual); } From ef2ed39260767c6c3c739b29f377a19eb08570b0 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Aug 2024 15:52:12 -0700 Subject: [PATCH 22/26] Test: Drop leading zero hexits. --- tests/std/tests/VSO_0000000_vector_algorithms/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp b/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp index 88d8098cf23..a09ed25c352 100644 --- a/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp +++ b/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp @@ -1068,7 +1068,7 @@ void test_basic_string(mt19937_64& gen) { uniform_int_distribution dis_latin('a', 'z'); test_basic_string_dis(gen, dis_latin); if constexpr (sizeof(T) >= 2) { - uniform_int_distribution dis_greek(0x0391, 0x003C9); + uniform_int_distribution dis_greek(0x391, 0x3C9); test_basic_string_dis(gen, dis_greek); } } From 8da299b16578ad30d8384020ed349c4f77237e66 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Aug 2024 20:01:55 -0700 Subject: [PATCH 23/26] Lift out the `_Is_constant_evaluated()` check. I'm giving up the "bitmap" optimization for constexpr evaluation. Now we can mark `const bool _Try_vectorize` without harming perf. --- stl/inc/__msvc_string_view.hpp | 54 ++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/stl/inc/__msvc_string_view.hpp b/stl/inc/__msvc_string_view.hpp index ffe4ed328b8..8480b0dc744 100644 --- a/stl/inc/__msvc_string_view.hpp +++ b/stl/inc/__msvc_string_view.hpp @@ -712,49 +712,51 @@ constexpr size_t _Traits_find_first_of(_In_reads_(_Hay_size) const _Traits_ptr_t const auto _Hay_end = _Haystack + _Hay_size; if constexpr (_Special) { - using _Elem = typename _Traits::char_type; + if (!_STD _Is_constant_evaluated()) { + using _Elem = typename _Traits::char_type; - bool _Use_bitmap = true; + bool _Use_bitmap = true; #if _USE_STD_VECTOR_ALGORITHMS - bool _Try_vectorize = !_STD _Is_constant_evaluated() && _Hay_size - _Start_at > _Threshold_find_first_of; + const bool _Try_vectorize = _Hay_size - _Start_at > _Threshold_find_first_of; #pragma warning(push) #pragma warning(disable : 4127) // conditional expression is constant - // Additional condition for when the vectorization outperforms the table lookup - if (_Try_vectorize && (sizeof(_Elem) == 1 || sizeof(_Elem) * _Needle_size <= 16)) { - _Use_bitmap = false; - } + // Additional condition for when the vectorization outperforms the table lookup + if (_Try_vectorize && (sizeof(_Elem) == 1 || sizeof(_Elem) * _Needle_size <= 16)) { + _Use_bitmap = false; + } #pragma warning(pop) #endif // _USE_STD_VECTOR_ALGORITHMS - if (_Use_bitmap) { - _String_bitmap<_Elem> _Matches; + if (_Use_bitmap) { + _String_bitmap<_Elem> _Matches; - if (_Matches._Mark(_Needle, _Needle + _Needle_size)) { - for (auto _Match_try = _Hay_start; _Match_try < _Hay_end; ++_Match_try) { - if (_Matches._Match(*_Match_try)) { - return static_cast(_Match_try - _Haystack); // found a match + if (_Matches._Mark(_Needle, _Needle + _Needle_size)) { + for (auto _Match_try = _Hay_start; _Match_try < _Hay_end; ++_Match_try) { + if (_Matches._Match(*_Match_try)) { + return static_cast(_Match_try - _Haystack); // found a match + } } + return static_cast(-1); // no match } - return static_cast(-1); // no match - } - // couldn't put one of the characters into the bitmap, fall back to the vectorized or serial algorithms - } + // couldn't put one of the characters into the bitmap, fall back to vectorized or serial algorithms + } #if _USE_STD_VECTOR_ALGORITHMS - if (_Try_vectorize) { - const _Traits_ptr_t<_Traits> _Found = - _STD _Find_first_of_vectorized(_Hay_start, _Hay_end, _Needle, _Needle + _Needle_size); - - if (_Found != _Hay_end) { - return static_cast(_Found - _Haystack); // found a match - } else { - return static_cast(-1); // no match + if (_Try_vectorize) { + const _Traits_ptr_t<_Traits> _Found = + _STD _Find_first_of_vectorized(_Hay_start, _Hay_end, _Needle, _Needle + _Needle_size); + + if (_Found != _Hay_end) { + return static_cast(_Found - _Haystack); // found a match + } else { + return static_cast(-1); // no match + } } - } #endif // _USE_STD_VECTOR_ALGORITHMS + } } for (auto _Match_try = _Hay_start; _Match_try < _Hay_end; ++_Match_try) { From e162d0de7630bcacc9fc4ed39cd3b35cf2657681 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Fri, 30 Aug 2024 10:47:15 -0700 Subject: [PATCH 24/26] Avoid C4127 instead of suppressing --- stl/inc/__msvc_string_view.hpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/stl/inc/__msvc_string_view.hpp b/stl/inc/__msvc_string_view.hpp index 8480b0dc744..b1e27961a6a 100644 --- a/stl/inc/__msvc_string_view.hpp +++ b/stl/inc/__msvc_string_view.hpp @@ -715,18 +715,13 @@ constexpr size_t _Traits_find_first_of(_In_reads_(_Hay_size) const _Traits_ptr_t if (!_STD _Is_constant_evaluated()) { using _Elem = typename _Traits::char_type; - bool _Use_bitmap = true; - #if _USE_STD_VECTOR_ALGORITHMS const bool _Try_vectorize = _Hay_size - _Start_at > _Threshold_find_first_of; -#pragma warning(push) -#pragma warning(disable : 4127) // conditional expression is constant // Additional condition for when the vectorization outperforms the table lookup - if (_Try_vectorize && (sizeof(_Elem) == 1 || sizeof(_Elem) * _Needle_size <= 16)) { - _Use_bitmap = false; - } -#pragma warning(pop) + const bool _Use_bitmap = !_Try_vectorize || (sizeof(_Elem) > 1 && sizeof(_Elem) * _Needle_size > 16); +#else + const bool _Use_bitmap = true; #endif // _USE_STD_VECTOR_ALGORITHMS if (_Use_bitmap) { From 50a55995951aac89444345437b55f4577120858a Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Fri, 30 Aug 2024 10:56:25 -0700 Subject: [PATCH 25/26] Fix thinko --- stl/inc/__msvc_string_view.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/inc/__msvc_string_view.hpp b/stl/inc/__msvc_string_view.hpp index b1e27961a6a..57d4534565b 100644 --- a/stl/inc/__msvc_string_view.hpp +++ b/stl/inc/__msvc_string_view.hpp @@ -715,13 +715,13 @@ constexpr size_t _Traits_find_first_of(_In_reads_(_Hay_size) const _Traits_ptr_t if (!_STD _Is_constant_evaluated()) { using _Elem = typename _Traits::char_type; + bool _Use_bitmap = true; + #if _USE_STD_VECTOR_ALGORITHMS const bool _Try_vectorize = _Hay_size - _Start_at > _Threshold_find_first_of; // Additional condition for when the vectorization outperforms the table lookup - const bool _Use_bitmap = !_Try_vectorize || (sizeof(_Elem) > 1 && sizeof(_Elem) * _Needle_size > 16); -#else - const bool _Use_bitmap = true; + _Use_bitmap = !_Try_vectorize || (sizeof(_Elem) > 1 && sizeof(_Elem) * _Needle_size > 16); #endif // _USE_STD_VECTOR_ALGORITHMS if (_Use_bitmap) { From 5eb4dfa60d4a7a2a6a1569ce886b6175f493ad91 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Fri, 30 Aug 2024 10:57:45 -0700 Subject: [PATCH 26/26] Revert "Fix thinko" This reverts commit 50a55995951aac89444345437b55f4577120858a. --- stl/inc/__msvc_string_view.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/inc/__msvc_string_view.hpp b/stl/inc/__msvc_string_view.hpp index 57d4534565b..b1e27961a6a 100644 --- a/stl/inc/__msvc_string_view.hpp +++ b/stl/inc/__msvc_string_view.hpp @@ -715,13 +715,13 @@ constexpr size_t _Traits_find_first_of(_In_reads_(_Hay_size) const _Traits_ptr_t if (!_STD _Is_constant_evaluated()) { using _Elem = typename _Traits::char_type; - bool _Use_bitmap = true; - #if _USE_STD_VECTOR_ALGORITHMS const bool _Try_vectorize = _Hay_size - _Start_at > _Threshold_find_first_of; // Additional condition for when the vectorization outperforms the table lookup - _Use_bitmap = !_Try_vectorize || (sizeof(_Elem) > 1 && sizeof(_Elem) * _Needle_size > 16); + const bool _Use_bitmap = !_Try_vectorize || (sizeof(_Elem) > 1 && sizeof(_Elem) * _Needle_size > 16); +#else + const bool _Use_bitmap = true; #endif // _USE_STD_VECTOR_ALGORITHMS if (_Use_bitmap) {