From 9043ffe1b64ae9927ca616dacadc64d127b4c193 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Tue, 18 Mar 2025 20:44:44 +0200 Subject: [PATCH 1/5] Use `find` for `search_n` when n=1 --- benchmarks/CMakeLists.txt | 1 + benchmarks/src/search_n.cpp | 57 +++++++++++++++++++ stl/inc/algorithm | 37 ++++++++++++ .../P0896R4_ranges_alg_search_n/test.cpp | 14 +++++ 4 files changed, 109 insertions(+) create mode 100644 benchmarks/src/search_n.cpp diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 22503345a4a..d1367bc9d3f 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -124,6 +124,7 @@ add_benchmark(random_integer_generation src/random_integer_generation.cpp) add_benchmark(remove src/remove.cpp) add_benchmark(replace src/replace.cpp) add_benchmark(search src/search.cpp) +add_benchmark(search_n src/search_n.cpp) add_benchmark(std_copy src/std_copy.cpp) add_benchmark(sv_equal src/sv_equal.cpp) add_benchmark(swap_ranges src/swap_ranges.cpp) diff --git a/benchmarks/src/search_n.cpp b/benchmarks/src/search_n.cpp new file mode 100644 index 00000000000..313b944034e --- /dev/null +++ b/benchmarks/src/search_n.cpp @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include + +#include "skewed_allocator.hpp" + +using namespace std; + +// NB: This particular algorthm has std and ranges implementations with different perf charactterstitics! + +enum class AlgType { Std, Rng }; + +template +void bm(benchmark::State& state) { + const auto size = static_cast(state.range(0)); + + constexpr size_t count = 1; + + constexpr T no_match{'-'}; + constexpr T match{'*'}; + + vector> v(size, no_match); + + fill(v.begin() + v.size() / 2, v.end(), match); + + for (auto _ : state) { + if constexpr (Alg == AlgType::Std) { + benchmark::DoNotOptimize(search_n(v.begin(), v.end(), count, match)); + } else if constexpr (Alg == AlgType::Rng) { + benchmark::DoNotOptimize(ranges::search_n(v, count, match)); + } + } +} + +void common_args(auto bm) { + bm->Arg(3000); +} + +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(); diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 8109baf3a16..d1f0a6684b9 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -2220,6 +2220,16 @@ _NODISCARD _CONSTEXPR20 _FwdIt search_n( return _First; } + if constexpr (_Is_any_of_v<_Pr, +#if _HAS_CXX20 + _RANGES equal_to, +#endif + equal_to<>>) { + if (_Count == 1) { + return _STD find(_First, _Last, _Val); + } + } + if (static_cast(_Count) > static_cast(_STD _Max_limit<_Iter_diff_t<_FwdIt>>())) { // if the number of _Vals searched for is larger than the longest possible sequence, we can't find it return _Last; @@ -2320,6 +2330,19 @@ namespace ranges { return {_First, _First}; } + if constexpr (_Is_any_of_v<_Pr, _STD equal_to<>, _RANGES equal_to>) { + if (_Count == 1) { + auto _Res = _RANGES find(_First, _Last, _Val, _Pass_fn(_Proj)); + if (_Res != _Last) { + auto _Res_end = _Res; + ++_Res_end; + return {_STD move(_Res), _STD move(_Res_end)}; + } else { + return {_Res, _Res}; + } + } + } + auto _UFirst = _RANGES _Unwrap_iter<_Se>(_STD move(_First)); auto _ULast = _RANGES _Unwrap_sent<_It>(_STD move(_Last)); @@ -2346,6 +2369,20 @@ namespace ranges { return {_First, _First}; } + if constexpr (_Is_any_of_v<_Pr, _STD equal_to<>, _RANGES equal_to>) { + if (_Count == 1) { + auto _Res = _RANGES find(_Range, _Val, _Pass_fn(_Proj)); + auto _Last = _RANGES end(_Range); + if (_Res != _Last) { + auto _Res_end = _Res; + ++_Res_end; + return {_STD move(_Res), _STD move(_Res_end)}; + } else { + return {_Res, _Res}; + } + } + } + if constexpr (sized_range<_Rng>) { const auto _Dist = _RANGES distance(_Range); diff --git a/tests/std/tests/P0896R4_ranges_alg_search_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_search_n/test.cpp index 3f3a609e568..fa3e9e7c6e8 100644 --- a/tests/std/tests/P0896R4_ranges_alg_search_n/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_search_n/test.cpp @@ -98,6 +98,20 @@ struct instantiator { assert(result.end() == range.begin()); } + // trivial case: unit needle + { + const auto result = ranges::search_n(range, 1, 0, cmp, get_first); + static_assert(same_as>>); + assert(result.begin() == ranges::next(range.begin(), 1)); + assert(result.end() == ranges::next(range.begin(), 2)); + } + { + const auto result = ranges::search_n(ranges::begin(range), ranges::end(range), 1, 0, cmp, get_first); + static_assert(same_as>>); + assert(result.begin() == ranges::next(range.begin(), 1)); + assert(result.end() == ranges::next(range.begin(), 2)); + } + // trivial case: range too small { const auto result = ranges::search_n(range, 99999, 0, cmp, get_first); From 7af139a3765f9bffabdd017edf2d1cbe5cdcdc42 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Tue, 18 Mar 2025 23:17:19 +0200 Subject: [PATCH 2/5] Actually test predicate-less unit needle --- .../std/tests/P0896R4_ranges_alg_search_n/test.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/std/tests/P0896R4_ranges_alg_search_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_search_n/test.cpp index fa3e9e7c6e8..46a2590bdb7 100644 --- a/tests/std/tests/P0896R4_ranges_alg_search_n/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_search_n/test.cpp @@ -99,6 +99,20 @@ struct instantiator { } // trivial case: unit needle + { + const auto result = ranges::search_n(range, 1, P{1, 42}); + static_assert(same_as>>); + assert(result.begin() == ranges::next(range.begin(), 1)); + assert(result.end() == ranges::next(range.begin(), 2)); + } + { + const auto result = ranges::search_n(ranges::begin(range), ranges::end(range), 1, P{1, 42}); + static_assert(same_as>>); + assert(result.begin() == ranges::next(range.begin(), 1)); + assert(result.end() == ranges::next(range.begin(), 2)); + } + + // trivial case: unit needle with predicate { const auto result = ranges::search_n(range, 1, 0, cmp, get_first); static_assert(same_as>>); From 74116a215d3ace79d1be2e43c6072188bff8a394 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 19 Mar 2025 17:20:22 -0700 Subject: [PATCH 3/5] Fix comment typos. --- benchmarks/src/search_n.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/src/search_n.cpp b/benchmarks/src/search_n.cpp index 313b944034e..ffddae9ca96 100644 --- a/benchmarks/src/search_n.cpp +++ b/benchmarks/src/search_n.cpp @@ -12,7 +12,7 @@ using namespace std; -// NB: This particular algorthm has std and ranges implementations with different perf charactterstitics! +// NB: This particular algorithm has std and ranges implementations with different perf characteristics! enum class AlgType { Std, Rng }; From d3766eafdc94d002a415809b9b3c9c7897fa55a1 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 19 Mar 2025 17:23:08 -0700 Subject: [PATCH 4/5] Avoid shadowing: count => N --- benchmarks/src/search_n.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/benchmarks/src/search_n.cpp b/benchmarks/src/search_n.cpp index ffddae9ca96..1fab2bf11f5 100644 --- a/benchmarks/src/search_n.cpp +++ b/benchmarks/src/search_n.cpp @@ -20,7 +20,7 @@ template void bm(benchmark::State& state) { const auto size = static_cast(state.range(0)); - constexpr size_t count = 1; + constexpr size_t N = 1; constexpr T no_match{'-'}; constexpr T match{'*'}; @@ -31,9 +31,9 @@ void bm(benchmark::State& state) { for (auto _ : state) { if constexpr (Alg == AlgType::Std) { - benchmark::DoNotOptimize(search_n(v.begin(), v.end(), count, match)); + benchmark::DoNotOptimize(search_n(v.begin(), v.end(), N, match)); } else if constexpr (Alg == AlgType::Rng) { - benchmark::DoNotOptimize(ranges::search_n(v, count, match)); + benchmark::DoNotOptimize(ranges::search_n(v, N, match)); } } } From 2cb7d1ca06910b3e45a58cfad9c6f01c93d7347a Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 19 Mar 2025 17:24:12 -0700 Subject: [PATCH 5/5] Remove unused ``. --- benchmarks/src/search_n.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/benchmarks/src/search_n.cpp b/benchmarks/src/search_n.cpp index 1fab2bf11f5..b35cfd9eb2d 100644 --- a/benchmarks/src/search_n.cpp +++ b/benchmarks/src/search_n.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include "skewed_allocator.hpp"