From 149cfffc032a53ec70c8120d6410ac007eb21746 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Thu, 4 Apr 2024 11:07:45 +0300 Subject: [PATCH 01/11] Optimize `find_first_of` for one element needle --- benchmarks/src/find_first_of.cpp | 3 +++ stl/inc/algorithm | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/benchmarks/src/find_first_of.cpp b/benchmarks/src/find_first_of.cpp index 170793f1e58..8b415b288e5 100644 --- a/benchmarks/src/find_first_of.cpp +++ b/benchmarks/src/find_first_of.cpp @@ -37,6 +37,9 @@ BENCHMARK(bm); BENCHMARK(bm); BENCHMARK(bm); +BENCHMARK(bm); +BENCHMARK(bm); + BENCHMARK(bm); BENCHMARK(bm); diff --git a/stl/inc/algorithm b/stl/inc/algorithm index ff1f8b65e3c..68defcfb58c 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -3383,6 +3383,17 @@ _NODISCARD _CONSTEXPR20 _FwdIt1 find_first_of( const auto _ULast1 = _STD _Get_unwrapped(_Last1); const auto _UFirst2 = _STD _Get_unwrapped(_First2); const auto _ULast2 = _STD _Get_unwrapped(_Last2); + + if constexpr (_Is_ranges_random_iter_v<_FwdIt2>) { + const auto _Count2 = _Last2 - _First2; + if (_Count2 == 1) { + _UFirst1 = _STD _Find_unchecked(_STD move(_UFirst1), _STD move(_ULast1), *_UFirst2); + _STD _Seek_wrapped(_First1, _UFirst1); + return _First1; + } + } + + #if _USE_STD_VECTOR_ALGORITHMS if constexpr (_Vector_alg_in_find_first_of_is_safe) { if (!_STD _Is_constant_evaluated() && _ULast1 - _UFirst1 >= _Threshold_find_first_of) { @@ -3478,6 +3489,14 @@ namespace ranges { _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se2, _It2>); _STL_INTERNAL_STATIC_ASSERT(indirectly_comparable<_It1, _It2, _Pr, _Pj1, _Pj2>); + if constexpr (_Is_ranges_random_iter_v<_It2> && sized_sentinel_for<_Se2, _It2>) { + const auto _Count2 = _Last2 - _First2; + if (_Count2 == 1) { + return _RANGES _Find_unchecked( + _STD move(_First1), _STD move(_Last1), _STD invoke(_Proj2, *_First2), _Proj1); + } + } + #if _USE_STD_VECTOR_ALGORITHMS if constexpr (_Vector_alg_in_find_first_of_is_safe<_It1, _It2, _Pr> && sized_sentinel_for<_Se1, _It1> && sized_sentinel_for<_Se2, _It2> && is_same_v<_Pj1, identity> && is_same_v<_Pj2, identity>) { From 55567dcb0dc48413d3de8a19564d5b6d6eefd24f Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Thu, 4 Apr 2024 13:07:19 +0300 Subject: [PATCH 02/11] Missing predicate check --- stl/inc/algorithm | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 68defcfb58c..c544c911add 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -3489,11 +3489,13 @@ namespace ranges { _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se2, _It2>); _STL_INTERNAL_STATIC_ASSERT(indirectly_comparable<_It1, _It2, _Pr, _Pj1, _Pj2>); - if constexpr (_Is_ranges_random_iter_v<_It2> && sized_sentinel_for<_Se2, _It2>) { + + if constexpr (_Is_ranges_random_iter_v<_It2> && sized_sentinel_for<_Se2, _It2> + && _Is_any_of_v<_Pr, _STD equal_to<>, _RANGES equal_to>) { const auto _Count2 = _Last2 - _First2; if (_Count2 == 1) { return _RANGES _Find_unchecked( - _STD move(_First1), _STD move(_Last1), _STD invoke(_Proj2, *_First2), _Proj1); + _STD move(_First1), _STD move(_Last1), _STD invoke(_Proj2, *_First2), _STD _Pass_fn(_Proj1)); } } From f11d4392dc690fc5afccfcedab7cfa31d5510426 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Thu, 4 Apr 2024 13:08:56 +0300 Subject: [PATCH 03/11] More missing predicate check --- stl/inc/algorithm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index c544c911add..60473df163b 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -3384,7 +3384,7 @@ _NODISCARD _CONSTEXPR20 _FwdIt1 find_first_of( const auto _UFirst2 = _STD _Get_unwrapped(_First2); const auto _ULast2 = _STD _Get_unwrapped(_Last2); - if constexpr (_Is_ranges_random_iter_v<_FwdIt2>) { + if constexpr (_Is_ranges_random_iter_v<_FwdIt2> && _Is_any_of_v<_Pr, _STD equal_to<>, _RANGES equal_to>) { const auto _Count2 = _Last2 - _First2; if (_Count2 == 1) { _UFirst1 = _STD _Find_unchecked(_STD move(_UFirst1), _STD move(_ULast1), *_UFirst2); From 737656bda6a7b92efb5edc2880b138f1c0247187 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Thu, 4 Apr 2024 14:52:43 +0300 Subject: [PATCH 04/11] C++20 guard --- stl/inc/algorithm | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 60473df163b..672a4301ada 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -3384,7 +3384,13 @@ _NODISCARD _CONSTEXPR20 _FwdIt1 find_first_of( const auto _UFirst2 = _STD _Get_unwrapped(_First2); const auto _ULast2 = _STD _Get_unwrapped(_Last2); - if constexpr (_Is_ranges_random_iter_v<_FwdIt2> && _Is_any_of_v<_Pr, _STD equal_to<>, _RANGES equal_to>) { + constexpr bool _Is_predicate_equal = _Is_any_of_v<_Pr, +#if _HAS_CXX20 + _RANGES equal_to, +#endif // _HAS_CXX20 + _STD equal_to<>>; + + if constexpr (_Is_ranges_random_iter_v<_FwdIt2> && _Is_predicate_equal) { const auto _Count2 = _Last2 - _First2; if (_Count2 == 1) { _UFirst1 = _STD _Find_unchecked(_STD move(_UFirst1), _STD move(_ULast1), *_UFirst2); From 2738b9420af9474cd6c64be8e7347a5dd0a0930b Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Fri, 5 Apr 2024 07:37:02 +0300 Subject: [PATCH 05/11] unwrapped --- stl/inc/algorithm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 672a4301ada..5726e9df871 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -3390,7 +3390,7 @@ _NODISCARD _CONSTEXPR20 _FwdIt1 find_first_of( #endif // _HAS_CXX20 _STD equal_to<>>; - if constexpr (_Is_ranges_random_iter_v<_FwdIt2> && _Is_predicate_equal) { + if constexpr (_Is_ranges_random_iter_v && _Is_predicate_equal) { const auto _Count2 = _Last2 - _First2; if (_Count2 == 1) { _UFirst1 = _STD _Find_unchecked(_STD move(_UFirst1), _STD move(_ULast1), *_UFirst2); @@ -3399,7 +3399,6 @@ _NODISCARD _CONSTEXPR20 _FwdIt1 find_first_of( } } - #if _USE_STD_VECTOR_ALGORITHMS if constexpr (_Vector_alg_in_find_first_of_is_safe) { if (!_STD _Is_constant_evaluated() && _ULast1 - _UFirst1 >= _Threshold_find_first_of) { From 685f46daf4a51a784549854babaa5c27e30f1c66 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Fri, 5 Apr 2024 08:20:52 +0300 Subject: [PATCH 06/11] unconst --- stl/inc/algorithm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 5726e9df871..9e3d0b4599e 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -3390,7 +3390,7 @@ _NODISCARD _CONSTEXPR20 _FwdIt1 find_first_of( #endif // _HAS_CXX20 _STD equal_to<>>; - if constexpr (_Is_ranges_random_iter_v && _Is_predicate_equal) { + if constexpr (_Is_ranges_random_iter_v> && _Is_predicate_equal) { const auto _Count2 = _Last2 - _First2; if (_Count2 == 1) { _UFirst1 = _STD _Find_unchecked(_STD move(_UFirst1), _STD move(_ULast1), *_UFirst2); From bf4914db2f84a6664d50ee94a0337643228668c4 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Fri, 5 Apr 2024 10:55:23 +0300 Subject: [PATCH 07/11] more scalable benchmark variation --- benchmarks/src/find_first_of.cpp | 46 ++++++++++++++++---------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/benchmarks/src/find_first_of.cpp b/benchmarks/src/find_first_of.cpp index 8b415b288e5..5ecc3f14718 100644 --- a/benchmarks/src/find_first_of.cpp +++ b/benchmarks/src/find_first_of.cpp @@ -10,14 +10,21 @@ using namespace std; -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)); + const size_t HSize = Pos * 2; + const size_t Which = 0; + vector h(HSize, T{'.'}); vector n(NSize); iota(n.begin(), n.end(), T{'a'}); - static_assert(Pos < HSize); - static_assert(Which < NSize); + if (Pos >= HSize || Which >= NSize) { + abort(); + } + h[Pos] = n[Which]; for (auto _ : state) { @@ -25,25 +32,18 @@ void bm(benchmark::State& state) { } } -BENCHMARK(bm); -BENCHMARK(bm); - -BENCHMARK(bm); -BENCHMARK(bm); - -BENCHMARK(bm); -BENCHMARK(bm); - -BENCHMARK(bm); -BENCHMARK(bm); - -BENCHMARK(bm); -BENCHMARK(bm); - -BENCHMARK(bm); -BENCHMARK(bm); - -BENCHMARK(bm); -BENCHMARK(bm); +#define ARGS \ + Args({2, 3}) \ + ->Args({7, 4}) \ + ->Args({9, 3}) \ + ->Args({22, 5}) \ + ->Args({58, 2}) \ + ->Args({102, 4}) \ + ->Args({325, 1}) \ + ->Args({1011, 11}) \ + ->Args({3056, 7}); + +BENCHMARK(bm)->ARGS; +BENCHMARK(bm)->ARGS; BENCHMARK_MAIN(); From 53e761e7010b3d2c35f189b613b9b807864913fc Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 5 Apr 2024 06:31:11 -0700 Subject: [PATCH 08/11] Drop redundant `_Pass_fn()`. --- stl/inc/algorithm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 9e3d0b4599e..9bd6c259d78 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -3500,7 +3500,7 @@ namespace ranges { const auto _Count2 = _Last2 - _First2; if (_Count2 == 1) { return _RANGES _Find_unchecked( - _STD move(_First1), _STD move(_Last1), _STD invoke(_Proj2, *_First2), _STD _Pass_fn(_Proj1)); + _STD move(_First1), _STD move(_Last1), _STD invoke(_Proj2, *_First2), _Proj1); } } From 469b993d456df47186f768b928dac573ca3f443c Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 5 Apr 2024 06:32:39 -0700 Subject: [PATCH 09/11] Include `` for `abort()`. --- benchmarks/src/find_first_of.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/benchmarks/src/find_first_of.cpp b/benchmarks/src/find_first_of.cpp index 5ecc3f14718..4697ccd3c8a 100644 --- a/benchmarks/src/find_first_of.cpp +++ b/benchmarks/src/find_first_of.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include From 8c70d08ce7d7115b90a3f5c02293cd14c6a76efb Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 5 Apr 2024 06:40:43 -0700 Subject: [PATCH 10/11] Subtract unchecked iterators for efficiency. --- stl/inc/algorithm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 9bd6c259d78..62035207b6c 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -3391,7 +3391,7 @@ _NODISCARD _CONSTEXPR20 _FwdIt1 find_first_of( _STD equal_to<>>; if constexpr (_Is_ranges_random_iter_v> && _Is_predicate_equal) { - const auto _Count2 = _Last2 - _First2; + const auto _Count2 = _ULast2 - _UFirst2; if (_Count2 == 1) { _UFirst1 = _STD _Find_unchecked(_STD move(_UFirst1), _STD move(_ULast1), *_UFirst2); _STD _Seek_wrapped(_First1, _UFirst1); From 8fd316bf87bf8ee50ba8a2b5780de1f5ae8406e9 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 5 Apr 2024 06:49:19 -0700 Subject: [PATCH 11/11] Remove interfering constness, and an extra newline. --- stl/inc/algorithm | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 62035207b6c..5284ebebe2d 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -3379,10 +3379,10 @@ _NODISCARD _CONSTEXPR20 _FwdIt1 find_first_of( // look for one of [_First2, _Last2) satisfying _Pred with element _STD _Adl_verify_range(_First1, _Last1); _STD _Adl_verify_range(_First2, _Last2); - auto _UFirst1 = _STD _Get_unwrapped(_First1); - const auto _ULast1 = _STD _Get_unwrapped(_Last1); - const auto _UFirst2 = _STD _Get_unwrapped(_First2); - const auto _ULast2 = _STD _Get_unwrapped(_Last2); + auto _UFirst1 = _STD _Get_unwrapped(_First1); + auto _ULast1 = _STD _Get_unwrapped(_Last1); + auto _UFirst2 = _STD _Get_unwrapped(_First2); + const auto _ULast2 = _STD _Get_unwrapped(_Last2); constexpr bool _Is_predicate_equal = _Is_any_of_v<_Pr, #if _HAS_CXX20 @@ -3390,7 +3390,7 @@ _NODISCARD _CONSTEXPR20 _FwdIt1 find_first_of( #endif // _HAS_CXX20 _STD equal_to<>>; - if constexpr (_Is_ranges_random_iter_v> && _Is_predicate_equal) { + if constexpr (_Is_ranges_random_iter_v && _Is_predicate_equal) { const auto _Count2 = _ULast2 - _UFirst2; if (_Count2 == 1) { _UFirst1 = _STD _Find_unchecked(_STD move(_UFirst1), _STD move(_ULast1), *_UFirst2); @@ -3486,15 +3486,14 @@ namespace ranges { private: template - _NODISCARD static constexpr _It1 _Find_first_of_unchecked(_It1 _First1, const _Se1 _Last1, const _It2 _First2, - const _Se2 _Last2, _Pr _Pred, _Pj1 _Proj1, _Pj2 _Proj2) { + _NODISCARD static constexpr _It1 _Find_first_of_unchecked( + _It1 _First1, _Se1 _Last1, const _It2 _First2, const _Se2 _Last2, _Pr _Pred, _Pj1 _Proj1, _Pj2 _Proj2) { _STL_INTERNAL_STATIC_ASSERT(input_iterator<_It1>); _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se1, _It1>); _STL_INTERNAL_STATIC_ASSERT(forward_iterator<_It2>); _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se2, _It2>); _STL_INTERNAL_STATIC_ASSERT(indirectly_comparable<_It1, _It2, _Pr, _Pj1, _Pj2>); - if constexpr (_Is_ranges_random_iter_v<_It2> && sized_sentinel_for<_Se2, _It2> && _Is_any_of_v<_Pr, _STD equal_to<>, _RANGES equal_to>) { const auto _Count2 = _Last2 - _First2;