@@ -38,7 +38,7 @@ int main(int argc, char** argv) {
3838 });
3939 };
4040
41- // Benchmark {std,ranges}::search where the needle is never found
41+ // Benchmark {std,ranges}::search where the needle is never found (worst case).
4242 {
4343 auto bm = []<class Container >(std::string name, auto search) {
4444 benchmark::RegisterBenchmark (
@@ -80,7 +80,7 @@ int main(int argc, char** argv) {
8080 bm.operator ()<std::list<int >>(" rng::search(list<int>, pred) (no match)" , ranges_search_pred);
8181 }
8282
83- // Benchmark {std,ranges}::search where we intersperse "near matches" inside the haystack
83+ // Benchmark {std,ranges}::search where we intersperse "near matches" inside the haystack.
8484 {
8585 auto bm = []<class Container >(std::string name, auto search) {
8686 benchmark::RegisterBenchmark (
@@ -132,6 +132,87 @@ int main(int argc, char** argv) {
132132 bm.operator ()<std::list<int >>(" rng::search(list<int>, pred) (near matches)" , ranges_search_pred);
133133 }
134134
135+ // Special case: the two ranges are the same length (and they are equal, which is the worst case).
136+ {
137+ auto bm = []<class Container >(std::string name, auto search) {
138+ benchmark::RegisterBenchmark (
139+ name,
140+ [search](auto & st) {
141+ std::size_t const size = st.range (0 );
142+ using ValueType = typename Container::value_type;
143+ ValueType x = Generate<ValueType>::random ();
144+ Container haystack (size, x);
145+ Container needle (size, x);
146+
147+ for ([[maybe_unused]] auto _ : st) {
148+ benchmark::DoNotOptimize (haystack);
149+ benchmark::DoNotOptimize (needle);
150+ auto result = search (haystack.begin (), haystack.end (), needle.begin (), needle.end ());
151+ benchmark::DoNotOptimize (result);
152+ }
153+ })
154+ ->Arg (1000 ) // non power-of-two
155+ ->Arg (1024 )
156+ ->Arg (8192 );
157+ };
158+ // {std,ranges}::search
159+ bm.operator ()<std::vector<int >>(" std::search(vector<int>) (same length)" , std_search);
160+ bm.operator ()<std::deque<int >>(" std::search(deque<int>) (same length)" , std_search);
161+ bm.operator ()<std::list<int >>(" std::search(list<int>) (same length)" , std_search);
162+ bm.operator ()<std::vector<int >>(" rng::search(vector<int>) (same length)" , std::ranges::search);
163+ bm.operator ()<std::deque<int >>(" rng::search(deque<int>) (same length)" , std::ranges::search);
164+ bm.operator ()<std::list<int >>(" rng::search(list<int>) (same length)" , std::ranges::search);
165+
166+ // {std,ranges}::search(pred)
167+ bm.operator ()<std::vector<int >>(" std::search(vector<int>, pred) (same length)" , std_search_pred);
168+ bm.operator ()<std::deque<int >>(" std::search(deque<int>, pred) (same length)" , std_search_pred);
169+ bm.operator ()<std::list<int >>(" std::search(list<int>, pred) (same length)" , std_search_pred);
170+ bm.operator ()<std::vector<int >>(" rng::search(vector<int>, pred) (same length)" , ranges_search_pred);
171+ bm.operator ()<std::deque<int >>(" rng::search(deque<int>, pred) (same length)" , ranges_search_pred);
172+ bm.operator ()<std::list<int >>(" rng::search(list<int>, pred) (same length)" , ranges_search_pred);
173+ }
174+
175+ // Special case: the needle contains a single element (which we never find, i.e. the worst case).
176+ {
177+ auto bm = []<class Container >(std::string name, auto search) {
178+ benchmark::RegisterBenchmark (
179+ name,
180+ [search](auto & st) {
181+ std::size_t const size = st.range (0 );
182+ using ValueType = typename Container::value_type;
183+ ValueType x = Generate<ValueType>::random ();
184+ ValueType y = random_different_from ({x});
185+ Container haystack (size, x);
186+ Container needle (1 , y);
187+
188+ for ([[maybe_unused]] auto _ : st) {
189+ benchmark::DoNotOptimize (haystack);
190+ benchmark::DoNotOptimize (needle);
191+ auto result = search (haystack.begin (), haystack.end (), needle.begin (), needle.end ());
192+ benchmark::DoNotOptimize (result);
193+ }
194+ })
195+ ->Arg (1000 ) // non power-of-two
196+ ->Arg (1024 )
197+ ->Arg (8192 );
198+ };
199+ // {std,ranges}::search
200+ bm.operator ()<std::vector<int >>(" std::search(vector<int>) (single element)" , std_search);
201+ bm.operator ()<std::deque<int >>(" std::search(deque<int>) (single element)" , std_search);
202+ bm.operator ()<std::list<int >>(" std::search(list<int>) (single element)" , std_search);
203+ bm.operator ()<std::vector<int >>(" rng::search(vector<int>) (single element)" , std::ranges::search);
204+ bm.operator ()<std::deque<int >>(" rng::search(deque<int>) (single element)" , std::ranges::search);
205+ bm.operator ()<std::list<int >>(" rng::search(list<int>) (single element)" , std::ranges::search);
206+
207+ // {std,ranges}::search(pred)
208+ bm.operator ()<std::vector<int >>(" std::search(vector<int>, pred) (single element)" , std_search_pred);
209+ bm.operator ()<std::deque<int >>(" std::search(deque<int>, pred) (single element)" , std_search_pred);
210+ bm.operator ()<std::list<int >>(" std::search(list<int>, pred) (single element)" , std_search_pred);
211+ bm.operator ()<std::vector<int >>(" rng::search(vector<int>, pred) (single element)" , ranges_search_pred);
212+ bm.operator ()<std::deque<int >>(" rng::search(deque<int>, pred) (single element)" , ranges_search_pred);
213+ bm.operator ()<std::list<int >>(" rng::search(list<int>, pred) (single element)" , ranges_search_pred);
214+ }
215+
135216 benchmark::Initialize (&argc, argv);
136217 benchmark::RunSpecifiedBenchmarks ();
137218 benchmark::Shutdown ();
0 commit comments