[libcxx-commits] [libcxx] b3a4bf9 - [libc++] Refactor and add benchmarks from [alg.nonmodifying] (#128206)
via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Mar 18 21:08:49 PDT 2025
Author: Louis Dionne
Date: 2025-03-19T00:08:46-04:00
New Revision: b3a4bf9d8f04018bfa81b7e97ec36b247e15b378
URL: https://github.com/llvm/llvm-project/commit/b3a4bf9d8f04018bfa81b7e97ec36b247e15b378
DIFF: https://github.com/llvm/llvm-project/commit/b3a4bf9d8f04018bfa81b7e97ec36b247e15b378.diff
LOG: [libc++] Refactor and add benchmarks from [alg.nonmodifying] (#128206)
Added:
libcxx/test/benchmarks/algorithms/nonmodifying/adjacent_find.bench.cpp
libcxx/test/benchmarks/algorithms/nonmodifying/any_all_none_of.bench.cpp
libcxx/test/benchmarks/algorithms/nonmodifying/contains.bench.cpp
libcxx/test/benchmarks/algorithms/nonmodifying/contains_subrange.bench.cpp
libcxx/test/benchmarks/algorithms/nonmodifying/count.bench.cpp
libcxx/test/benchmarks/algorithms/nonmodifying/ends_with.bench.cpp
libcxx/test/benchmarks/algorithms/nonmodifying/equal.bench.cpp
libcxx/test/benchmarks/algorithms/nonmodifying/find.bench.cpp
libcxx/test/benchmarks/algorithms/nonmodifying/find_end.bench.cpp
libcxx/test/benchmarks/algorithms/nonmodifying/find_first_of.bench.cpp
libcxx/test/benchmarks/algorithms/nonmodifying/find_last.bench.cpp
libcxx/test/benchmarks/algorithms/nonmodifying/fold.bench.cpp
libcxx/test/benchmarks/algorithms/nonmodifying/for_each.bench.cpp
libcxx/test/benchmarks/algorithms/nonmodifying/is_permutation.bench.cpp
libcxx/test/benchmarks/algorithms/nonmodifying/mismatch.bench.cpp
libcxx/test/benchmarks/algorithms/nonmodifying/search.bench.cpp
libcxx/test/benchmarks/algorithms/nonmodifying/search_n.bench.cpp
libcxx/test/benchmarks/algorithms/nonmodifying/starts_with.bench.cpp
Modified:
libcxx/include/module.modulemap
libcxx/test/benchmarks/GenerateInput.h
Removed:
libcxx/test/benchmarks/algorithms/count.bench.cpp
libcxx/test/benchmarks/algorithms/equal.bench.cpp
libcxx/test/benchmarks/algorithms/find.bench.cpp
libcxx/test/benchmarks/algorithms/for_each.bench.cpp
libcxx/test/benchmarks/algorithms/mismatch.bench.cpp
libcxx/test/benchmarks/algorithms/ranges_contains.bench.cpp
libcxx/test/benchmarks/algorithms/ranges_ends_with.bench.cpp
################################################################################
diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index 43072aa0fb0f1..99f8c94d351ad 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -543,11 +543,17 @@ module std [system] {
}
module ranges_fill_n { header "__algorithm/ranges_fill_n.h" }
module ranges_fill { header "__algorithm/ranges_fill.h" }
- module ranges_find_end { header "__algorithm/ranges_find_end.h" }
+ module ranges_find_end {
+ header "__algorithm/ranges_find_end.h"
+ export std.ranges.subrange // return type
+ }
module ranges_find_first_of { header "__algorithm/ranges_find_first_of.h" }
module ranges_find_if_not { header "__algorithm/ranges_find_if_not.h" }
module ranges_find_if { header "__algorithm/ranges_find_if.h" }
- module ranges_find_last { header "__algorithm/ranges_find_last.h" }
+ module ranges_find_last {
+ header "__algorithm/ranges_find_last.h"
+ export std.ranges.subrange // return type
+ }
module ranges_find { header "__algorithm/ranges_find.h" }
module ranges_fold { header "__algorithm/ranges_fold.h" }
module ranges_for_each_n {
@@ -737,8 +743,14 @@ module std [system] {
}
module ranges_rotate { header "__algorithm/ranges_rotate.h" }
module ranges_sample { header "__algorithm/ranges_sample.h" }
- module ranges_search_n { header "__algorithm/ranges_search_n.h" }
- module ranges_search { header "__algorithm/ranges_search.h" }
+ module ranges_search_n {
+ header "__algorithm/ranges_search_n.h"
+ export std.ranges.subrange // return type
+ }
+ module ranges_search {
+ header "__algorithm/ranges_search.h"
+ export std.ranges.subrange // return type
+ }
module ranges_set_
diff erence {
header "__algorithm/ranges_set_
diff erence.h"
export std.functional.ranges_operations
diff --git a/libcxx/test/benchmarks/GenerateInput.h b/libcxx/test/benchmarks/GenerateInput.h
index 9be76f55c2774..06387852f76a6 100644
--- a/libcxx/test/benchmarks/GenerateInput.h
+++ b/libcxx/test/benchmarks/GenerateInput.h
@@ -13,6 +13,7 @@
#include <climits>
#include <concepts>
#include <cstddef>
+#include <initializer_list>
#include <random>
#include <string>
#include <vector>
diff --git a/libcxx/test/benchmarks/algorithms/count.bench.cpp b/libcxx/test/benchmarks/algorithms/count.bench.cpp
deleted file mode 100644
index 46b85e909efa5..0000000000000
--- a/libcxx/test/benchmarks/algorithms/count.bench.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03, c++11, c++14, c++17
-
-#include <algorithm>
-#include <benchmark/benchmark.h>
-#include <cstring>
-#include <random>
-#include <vector>
-
-static void bm_vector_bool_count(benchmark::State& state) {
- std::vector<bool> vec1(state.range(), false);
-
- for (auto _ : state) {
- benchmark::DoNotOptimize(vec1);
- benchmark::DoNotOptimize(std::count(vec1.begin(), vec1.end(), true));
- }
-}
-BENCHMARK(bm_vector_bool_count)->DenseRange(1, 8)->Range(16, 1 << 20);
-
-static void bm_vector_bool_ranges_count(benchmark::State& state) {
- std::vector<bool> vec1(state.range(), false);
-
- for (auto _ : state) {
- benchmark::DoNotOptimize(vec1);
- benchmark::DoNotOptimize(std::ranges::count(vec1.begin(), vec1.end(), true));
- }
-}
-BENCHMARK(bm_vector_bool_ranges_count)->DenseRange(1, 8)->Range(16, 1 << 20);
-
-BENCHMARK_MAIN();
diff --git a/libcxx/test/benchmarks/algorithms/equal.bench.cpp b/libcxx/test/benchmarks/algorithms/equal.bench.cpp
deleted file mode 100644
index 328b39608607e..0000000000000
--- a/libcxx/test/benchmarks/algorithms/equal.bench.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03, c++11, c++14, c++17
-
-#include <algorithm>
-#include <benchmark/benchmark.h>
-#include <vector>
-
-static void bm_equal_iter(benchmark::State& state) {
- std::vector<char> vec1(state.range(), '1');
- std::vector<char> vec2(state.range(), '1');
- for (auto _ : state) {
- benchmark::DoNotOptimize(vec1);
- benchmark::DoNotOptimize(vec2);
- benchmark::DoNotOptimize(std::equal(vec1.begin(), vec1.end(), vec2.begin()));
- }
-}
-BENCHMARK(bm_equal_iter)->DenseRange(1, 8)->Range(16, 1 << 20);
-
-static void bm_equal(benchmark::State& state) {
- std::vector<char> vec1(state.range(), '1');
- std::vector<char> vec2(state.range(), '1');
- for (auto _ : state) {
- benchmark::DoNotOptimize(vec1);
- benchmark::DoNotOptimize(vec2);
- benchmark::DoNotOptimize(std::equal(vec1.begin(), vec1.end(), vec2.begin(), vec2.end()));
- }
-}
-BENCHMARK(bm_equal)->DenseRange(1, 8)->Range(16, 1 << 20);
-
-static void bm_ranges_equal(benchmark::State& state) {
- std::vector<char> vec1(state.range(), '1');
- std::vector<char> vec2(state.range(), '1');
- for (auto _ : state) {
- benchmark::DoNotOptimize(vec1);
- benchmark::DoNotOptimize(vec2);
- benchmark::DoNotOptimize(std::ranges::equal(vec1, vec2));
- }
-}
-BENCHMARK(bm_ranges_equal)->DenseRange(1, 8)->Range(16, 1 << 20);
-
-static void bm_ranges_equal_vb_aligned(benchmark::State& state) {
- auto n = state.range();
- std::vector<bool> vec1(n, true);
- std::vector<bool> vec2(n, true);
- for (auto _ : state) {
- benchmark::DoNotOptimize(std::ranges::equal(vec1, vec2));
- benchmark::DoNotOptimize(&vec1);
- benchmark::DoNotOptimize(&vec2);
- }
-}
-
-static void bm_ranges_equal_vb_unaligned(benchmark::State& state) {
- auto n = state.range();
- std::vector<bool> vec1(n, true);
- std::vector<bool> vec2(n + 8, true);
- auto beg1 = std::ranges::begin(vec1);
- auto end1 = std::ranges::end(vec1);
- auto beg2 = std::ranges::begin(vec2) + 4;
- auto end2 = std::ranges::end(vec2) - 4;
- for (auto _ : state) {
- benchmark::DoNotOptimize(std::ranges::equal(beg1, end1, beg2, end2));
- benchmark::DoNotOptimize(&vec1);
- benchmark::DoNotOptimize(&vec2);
- }
-}
-
-// Test std::ranges::equal for vector<bool>::iterator
-BENCHMARK(bm_ranges_equal_vb_aligned)->RangeMultiplier(4)->Range(8, 1 << 20);
-BENCHMARK(bm_ranges_equal_vb_unaligned)->Range(8, 1 << 20);
-
-static void bm_equal_vb(benchmark::State& state, bool aligned) {
- auto n = state.range();
- std::vector<bool> vec1(n, true);
- std::vector<bool> vec2(aligned ? n : n + 8, true);
- auto beg1 = vec1.begin();
- auto end1 = vec1.end();
- auto beg2 = aligned ? vec2.begin() : vec2.begin() + 4;
- for (auto _ : state) {
- benchmark::DoNotOptimize(std::equal(beg1, end1, beg2));
- benchmark::DoNotOptimize(&vec1);
- benchmark::DoNotOptimize(&vec2);
- }
-}
-
-static void bm_equal_vb_aligned(benchmark::State& state) { bm_equal_vb(state, true); }
-static void bm_equal_vb_unaligned(benchmark::State& state) { bm_equal_vb(state, false); }
-
-// Test std::equal for vector<bool>::iterator
-BENCHMARK(bm_equal_vb_aligned)->Range(8, 1 << 20);
-BENCHMARK(bm_equal_vb_unaligned)->Range(8, 1 << 20);
-
-BENCHMARK_MAIN();
diff --git a/libcxx/test/benchmarks/algorithms/find.bench.cpp b/libcxx/test/benchmarks/algorithms/find.bench.cpp
deleted file mode 100644
index 43d103474ebdf..0000000000000
--- a/libcxx/test/benchmarks/algorithms/find.bench.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03, c++11, c++14, c++17
-
-#include <algorithm>
-#include <benchmark/benchmark.h>
-#include <cstring>
-#include <deque>
-#include <random>
-#include <vector>
-
-template <class Container>
-static void bm_find(benchmark::State& state) {
- using T = Container::value_type;
-
- Container vec1(state.range(), '1');
- std::mt19937_64 rng(std::random_device{}());
-
- for (auto _ : state) {
- auto idx = rng() % vec1.size();
- vec1[idx] = '2';
- benchmark::DoNotOptimize(vec1);
- benchmark::DoNotOptimize(std::find(vec1.begin(), vec1.end(), T('2')));
- vec1[idx] = '1';
- }
-}
-BENCHMARK(bm_find<std::vector<char>>)->DenseRange(1, 8)->Range(16, 1 << 20);
-BENCHMARK(bm_find<std::vector<short>>)->DenseRange(1, 8)->Range(16, 1 << 20);
-BENCHMARK(bm_find<std::vector<int>>)->DenseRange(1, 8)->Range(16, 1 << 20);
-BENCHMARK(bm_find<std::deque<char>>)->DenseRange(1, 8)->Range(16, 1 << 20);
-BENCHMARK(bm_find<std::deque<short>>)->DenseRange(1, 8)->Range(16, 1 << 20);
-BENCHMARK(bm_find<std::deque<int>>)->DenseRange(1, 8)->Range(16, 1 << 20);
-
-template <class Container>
-static void bm_ranges_find(benchmark::State& state) {
- using T = Container::value_type;
-
- Container vec1(state.range(), '1');
- std::mt19937_64 rng(std::random_device{}());
-
- for (auto _ : state) {
- auto idx = rng() % vec1.size();
- vec1[idx] = '2';
- benchmark::DoNotOptimize(vec1);
- benchmark::DoNotOptimize(std::ranges::find(vec1, T('2')));
- vec1[idx] = '1';
- }
-}
-BENCHMARK(bm_ranges_find<std::vector<char>>)->DenseRange(1, 8)->Range(16, 1 << 20);
-BENCHMARK(bm_ranges_find<std::vector<short>>)->DenseRange(1, 8)->Range(16, 1 << 20);
-BENCHMARK(bm_ranges_find<std::vector<int>>)->DenseRange(1, 8)->Range(16, 1 << 20);
-BENCHMARK(bm_ranges_find<std::deque<char>>)->DenseRange(1, 8)->Range(16, 1 << 20);
-BENCHMARK(bm_ranges_find<std::deque<short>>)->DenseRange(1, 8)->Range(16, 1 << 20);
-BENCHMARK(bm_ranges_find<std::deque<int>>)->DenseRange(1, 8)->Range(16, 1 << 20);
-
-static void bm_vector_bool_find(benchmark::State& state) {
- std::vector<bool> vec1(state.range(), false);
- std::mt19937_64 rng(std::random_device{}());
-
- for (auto _ : state) {
- auto idx = rng() % vec1.size();
- vec1[idx] = true;
- benchmark::DoNotOptimize(vec1);
- benchmark::DoNotOptimize(std::find(vec1.begin(), vec1.end(), true));
- vec1[idx] = false;
- }
-}
-BENCHMARK(bm_vector_bool_find)->DenseRange(1, 8)->Range(16, 1 << 20);
-
-static void bm_vector_bool_ranges_find(benchmark::State& state) {
- std::vector<bool> vec1(state.range(), false);
- std::mt19937_64 rng(std::random_device{}());
-
- for (auto _ : state) {
- auto idx = rng() % vec1.size();
- vec1[idx] = true;
- benchmark::DoNotOptimize(vec1);
- benchmark::DoNotOptimize(std::ranges::find(vec1, true));
- vec1[idx] = false;
- }
-}
-BENCHMARK(bm_vector_bool_ranges_find)->DenseRange(1, 8)->Range(16, 1 << 20);
-
-BENCHMARK_MAIN();
diff --git a/libcxx/test/benchmarks/algorithms/for_each.bench.cpp b/libcxx/test/benchmarks/algorithms/for_each.bench.cpp
deleted file mode 100644
index 554c9ec993043..0000000000000
--- a/libcxx/test/benchmarks/algorithms/for_each.bench.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03, c++11, c++14
-
-#include <algorithm>
-#include <benchmark/benchmark.h>
-#include <deque>
-
-static void bm_deque_for_each(benchmark::State& state) {
- std::deque<char> vec1(state.range(), '1');
- for (auto _ : state) {
- benchmark::DoNotOptimize(vec1);
- benchmark::DoNotOptimize(
- std::for_each(vec1.begin(), vec1.end(), [](char& v) { v = std::clamp(v, (char)10, (char)100); }));
- }
-}
-BENCHMARK(bm_deque_for_each)->DenseRange(1, 8)->Range(16, 1 << 20);
-
-BENCHMARK_MAIN();
diff --git a/libcxx/test/benchmarks/algorithms/mismatch.bench.cpp b/libcxx/test/benchmarks/algorithms/mismatch.bench.cpp
deleted file mode 100644
index 348009a230d6e..0000000000000
--- a/libcxx/test/benchmarks/algorithms/mismatch.bench.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03, c++11, c++14
-
-#include <algorithm>
-#include <benchmark/benchmark.h>
-#include <random>
-
-void BenchmarkSizes(benchmark::internal::Benchmark* Benchmark) {
- Benchmark->DenseRange(1, 8);
- for (size_t i = 16; i != 1 << 20; i *= 2) {
- Benchmark->Arg(i - 1);
- Benchmark->Arg(i);
- Benchmark->Arg(i + 1);
- }
-}
-
-// TODO: Look into benchmarking aligned and unaligned memory explicitly
-// (currently things happen to be aligned because they are malloced that way)
-template <class T>
-static void bm_mismatch(benchmark::State& state) {
- std::vector<T> vec1(state.range(), '1');
- std::vector<T> vec2(state.range(), '1');
- std::mt19937_64 rng(std::random_device{}());
-
- vec1.back() = '2';
- for (auto _ : state) {
- benchmark::DoNotOptimize(vec1);
- benchmark::DoNotOptimize(std::mismatch(vec1.begin(), vec1.end(), vec2.begin()));
- }
-}
-BENCHMARK(bm_mismatch<char>)->Apply(BenchmarkSizes);
-BENCHMARK(bm_mismatch<short>)->Apply(BenchmarkSizes);
-BENCHMARK(bm_mismatch<int>)->Apply(BenchmarkSizes);
-
-template <class T>
-static void bm_mismatch_two_range_overload(benchmark::State& state) {
- std::vector<T> vec1(state.range(), '1');
- std::vector<T> vec2(state.range(), '1');
- std::mt19937_64 rng(std::random_device{}());
-
- vec1.back() = '2';
- for (auto _ : state) {
- benchmark::DoNotOptimize(vec1);
- benchmark::DoNotOptimize(std::mismatch(vec1.begin(), vec1.end(), vec2.begin(), vec2.end()));
- }
-}
-BENCHMARK(bm_mismatch_two_range_overload<char>)->DenseRange(1, 8)->Range(16, 1 << 20);
-BENCHMARK(bm_mismatch_two_range_overload<short>)->DenseRange(1, 8)->Range(16, 1 << 20);
-BENCHMARK(bm_mismatch_two_range_overload<int>)->DenseRange(1, 8)->Range(16, 1 << 20);
-
-BENCHMARK_MAIN();
diff --git a/libcxx/test/benchmarks/algorithms/nonmodifying/adjacent_find.bench.cpp b/libcxx/test/benchmarks/algorithms/nonmodifying/adjacent_find.bench.cpp
new file mode 100644
index 0000000000000..2bfdffdabdf02
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/nonmodifying/adjacent_find.bench.cpp
@@ -0,0 +1,88 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <algorithm>
+#include <cstddef>
+#include <deque>
+#include <list>
+#include <string>
+#include <vector>
+
+#include <benchmark/benchmark.h>
+#include "../../GenerateInput.h"
+
+int main(int argc, char** argv) {
+ auto std_adjacent_find = [](auto first, auto last) { return std::adjacent_find(first, last); };
+ auto std_adjacent_find_pred = [](auto first, auto last) {
+ return std::adjacent_find(first, last, [](auto x, auto y) {
+ benchmark::DoNotOptimize(x);
+ benchmark::DoNotOptimize(y);
+ return x == y;
+ });
+ };
+ auto ranges_adjacent_find_pred = [](auto first, auto last) {
+ return std::ranges::adjacent_find(first, last, [](auto x, auto y) {
+ benchmark::DoNotOptimize(x);
+ benchmark::DoNotOptimize(y);
+ return x == y;
+ });
+ };
+
+ // Benchmark {std,ranges}::adjacent_find on a sequence of the form xyxyxyxyxyxyxyxyxyxy,
+ // which means we never find adjacent equal elements (the worst case of the algorithm).
+ {
+ auto bm = []<class Container>(std::string name, auto adjacent_find) {
+ benchmark::RegisterBenchmark(
+ name,
+ [adjacent_find](auto& st) {
+ std::size_t const size = st.range(0);
+ using ValueType = typename Container::value_type;
+ ValueType x = Generate<ValueType>::random();
+ ValueType y = random_
diff erent_from({x});
+ Container c;
+ for (std::size_t i = 0; i != size; ++i) {
+ c.push_back(i % 2 == 0 ? x : y);
+ }
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(c);
+ auto result = adjacent_find(c.begin(), c.end());
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(8)
+ ->Arg(50) // non power-of-two
+ ->Arg(1024)
+ ->Arg(8192)
+ ->Arg(1 << 20);
+ };
+
+ // {std,ranges}::adjacent_find
+ bm.operator()<std::vector<int>>("std::adjacent_find(vector<int>)", std_adjacent_find);
+ bm.operator()<std::deque<int>>("std::adjacent_find(deque<int>)", std_adjacent_find);
+ bm.operator()<std::list<int>>("std::adjacent_find(list<int>)", std_adjacent_find);
+ bm.operator()<std::vector<int>>("rng::adjacent_find(vector<int>)", std::ranges::adjacent_find);
+ bm.operator()<std::deque<int>>("rng::adjacent_find(deque<int>)", std::ranges::adjacent_find);
+ bm.operator()<std::list<int>>("rng::adjacent_find(list<int>)", std::ranges::adjacent_find);
+
+ // {std,ranges}::adjacent_find(pred)
+ bm.operator()<std::vector<int>>("std::adjacent_find(vector<int>, pred)", std_adjacent_find_pred);
+ bm.operator()<std::deque<int>>("std::adjacent_find(deque<int>, pred)", std_adjacent_find_pred);
+ bm.operator()<std::list<int>>("std::adjacent_find(list<int>, pred)", std_adjacent_find_pred);
+ bm.operator()<std::vector<int>>("rng::adjacent_find(vector<int>, pred)", ranges_adjacent_find_pred);
+ bm.operator()<std::deque<int>>("rng::adjacent_find(deque<int>, pred)", ranges_adjacent_find_pred);
+ bm.operator()<std::list<int>>("rng::adjacent_find(list<int>, pred)", ranges_adjacent_find_pred);
+ }
+
+ benchmark::Initialize(&argc, argv);
+ benchmark::RunSpecifiedBenchmarks();
+ benchmark::Shutdown();
+ return 0;
+}
diff --git a/libcxx/test/benchmarks/algorithms/nonmodifying/any_all_none_of.bench.cpp b/libcxx/test/benchmarks/algorithms/nonmodifying/any_all_none_of.bench.cpp
new file mode 100644
index 0000000000000..fb17ef12f1fce
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/nonmodifying/any_all_none_of.bench.cpp
@@ -0,0 +1,100 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <algorithm>
+#include <cstddef>
+#include <deque>
+#include <list>
+#include <numeric>
+#include <string>
+#include <vector>
+
+#include <benchmark/benchmark.h>
+#include "../../GenerateInput.h"
+
+int main(int argc, char** argv) {
+ auto std_any_of = [](auto first, auto last, auto pred) { return std::any_of(first, last, pred); };
+ auto std_all_of = [](auto first, auto last, auto pred) {
+ // match semantics of any_of
+ return !std::all_of(first, last, [pred](auto x) { return !pred(x); });
+ };
+ auto std_none_of = [](auto first, auto last, auto pred) {
+ // match semantics of any_of
+ return !std::none_of(first, last, pred);
+ };
+
+ auto ranges_all_of = [](auto first, auto last, auto pred) {
+ // match semantics of any_of
+ return !std::ranges::all_of(first, last, [pred](auto x) { return !pred(x); });
+ };
+ auto ranges_none_of = [](auto first, auto last, auto pred) {
+ // match semantics of any_of
+ return !std::ranges::none_of(first, last, pred);
+ };
+
+ // Benchmark {std,ranges}::{any_of,all_of,none_of} where we process the whole sequence,
+ // which is the worst case.
+ {
+ auto bm = []<class Container>(std::string name, auto any_of) {
+ benchmark::RegisterBenchmark(
+ name,
+ [any_of](auto& st) {
+ std::size_t const size = st.range(0);
+ using ValueType = typename Container::value_type;
+ ValueType x = Generate<ValueType>::random();
+ ValueType y = random_
diff erent_from({x});
+ Container c(size, x);
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(c);
+ auto result = any_of(c.begin(), c.end(), [&](auto element) {
+ benchmark::DoNotOptimize(element);
+ return element == y;
+ });
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(8)
+ ->Arg(32)
+ ->Arg(50) // non power-of-two
+ ->Arg(8192)
+ ->Arg(32768);
+ };
+
+ // any_of
+ bm.operator()<std::vector<int>>("std::any_of(vector<int>) (process all)", std_any_of);
+ bm.operator()<std::deque<int>>("std::any_of(deque<int>) (process all)", std_any_of);
+ bm.operator()<std::list<int>>("std::any_of(list<int>) (process all)", std_any_of);
+ bm.operator()<std::vector<int>>("rng::any_of(vector<int>) (process all)", std::ranges::any_of);
+ bm.operator()<std::deque<int>>("rng::any_of(deque<int>) (process all)", std::ranges::any_of);
+ bm.operator()<std::list<int>>("rng::any_of(list<int>) (process all)", std::ranges::any_of);
+
+ // all_of
+ bm.operator()<std::vector<int>>("std::all_of(vector<int>) (process all)", std_all_of);
+ bm.operator()<std::deque<int>>("std::all_of(deque<int>) (process all)", std_all_of);
+ bm.operator()<std::list<int>>("std::all_of(list<int>) (process all)", std_all_of);
+ bm.operator()<std::vector<int>>("rng::all_of(vector<int>) (process all)", ranges_all_of);
+ bm.operator()<std::deque<int>>("rng::all_of(deque<int>) (process all)", ranges_all_of);
+ bm.operator()<std::list<int>>("rng::all_of(list<int>) (process all)", ranges_all_of);
+
+ // none_of
+ bm.operator()<std::vector<int>>("std::none_of(vector<int>) (process all)", std_none_of);
+ bm.operator()<std::deque<int>>("std::none_of(deque<int>) (process all)", std_none_of);
+ bm.operator()<std::list<int>>("std::none_of(list<int>) (process all)", std_none_of);
+ bm.operator()<std::vector<int>>("rng::none_of(vector<int>) (process all)", ranges_none_of);
+ bm.operator()<std::deque<int>>("rng::none_of(deque<int>) (process all)", ranges_none_of);
+ bm.operator()<std::list<int>>("rng::none_of(list<int>) (process all)", ranges_none_of);
+ }
+
+ benchmark::Initialize(&argc, argv);
+ benchmark::RunSpecifiedBenchmarks();
+ benchmark::Shutdown();
+ return 0;
+}
diff --git a/libcxx/test/benchmarks/algorithms/nonmodifying/contains.bench.cpp b/libcxx/test/benchmarks/algorithms/nonmodifying/contains.bench.cpp
new file mode 100644
index 0000000000000..1bb9400113ef9
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/nonmodifying/contains.bench.cpp
@@ -0,0 +1,59 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+#include <algorithm>
+#include <cstddef>
+#include <deque>
+#include <iterator>
+#include <list>
+#include <vector>
+
+#include <benchmark/benchmark.h>
+#include "../../GenerateInput.h"
+
+int main(int argc, char** argv) {
+ // Benchmark ranges::contains where we process the whole sequence, which is the
+ // worst case.
+ {
+ auto bm = []<class Container>(std::string name) {
+ benchmark::RegisterBenchmark(
+ name,
+ [](auto& st) {
+ std::size_t const size = st.range(0);
+ using ValueType = typename Container::value_type;
+ ValueType x = Generate<ValueType>::random();
+ ValueType y = random_
diff erent_from({x});
+ Container c(size, x);
+ auto first = c.begin();
+ auto last = c.end();
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(c);
+ benchmark::DoNotOptimize(y);
+ auto result = std::ranges::contains(first, last, y);
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(8)
+ ->Arg(32)
+ ->Arg(50) // non power-of-two
+ ->Arg(8192)
+ ->Arg(1 << 20);
+ };
+ bm.operator()<std::vector<int>>("rng::contains(vector<int>) (process all)");
+ bm.operator()<std::deque<int>>("rng::contains(deque<int>) (process all)");
+ bm.operator()<std::list<int>>("rng::contains(list<int>) (process all)");
+ }
+
+ benchmark::Initialize(&argc, argv);
+ benchmark::RunSpecifiedBenchmarks();
+ benchmark::Shutdown();
+ return 0;
+}
diff --git a/libcxx/test/benchmarks/algorithms/nonmodifying/contains_subrange.bench.cpp b/libcxx/test/benchmarks/algorithms/nonmodifying/contains_subrange.bench.cpp
new file mode 100644
index 0000000000000..cce2e42142ab0
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/nonmodifying/contains_subrange.bench.cpp
@@ -0,0 +1,162 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <deque>
+#include <iterator>
+#include <list>
+#include <vector>
+
+#include <benchmark/benchmark.h>
+#include "../../GenerateInput.h"
+
+int main(int argc, char** argv) {
+ // Benchmark ranges::contains_subrange where we never find the needle, which is the
+ // worst case.
+ {
+ auto bm = []<class Container>(std::string name) {
+ benchmark::RegisterBenchmark(
+ name,
+ [](auto& st) {
+ std::size_t const size = st.range(0);
+ using ValueType = typename Container::value_type;
+ ValueType x = Generate<ValueType>::random();
+ ValueType y = random_
diff erent_from({x});
+ Container haystack(size, x);
+ std::size_t n = size / 10; // needle size is 10% of the haystack, but we'll never find it
+ assert(n > 0);
+ Container needle(n, y);
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(haystack);
+ benchmark::DoNotOptimize(needle);
+ auto result = std::ranges::contains_subrange(haystack, needle);
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(16)
+ ->Arg(32)
+ ->Arg(50) // non power-of-two
+ ->Arg(8192)
+ ->Arg(1 << 20);
+ };
+ bm.operator()<std::vector<int>>("rng::contains_subrange(vector<int>) (process all)");
+ bm.operator()<std::deque<int>>("rng::contains_subrange(deque<int>) (process all)");
+ bm.operator()<std::list<int>>("rng::contains_subrange(list<int>) (process all)");
+ }
+
+ // Benchmark ranges::contains_subrange where we intersperse "near matches" inside the haystack.
+ {
+ auto bm = []<class Container>(std::string name) {
+ benchmark::RegisterBenchmark(
+ name,
+ [](auto& st) {
+ std::size_t const size = st.range(0);
+ using ValueType = typename Container::value_type;
+ ValueType x = Generate<ValueType>::random();
+ ValueType y = random_
diff erent_from({x});
+ Container haystack(size, x);
+ std::size_t n = size / 10; // needle size is 10% of the haystack, but we'll never find it
+ assert(n > 0);
+ Container needle(n, y);
+
+ // intersperse near-matches inside the haystack
+ {
+ auto first = haystack.begin();
+ for (int i = 0; i != 10; ++i) {
+ first = std::copy_n(needle.begin(), n - 1, first);
+ ++first; // this causes the subsequence not to match because it has length n-1
+ }
+ }
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(haystack);
+ benchmark::DoNotOptimize(needle);
+ auto result = std::ranges::contains_subrange(haystack, needle);
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(1000) // non power-of-two
+ ->Arg(1024)
+ ->Arg(8192);
+ };
+ bm.operator()<std::vector<int>>("rng::contains_subrange(vector<int>) (near matches)");
+ bm.operator()<std::deque<int>>("rng::contains_subrange(deque<int>) (near matches)");
+ bm.operator()<std::list<int>>("rng::contains_subrange(list<int>) (near matches)");
+ }
+
+ // Special case: the two ranges are the same length (and they are equal, which is the worst case).
+ {
+ auto bm = []<class Container>(std::string name) {
+ benchmark::RegisterBenchmark(
+ name,
+ [](auto& st) {
+ std::size_t const size = st.range(0);
+ using ValueType = typename Container::value_type;
+ ValueType x = Generate<ValueType>::random();
+ Container haystack(size, x);
+ Container needle(size, x);
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(haystack);
+ benchmark::DoNotOptimize(needle);
+ auto result = std::ranges::contains_subrange(haystack, needle);
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(16)
+ ->Arg(32)
+ ->Arg(50) // non power-of-two
+ ->Arg(8192)
+ ->Arg(1 << 20);
+ };
+ bm.operator()<std::vector<int>>("rng::contains_subrange(vector<int>) (same length)");
+ bm.operator()<std::deque<int>>("rng::contains_subrange(deque<int>) (same length)");
+ bm.operator()<std::list<int>>("rng::contains_subrange(list<int>) (same length)");
+ }
+
+ // Special case: the needle contains a single element (which we never find, i.e. the worst case).
+ {
+ auto bm = []<class Container>(std::string name) {
+ benchmark::RegisterBenchmark(
+ name,
+ [](auto& st) {
+ std::size_t const size = st.range(0);
+ using ValueType = typename Container::value_type;
+ ValueType x = Generate<ValueType>::random();
+ ValueType y = random_
diff erent_from({x});
+ Container haystack(size, x);
+ Container needle(1, y);
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(haystack);
+ benchmark::DoNotOptimize(needle);
+ auto result = std::ranges::contains_subrange(haystack, needle);
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(16)
+ ->Arg(32)
+ ->Arg(50) // non power-of-two
+ ->Arg(8192)
+ ->Arg(1 << 20);
+ };
+ bm.operator()<std::vector<int>>("rng::contains_subrange(vector<int>) (single element)");
+ bm.operator()<std::deque<int>>("rng::contains_subrange(deque<int>) (single element)");
+ bm.operator()<std::list<int>>("rng::contains_subrange(list<int>) (single element)");
+ }
+
+ benchmark::Initialize(&argc, argv);
+ benchmark::RunSpecifiedBenchmarks();
+ benchmark::Shutdown();
+ return 0;
+}
diff --git a/libcxx/test/benchmarks/algorithms/nonmodifying/count.bench.cpp b/libcxx/test/benchmarks/algorithms/nonmodifying/count.bench.cpp
new file mode 100644
index 0000000000000..c90b23eda8672
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/nonmodifying/count.bench.cpp
@@ -0,0 +1,111 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <algorithm>
+#include <cstddef>
+#include <deque>
+#include <list>
+#include <string>
+#include <vector>
+
+#include <benchmark/benchmark.h>
+#include "../../GenerateInput.h"
+
+int main(int argc, char** argv) {
+ auto std_count = [](auto first, auto last, auto const& value) { return std::count(first, last, value); };
+ auto std_count_if = [](auto first, auto last, auto const& value) {
+ return std::count_if(first, last, [&](auto element) {
+ benchmark::DoNotOptimize(element);
+ return element == value;
+ });
+ };
+
+ auto ranges_count = [](auto first, auto last, auto const& value) { return std::ranges::count(first, last, value); };
+ auto ranges_count_if = [](auto first, auto last, auto const& value) {
+ return std::ranges::count_if(first, last, [&](auto element) {
+ benchmark::DoNotOptimize(element);
+ return element == value;
+ });
+ };
+
+ // Benchmark {std,ranges}::{count,count_if} on a sequence where every other element is counted.
+ {
+ auto bm = []<class Container>(std::string name, auto count) {
+ benchmark::RegisterBenchmark(
+ name,
+ [count](auto& st) {
+ std::size_t const size = st.range(0);
+ using ValueType = typename Container::value_type;
+ ValueType x = Generate<ValueType>::random();
+ ValueType y = random_
diff erent_from({x});
+ Container c;
+ for (std::size_t i = 0; i != size; ++i) {
+ c.push_back(i % 2 == 0 ? x : y);
+ }
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(c);
+ benchmark::DoNotOptimize(x);
+ auto result = count(c.begin(), c.end(), x);
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(8)
+ ->Arg(1024)
+ ->Arg(8192)
+ ->Arg(1 << 20);
+ };
+
+ // count
+ bm.operator()<std::vector<int>>("std::count(vector<int>) (every other)", std_count);
+ bm.operator()<std::deque<int>>("std::count(deque<int>) (every other)", std_count);
+ bm.operator()<std::list<int>>("std::count(list<int>) (every other)", std_count);
+ bm.operator()<std::vector<int>>("rng::count(vector<int>) (every other)", ranges_count);
+ bm.operator()<std::deque<int>>("rng::count(deque<int>) (every other)", ranges_count);
+ bm.operator()<std::list<int>>("rng::count(list<int>) (every other)", ranges_count);
+
+ // count_if
+ bm.operator()<std::vector<int>>("std::count_if(vector<int>) (every other)", std_count_if);
+ bm.operator()<std::deque<int>>("std::count_if(deque<int>) (every other)", std_count_if);
+ bm.operator()<std::list<int>>("std::count_if(list<int>) (every other)", std_count_if);
+ bm.operator()<std::vector<int>>("rng::count_if(vector<int>) (every other)", ranges_count_if);
+ bm.operator()<std::deque<int>>("rng::count_if(deque<int>) (every other)", ranges_count_if);
+ bm.operator()<std::list<int>>("rng::count_if(list<int>) (every other)", ranges_count_if);
+ }
+
+ // Benchmark {std,ranges}::count(vector<bool>)
+ {
+ auto bm = [](std::string name, auto count) {
+ benchmark::RegisterBenchmark(
+ name,
+ [count](auto& st) {
+ std::size_t const size = st.range(0);
+ std::vector<bool> c(size, false);
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(c);
+ auto result = count(c.begin(), c.end(), true);
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(1000) // non power-of-two
+ ->Arg(1024)
+ ->Arg(8192)
+ ->Arg(1 << 20);
+ };
+ bm.operator()("std::count(vector<bool>)", std_count);
+ bm.operator()("rng::count(vector<bool>)", ranges_count);
+ }
+
+ benchmark::Initialize(&argc, argv);
+ benchmark::RunSpecifiedBenchmarks();
+ benchmark::Shutdown();
+ return 0;
+}
diff --git a/libcxx/test/benchmarks/algorithms/nonmodifying/ends_with.bench.cpp b/libcxx/test/benchmarks/algorithms/nonmodifying/ends_with.bench.cpp
new file mode 100644
index 0000000000000..0c01833453156
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/nonmodifying/ends_with.bench.cpp
@@ -0,0 +1,118 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <deque>
+#include <forward_list>
+#include <list>
+#include <string>
+#include <vector>
+
+#include <benchmark/benchmark.h>
+#include "../../GenerateInput.h"
+
+int main(int argc, char** argv) {
+ auto ranges_ends_with_pred = [](auto first1, auto last1, auto first2, auto last2) {
+ return std::ranges::ends_with(first1, last1, first2, last2, [](auto x, auto y) {
+ benchmark::DoNotOptimize(x);
+ benchmark::DoNotOptimize(y);
+ return x == y;
+ });
+ };
+
+ // Benchmark ranges::ends_with where we find the mismatching element at the very end.
+ {
+ auto bm = []<class Container>(std::string name, auto ends_with) {
+ benchmark::RegisterBenchmark(
+ name,
+ [ends_with](auto& st) {
+ std::size_t const size = st.range(0);
+ using ValueType = typename Container::value_type;
+ ValueType x = Generate<ValueType>::random();
+ ValueType y = random_
diff erent_from({x});
+ Container c1(size, x);
+ Container c2(size, x);
+ assert(size != 0);
+ *std::next(c2.begin(), size - 1) = y; // set last element to y
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(c1);
+ benchmark::DoNotOptimize(c2);
+ auto result = ends_with(c1.begin(), c1.end(), c2.begin(), c2.end());
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(8)
+ ->Arg(50) // non power-of-two
+ ->Arg(1024)
+ ->Arg(8192)
+ ->Arg(1 << 20);
+ };
+ bm.operator()<std::vector<int>>("rng::ends_with(vector<int>) (mismatch at end)", std::ranges::ends_with);
+ bm.operator()<std::deque<int>>("rng::ends_with(deque<int>) (mismatch at end)", std::ranges::ends_with);
+ bm.operator()<std::list<int>>("rng::ends_with(list<int>) (mismatch at end)", std::ranges::ends_with);
+ bm.operator()<std::forward_list<int>>(
+ "rng::ends_with(forward_list<int>) (mismatch at end)", std::ranges::ends_with);
+
+ bm.operator()<std::vector<int>>("rng::ends_with(vector<int>, pred) (mismatch at end)", ranges_ends_with_pred);
+ bm.operator()<std::deque<int>>("rng::ends_with(deque<int>, pred) (mismatch at end)", ranges_ends_with_pred);
+ bm.operator()<std::list<int>>("rng::ends_with(list<int>, pred) (mismatch at end)", ranges_ends_with_pred);
+ bm.operator()<std::forward_list<int>>(
+ "rng::ends_with(forward_list<int>, pred) (mismatch at end)", ranges_ends_with_pred);
+ }
+
+ // Benchmark ranges::ends_with where we find the mismatching element at the very beginning.
+ {
+ auto bm = []<class Container>(std::string name, auto ends_with) {
+ benchmark::RegisterBenchmark(
+ name,
+ [ends_with](auto& st) {
+ std::size_t const size = st.range(0);
+ using ValueType = typename Container::value_type;
+ ValueType x = Generate<ValueType>::random();
+ ValueType y = random_
diff erent_from({x});
+ Container c1(size, x);
+ Container c2(size, x);
+ assert(size != 0);
+ c2.front() = y;
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(c1);
+ benchmark::DoNotOptimize(c2);
+ auto result = ends_with(c1.begin(), c1.end(), c2.begin(), c2.end());
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(8)
+ ->Arg(50) // non power-of-two
+ ->Arg(1024)
+ ->Arg(8192)
+ ->Arg(1 << 20);
+ };
+ bm.operator()<std::vector<int>>("rng::ends_with(vector<int>) (mismatch at start)", std::ranges::ends_with);
+ bm.operator()<std::deque<int>>("rng::ends_with(deque<int>) (mismatch at start)", std::ranges::ends_with);
+ bm.operator()<std::list<int>>("rng::ends_with(list<int>) (mismatch at start)", std::ranges::ends_with);
+ bm.operator()<std::forward_list<int>>(
+ "rng::ends_with(forward_list<int>) (mismatch at start)", std::ranges::ends_with);
+
+ bm.operator()<std::vector<int>>("rng::ends_with(vector<int>, pred) (mismatch at start)", ranges_ends_with_pred);
+ bm.operator()<std::deque<int>>("rng::ends_with(deque<int>, pred) (mismatch at start)", ranges_ends_with_pred);
+ bm.operator()<std::list<int>>("rng::ends_with(list<int>, pred) (mismatch at start)", ranges_ends_with_pred);
+ bm.operator()<std::forward_list<int>>(
+ "rng::ends_with(forward_list<int>, pred) (mismatch at start)", ranges_ends_with_pred);
+ }
+
+ benchmark::Initialize(&argc, argv);
+ benchmark::RunSpecifiedBenchmarks();
+ benchmark::Shutdown();
+ return 0;
+}
diff --git a/libcxx/test/benchmarks/algorithms/nonmodifying/equal.bench.cpp b/libcxx/test/benchmarks/algorithms/nonmodifying/equal.bench.cpp
new file mode 100644
index 0000000000000..4da164d5f0f94
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/nonmodifying/equal.bench.cpp
@@ -0,0 +1,143 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <algorithm>
+#include <cstddef>
+#include <deque>
+#include <list>
+#include <string>
+#include <vector>
+
+#include <benchmark/benchmark.h>
+#include "../../GenerateInput.h"
+
+int main(int argc, char** argv) {
+ auto std_equal_3leg = [](auto first1, auto last1, auto first2, auto) { return std::equal(first1, last1, first2); };
+ auto std_equal_4leg = [](auto first1, auto last1, auto first2, auto last2) {
+ return std::equal(first1, last1, first2, last2);
+ };
+ auto std_equal_3leg_pred = [](auto first1, auto last1, auto first2, auto) {
+ return std::equal(first1, last1, first2, [](auto x, auto y) {
+ benchmark::DoNotOptimize(x);
+ benchmark::DoNotOptimize(y);
+ return x == y;
+ });
+ };
+ auto std_equal_4leg_pred = [](auto first1, auto last1, auto first2, auto last2) {
+ return std::equal(first1, last1, first2, last2, [](auto x, auto y) {
+ benchmark::DoNotOptimize(x);
+ benchmark::DoNotOptimize(y);
+ return x == y;
+ });
+ };
+ auto ranges_equal_4leg_pred = [](auto first1, auto last1, auto first2, auto last2) {
+ return std::ranges::equal(first1, last1, first2, last2, [](auto x, auto y) {
+ benchmark::DoNotOptimize(x);
+ benchmark::DoNotOptimize(y);
+ return x == y;
+ });
+ };
+
+ // Benchmark {std,ranges}::equal where we determine inequality at the very end (worst case).
+ {
+ auto bm = []<class Container>(std::string name, auto equal) {
+ benchmark::RegisterBenchmark(
+ name,
+ [equal](auto& st) {
+ std::size_t const size = st.range(0);
+ using ValueType = typename Container::value_type;
+ ValueType x = Generate<ValueType>::random();
+ ValueType y = random_
diff erent_from({x});
+ Container c1(size, x);
+ Container c2(size, x);
+ c2.back() = y;
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(c1);
+ benchmark::DoNotOptimize(c2);
+ auto result = equal(c1.begin(), c1.end(), c2.begin(), c2.end());
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(8)
+ ->Arg(50) // non power-of-two
+ ->Arg(1024)
+ ->Arg(8192)
+ ->Arg(1 << 20);
+ };
+
+ // std::equal(it, it, it)
+ bm.operator()<std::vector<int>>("std::equal(vector<int>) (it, it, it)", std_equal_3leg);
+ bm.operator()<std::deque<int>>("std::equal(deque<int>) (it, it, it)", std_equal_3leg);
+ bm.operator()<std::list<int>>("std::equal(list<int>) (it, it, it)", std_equal_3leg);
+
+ // std::equal(it, it, it, pred)
+ bm.operator()<std::vector<int>>("std::equal(vector<int>) (it, it, it, pred)", std_equal_3leg_pred);
+ bm.operator()<std::deque<int>>("std::equal(deque<int>) (it, it, it, pred)", std_equal_3leg_pred);
+ bm.operator()<std::list<int>>("std::equal(list<int>) (it, it, it, pred)", std_equal_3leg_pred);
+
+ // {std,ranges}::equal(it, it, it, it)
+ bm.operator()<std::vector<int>>("std::equal(vector<int>) (it, it, it, it)", std_equal_4leg);
+ bm.operator()<std::deque<int>>("std::equal(deque<int>) (it, it, it, it)", std_equal_4leg);
+ bm.operator()<std::list<int>>("std::equal(list<int>) (it, it, it, it)", std_equal_4leg);
+ bm.operator()<std::vector<int>>("rng::equal(vector<int>) (it, it, it, it)", std::ranges::equal);
+ bm.operator()<std::deque<int>>("rng::equal(deque<int>) (it, it, it, it)", std::ranges::equal);
+ bm.operator()<std::list<int>>("rng::equal(list<int>) (it, it, it, it)", std::ranges::equal);
+
+ // {std,ranges}::equal(it, it, it, it, pred)
+ bm.operator()<std::vector<int>>("std::equal(vector<int>) (it, it, it, it, pred)", std_equal_4leg_pred);
+ bm.operator()<std::deque<int>>("std::equal(deque<int>) (it, it, it, it, pred)", std_equal_4leg_pred);
+ bm.operator()<std::list<int>>("std::equal(list<int>) (it, it, it, it, pred)", std_equal_4leg_pred);
+ bm.operator()<std::vector<int>>("rng::equal(vector<int>) (it, it, it, it, pred)", ranges_equal_4leg_pred);
+ bm.operator()<std::deque<int>>("rng::equal(deque<int>) (it, it, it, it, pred)", ranges_equal_4leg_pred);
+ bm.operator()<std::list<int>>("rng::equal(list<int>) (it, it, it, it, pred)", ranges_equal_4leg_pred);
+ }
+
+ // Benchmark {std,ranges}::equal on vector<bool>.
+ {
+ auto bm = [](std::string name, auto equal, bool aligned) {
+ benchmark::RegisterBenchmark(
+ name,
+ [=](auto& st) {
+ std::size_t const size = st.range();
+ std::vector<bool> c1(size, true);
+ std::vector<bool> c2(size + 8, true);
+ auto first1 = c1.begin();
+ auto last1 = c1.end();
+ auto first2 = aligned ? c2.begin() : c2.begin() + 4;
+ auto last2 = aligned ? c2.end() : c2.end() - 4;
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(c1);
+ benchmark::DoNotOptimize(c2);
+ auto result = equal(first1, last1, first2, last2);
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(8)
+ ->Arg(50) // non power-of-two
+ ->Arg(1024)
+ ->Arg(8192)
+ ->Arg(1 << 20);
+ };
+
+ // {std,ranges}::equal(vector<bool>) (aligned)
+ bm("std::equal(vector<bool>) (aligned)", std_equal_4leg, true);
+ bm("rng::equal(vector<bool>) (aligned)", std::ranges::equal, true);
+
+ // {std,ranges}::equal(vector<bool>) (unaligned)
+ bm("std::equal(vector<bool>) (unaligned)", std_equal_4leg, false);
+ bm("rng::equal(vector<bool>) (unaligned)", std::ranges::equal, false);
+ }
+
+ benchmark::Initialize(&argc, argv);
+ benchmark::RunSpecifiedBenchmarks();
+ benchmark::Shutdown();
+ return 0;
+}
diff --git a/libcxx/test/benchmarks/algorithms/nonmodifying/find.bench.cpp b/libcxx/test/benchmarks/algorithms/nonmodifying/find.bench.cpp
new file mode 100644
index 0000000000000..b2ead1cc75585
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/nonmodifying/find.bench.cpp
@@ -0,0 +1,181 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <algorithm>
+#include <cstddef>
+#include <deque>
+#include <list>
+#include <string>
+#include <vector>
+
+#include <benchmark/benchmark.h>
+#include "../../GenerateInput.h"
+
+int main(int argc, char** argv) {
+ auto std_find = [](auto first, auto last, auto const& value) { return std::find(first, last, value); };
+ auto std_find_if = [](auto first, auto last, auto const& value) {
+ return std::find_if(first, last, [&](auto element) {
+ benchmark::DoNotOptimize(element);
+ return element == value;
+ });
+ };
+ auto std_find_if_not = [](auto first, auto last, auto const& value) {
+ return std::find_if_not(first, last, [&](auto element) {
+ benchmark::DoNotOptimize(element);
+ return element != value;
+ });
+ };
+
+ auto ranges_find = [](auto first, auto last, auto const& value) { return std::ranges::find(first, last, value); };
+ auto ranges_find_if = [](auto first, auto last, auto const& value) {
+ return std::ranges::find_if(first, last, [&](auto element) {
+ benchmark::DoNotOptimize(element);
+ return element == value;
+ });
+ };
+ auto ranges_find_if_not = [](auto first, auto last, auto const& value) {
+ return std::ranges::find_if_not(first, last, [&](auto element) {
+ benchmark::DoNotOptimize(element);
+ return element != value;
+ });
+ };
+
+ auto register_benchmarks = [&](auto bm, std::string comment) {
+ // find
+ bm.template operator()<std::vector<char>>("std::find(vector<char>) (" + comment + ")", std_find);
+ bm.template operator()<std::vector<int>>("std::find(vector<int>) (" + comment + ")", std_find);
+ bm.template operator()<std::deque<int>>("std::find(deque<int>) (" + comment + ")", std_find);
+ bm.template operator()<std::list<int>>("std::find(list<int>) (" + comment + ")", std_find);
+
+ bm.template operator()<std::vector<char>>("rng::find(vector<char>) (" + comment + ")", ranges_find);
+ bm.template operator()<std::vector<int>>("rng::find(vector<int>) (" + comment + ")", ranges_find);
+ bm.template operator()<std::deque<int>>("rng::find(deque<int>) (" + comment + ")", ranges_find);
+ bm.template operator()<std::list<int>>("rng::find(list<int>) (" + comment + ")", ranges_find);
+
+ // find_if
+ bm.template operator()<std::vector<char>>("std::find_if(vector<char>) (" + comment + ")", std_find_if);
+ bm.template operator()<std::vector<int>>("std::find_if(vector<int>) (" + comment + ")", std_find_if);
+ bm.template operator()<std::deque<int>>("std::find_if(deque<int>) (" + comment + ")", std_find_if);
+ bm.template operator()<std::list<int>>("std::find_if(list<int>) (" + comment + ")", std_find_if);
+
+ bm.template operator()<std::vector<char>>("rng::find_if(vector<char>) (" + comment + ")", ranges_find_if);
+ bm.template operator()<std::vector<int>>("rng::find_if(vector<int>) (" + comment + ")", ranges_find_if);
+ bm.template operator()<std::deque<int>>("rng::find_if(deque<int>) (" + comment + ")", ranges_find_if);
+ bm.template operator()<std::list<int>>("rng::find_if(list<int>) (" + comment + ")", ranges_find_if);
+
+ // find_if_not
+ bm.template operator()<std::vector<char>>("std::find_if_not(vector<char>) (" + comment + ")", std_find_if_not);
+ bm.template operator()<std::vector<int>>("std::find_if_not(vector<int>) (" + comment + ")", std_find_if_not);
+ bm.template operator()<std::deque<int>>("std::find_if_not(deque<int>) (" + comment + ")", std_find_if_not);
+ bm.template operator()<std::list<int>>("std::find_if_not(list<int>) (" + comment + ")", std_find_if_not);
+
+ bm.template operator()<std::vector<char>>("rng::find_if_not(vector<char>) (" + comment + ")", ranges_find_if_not);
+ bm.template operator()<std::vector<int>>("rng::find_if_not(vector<int>) (" + comment + ")", ranges_find_if_not);
+ bm.template operator()<std::deque<int>>("rng::find_if_not(deque<int>) (" + comment + ")", ranges_find_if_not);
+ bm.template operator()<std::list<int>>("rng::find_if_not(list<int>) (" + comment + ")", ranges_find_if_not);
+ };
+
+ // Benchmark {std,ranges}::{find,find_if,find_if_not}(normal container) where we
+ // bail out after 25% of elements
+ {
+ auto bm = []<class Container>(std::string name, auto find) {
+ benchmark::RegisterBenchmark(
+ name,
+ [find](auto& st) {
+ std::size_t const size = st.range(0);
+ using ValueType = typename Container::value_type;
+ ValueType x = Generate<ValueType>::random();
+ ValueType y = random_
diff erent_from({x});
+ Container c(size, x);
+
+ // put the element we're searching for at 25% of the sequence
+ *std::next(c.begin(), size / 4) = y;
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(c);
+ benchmark::DoNotOptimize(y);
+ auto result = find(c.begin(), c.end(), y);
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(8)
+ ->Arg(1024)
+ ->Arg(8192)
+ ->Arg(1 << 15);
+ };
+ register_benchmarks(bm, "bail 25%");
+ }
+
+ // Benchmark {std,ranges}::{find,find_if,find_if_not}(normal container) where we process the whole sequence
+ {
+ auto bm = []<class Container>(std::string name, auto find) {
+ benchmark::RegisterBenchmark(
+ name,
+ [find](auto& st) {
+ std::size_t const size = st.range(0);
+ using ValueType = typename Container::value_type;
+ ValueType x = Generate<ValueType>::random();
+ ValueType y = random_
diff erent_from({x});
+ Container c(size, x);
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(c);
+ benchmark::DoNotOptimize(y);
+ auto result = find(c.begin(), c.end(), y);
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(8)
+ ->Arg(50) // non power-of-two
+ ->Arg(1024)
+ ->Arg(8192)
+ ->Arg(1 << 15);
+ };
+ register_benchmarks(bm, "process all");
+ }
+
+ // Benchmark {std,ranges}::{find,find_if,find_if_not}(vector<bool>) where we process the whole sequence
+ {
+ auto bm = [](std::string name, auto find) {
+ benchmark::RegisterBenchmark(
+ name,
+ [find](auto& st) {
+ std::size_t const size = st.range(0);
+ std::vector<bool> c(size, true);
+ bool y = false;
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(c);
+ benchmark::DoNotOptimize(y);
+ auto result = find(c.begin(), c.end(), y);
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(8)
+ ->Arg(50) // non power-of-two
+ ->Arg(1024)
+ ->Arg(8192)
+ ->Arg(1 << 20);
+ };
+ bm("std::find(vector<bool>) (process all)", std_find);
+ bm("rng::find(vector<bool>) (process all)", ranges_find);
+
+ bm("std::find_if(vector<bool>) (process all)", std_find_if);
+ bm("rng::find_if(vector<bool>) (process all)", ranges_find_if);
+
+ bm("std::find_if_not(vector<bool>) (process all)", std_find_if_not);
+ bm("rng::find_if_not(vector<bool>) (process all)", ranges_find_if_not);
+ }
+
+ benchmark::Initialize(&argc, argv);
+ benchmark::RunSpecifiedBenchmarks();
+ benchmark::Shutdown();
+ return 0;
+}
diff --git a/libcxx/test/benchmarks/algorithms/nonmodifying/find_end.bench.cpp b/libcxx/test/benchmarks/algorithms/nonmodifying/find_end.bench.cpp
new file mode 100644
index 0000000000000..f1ad8a65c3235
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/nonmodifying/find_end.bench.cpp
@@ -0,0 +1,226 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <deque>
+#include <forward_list>
+#include <list>
+#include <string>
+#include <vector>
+
+#include <benchmark/benchmark.h>
+#include "../../GenerateInput.h"
+
+int main(int argc, char** argv) {
+ auto std_find_end = [](auto first1, auto last1, auto first2, auto last2) {
+ return std::find_end(first1, last1, first2, last2);
+ };
+ auto std_find_end_pred = [](auto first1, auto last1, auto first2, auto last2) {
+ return std::find_end(first1, last1, first2, last2, [](auto x, auto y) {
+ benchmark::DoNotOptimize(x);
+ benchmark::DoNotOptimize(y);
+ return x == y;
+ });
+ };
+ auto ranges_find_end_pred = [](auto first1, auto last1, auto first2, auto last2) {
+ return std::ranges::find_end(first1, last1, first2, last2, [](auto x, auto y) {
+ benchmark::DoNotOptimize(x);
+ benchmark::DoNotOptimize(y);
+ return x == y;
+ });
+ };
+
+ auto register_benchmarks = [&](auto bm, std::string comment) {
+ // {std,ranges}::find_end(it1, it1, it2, it2)
+ bm.template operator()<std::vector<int>>("std::find_end(vector<int>) (" + comment + ")", std_find_end);
+ bm.template operator()<std::deque<int>>("std::find_end(deque<int>) (" + comment + ")", std_find_end);
+ bm.template operator()<std::list<int>>("std::find_end(list<int>) (" + comment + ")", std_find_end);
+ bm.template operator()<std::forward_list<int>>("std::find_end(forward_list<int>) (" + comment + ")", std_find_end);
+ bm.template operator()<std::vector<int>>("rng::find_end(vector<int>) (" + comment + ")", std::ranges::find_end);
+ bm.template operator()<std::deque<int>>("rng::find_end(deque<int>) (" + comment + ")", std::ranges::find_end);
+ bm.template operator()<std::list<int>>("rng::find_end(list<int>) (" + comment + ")", std::ranges::find_end);
+ bm.template operator()<std::forward_list<int>>(
+ "rng::find_end(forward_list<int>) (" + comment + ")", std::ranges::find_end);
+
+ // {std,ranges}::find_end(it1, it1, it2, it2, pred)
+ bm.template operator()<std::vector<int>>("std::find_end(vector<int>, pred) (" + comment + ")", std_find_end_pred);
+ bm.template operator()<std::deque<int>>("std::find_end(deque<int>, pred) (" + comment + ")", std_find_end_pred);
+ bm.template operator()<std::list<int>>("std::find_end(list<int>, pred) (" + comment + ")", std_find_end_pred);
+ bm.template operator()<std::forward_list<int>>(
+ "std::find_end(forward_list<int>, pred) (" + comment + ")", std_find_end_pred);
+ bm.template operator()<std::vector<int>>(
+ "rng::find_end(vector<int>, pred) (" + comment + ")", ranges_find_end_pred);
+ bm.template operator()<std::deque<int>>("rng::find_end(deque<int>, pred) (" + comment + ")", ranges_find_end_pred);
+ bm.template operator()<std::list<int>>("rng::find_end(list<int>, pred) (" + comment + ")", ranges_find_end_pred);
+ bm.template operator()<std::forward_list<int>>(
+ "rng::find_end(forward_list<int>, pred) (" + comment + ")", ranges_find_end_pred);
+ };
+
+ // Benchmark {std,ranges}::find_end where we never find the needle, which is the
+ // worst case.
+ {
+ auto bm = []<class Container>(std::string name, auto find_end) {
+ benchmark::RegisterBenchmark(
+ name,
+ [find_end](auto& st) {
+ std::size_t const size = st.range(0);
+ using ValueType = typename Container::value_type;
+ ValueType x = Generate<ValueType>::random();
+ ValueType y = random_
diff erent_from({x});
+ Container haystack(size, x);
+ std::size_t n = size / 10; // needle size is 10% of the haystack, but we'll never find it
+ assert(n > 0);
+ Container needle(n, y);
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(haystack);
+ benchmark::DoNotOptimize(needle);
+ auto result = find_end(haystack.begin(), haystack.end(), needle.begin(), needle.end());
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(1000) // non power-of-two
+ ->Arg(1024)
+ ->Arg(8192)
+ ->Arg(1 << 20);
+ };
+ register_benchmarks(bm, "process all");
+ }
+
+ // Benchmark {std,ranges}::find_end where we intersperse "near matches" inside the haystack.
+ {
+ auto bm = []<class Container>(std::string name, auto find_end) {
+ benchmark::RegisterBenchmark(
+ name,
+ [find_end](auto& st) {
+ std::size_t const size = st.range(0);
+ using ValueType = typename Container::value_type;
+ ValueType x = Generate<ValueType>::random();
+ ValueType y = random_
diff erent_from({x});
+ Container haystack(size, x);
+ std::size_t n = size / 10; // needle size is 10% of the haystack
+ assert(n > 0);
+ Container needle(n, y);
+
+ // intersperse near-matches inside the haystack
+ {
+ auto first = haystack.begin();
+ for (int i = 0; i != 10; ++i) {
+ first = std::copy_n(needle.begin(), n - 1, first);
+ ++first; // this causes the subsequence not to match because it has length n-1
+ }
+ }
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(haystack);
+ benchmark::DoNotOptimize(needle);
+ auto result = find_end(haystack.begin(), haystack.end(), needle.begin(), needle.end());
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(1000) // non power-of-two
+ ->Arg(1024)
+ ->Arg(8192);
+ };
+ register_benchmarks(bm, "near matches");
+ }
+
+ // Special case: the two ranges are the same length (and they are equal, which is the worst case).
+ {
+ auto bm = []<class Container>(std::string name, auto find_end) {
+ benchmark::RegisterBenchmark(
+ name,
+ [find_end](auto& st) {
+ std::size_t const size = st.range(0);
+ using ValueType = typename Container::value_type;
+ ValueType x = Generate<ValueType>::random();
+ Container haystack(size, x);
+ Container needle(size, x);
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(haystack);
+ benchmark::DoNotOptimize(needle);
+ auto result = find_end(haystack.begin(), haystack.end(), needle.begin(), needle.end());
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(1000) // non power-of-two
+ ->Arg(1024)
+ ->Arg(8192);
+ };
+ register_benchmarks(bm, "same length");
+ }
+
+ // Special case: the needle contains a single element (which we never find, i.e. the worst case).
+ {
+ auto bm = []<class Container>(std::string name, auto find_end) {
+ benchmark::RegisterBenchmark(
+ name,
+ [find_end](auto& st) {
+ std::size_t const size = st.range(0);
+ using ValueType = typename Container::value_type;
+ ValueType x = Generate<ValueType>::random();
+ ValueType y = random_
diff erent_from({x});
+ Container haystack(size, x);
+ Container needle(1, y);
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(haystack);
+ benchmark::DoNotOptimize(needle);
+ auto result = find_end(haystack.begin(), haystack.end(), needle.begin(), needle.end());
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(1000) // non power-of-two
+ ->Arg(1024)
+ ->Arg(8192);
+ };
+ register_benchmarks(bm, "single element");
+ }
+
+ // Special case: we have a match close to the end of the haystack (ideal case if we start searching from the end).
+ {
+ auto bm = []<class Container>(std::string name, auto find_end) {
+ benchmark::RegisterBenchmark(
+ name,
+ [find_end](auto& st) {
+ std::size_t const size = st.range(0);
+ using ValueType = typename Container::value_type;
+ ValueType x = Generate<ValueType>::random();
+ ValueType y = random_
diff erent_from({x});
+ Container haystack(size, x);
+ std::size_t n = size / 10; // needle size is 10% of the haystack
+ assert(n > 0);
+ Container needle(n, y);
+
+ // put the needle at 90% of the haystack
+ std::ranges::copy(needle, std::next(haystack.begin(), (9 * size) / 10));
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(haystack);
+ benchmark::DoNotOptimize(needle);
+ auto result = find_end(haystack.begin(), haystack.end(), needle.begin(), needle.end());
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(1000) // non power-of-two
+ ->Arg(1024)
+ ->Arg(8192);
+ };
+ register_benchmarks(bm, "match near end");
+ }
+
+ benchmark::Initialize(&argc, argv);
+ benchmark::RunSpecifiedBenchmarks();
+ benchmark::Shutdown();
+ return 0;
+}
diff --git a/libcxx/test/benchmarks/algorithms/nonmodifying/find_first_of.bench.cpp b/libcxx/test/benchmarks/algorithms/nonmodifying/find_first_of.bench.cpp
new file mode 100644
index 0000000000000..fca1aaf233988
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/nonmodifying/find_first_of.bench.cpp
@@ -0,0 +1,133 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <algorithm>
+#include <cstddef>
+#include <deque>
+#include <initializer_list>
+#include <list>
+#include <string>
+#include <vector>
+
+#include <benchmark/benchmark.h>
+#include "../../GenerateInput.h"
+
+int main(int argc, char** argv) {
+ auto std_find_first_of = [](auto first1, auto last1, auto first2, auto last2) {
+ return std::find_first_of(first1, last1, first2, last2);
+ };
+ auto std_find_first_of_pred = [](auto first1, auto last1, auto first2, auto last2) {
+ return std::find_first_of(first1, last1, first2, last2, [](auto x, auto y) {
+ benchmark::DoNotOptimize(x);
+ benchmark::DoNotOptimize(y);
+ return x == y;
+ });
+ };
+ auto ranges_find_first_of_pred = [](auto first1, auto last1, auto first2, auto last2) {
+ return std::ranges::find_first_of(first1, last1, first2, last2, [](auto x, auto y) {
+ benchmark::DoNotOptimize(x);
+ benchmark::DoNotOptimize(y);
+ return x == y;
+ });
+ };
+
+ // Benchmark {std,ranges}::find_first_of where we never find a match in the needle, and the needle is small.
+ // This is the worst case of the most common case (a small needle).
+ {
+ auto bm = []<class Container>(std::string name, auto find_first_of) {
+ benchmark::RegisterBenchmark(
+ name,
+ [find_first_of](auto& st) {
+ std::size_t const size = st.range(0);
+ using ValueType = typename Container::value_type;
+ ValueType x = Generate<ValueType>::random();
+ ValueType y = random_
diff erent_from({x});
+ Container haystack(size, x);
+ Container needle(10, y);
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(haystack);
+ benchmark::DoNotOptimize(needle);
+ auto result = find_first_of(haystack.begin(), haystack.end(), needle.begin(), needle.end());
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(32)
+ ->Arg(50) // non power-of-two
+ ->Arg(1024)
+ ->Arg(8192);
+ };
+ // {std,ranges}::find_first_of(it1, it1, it2, it2)
+ bm.operator()<std::vector<int>>("std::find_first_of(vector<int>) (small needle)", std_find_first_of);
+ bm.operator()<std::deque<int>>("std::find_first_of(deque<int>) (small needle)", std_find_first_of);
+ bm.operator()<std::list<int>>("std::find_first_of(list<int>) (small needle)", std_find_first_of);
+ bm.operator()<std::vector<int>>("rng::find_first_of(vector<int>) (small needle)", std::ranges::find_first_of);
+ bm.operator()<std::deque<int>>("rng::find_first_of(deque<int>) (small needle)", std::ranges::find_first_of);
+ bm.operator()<std::list<int>>("rng::find_first_of(list<int>) (small needle)", std::ranges::find_first_of);
+
+ // {std,ranges}::find_first_of(it1, it1, it2, it2, pred)
+ bm.operator()<std::vector<int>>("std::find_first_of(vector<int>, pred) (small needle)", std_find_first_of_pred);
+ bm.operator()<std::deque<int>>("std::find_first_of(deque<int>, pred) (small needle)", std_find_first_of_pred);
+ bm.operator()<std::list<int>>("std::find_first_of(list<int>, pred) (small needle)", std_find_first_of_pred);
+ bm.operator()<std::vector<int>>("rng::find_first_of(vector<int>, pred) (small needle)", ranges_find_first_of_pred);
+ bm.operator()<std::deque<int>>("rng::find_first_of(deque<int>, pred) (small needle)", ranges_find_first_of_pred);
+ bm.operator()<std::list<int>>("rng::find_first_of(list<int>, pred) (small needle)", ranges_find_first_of_pred);
+ }
+
+ // Special case: the needle is large compared to the haystack, and we find a match early in the haystack.
+ {
+ auto bm = []<class Container>(std::string name, auto find_first_of) {
+ benchmark::RegisterBenchmark(
+ name,
+ [find_first_of](auto& st) {
+ std::size_t const size = st.range(0);
+ using ValueType = typename Container::value_type;
+ ValueType x = Generate<ValueType>::random();
+ ValueType y = random_
diff erent_from({x});
+ Container haystack(size, x);
+ Container needle(size * 10, y);
+
+ // put a match at 10% of the haystack
+ *std::next(haystack.begin(), haystack.size() / 10) = y;
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(haystack);
+ benchmark::DoNotOptimize(needle);
+ auto result = find_first_of(haystack.begin(), haystack.end(), needle.begin(), needle.end());
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(32)
+ ->Arg(50) // non power-of-two
+ ->Arg(1024)
+ ->Arg(8192);
+ };
+ // {std,ranges}::find_first_of(it1, it1, it2, it2)
+ bm.operator()<std::vector<int>>("std::find_first_of(vector<int>) (large needle)", std_find_first_of);
+ bm.operator()<std::deque<int>>("std::find_first_of(deque<int>) (large needle)", std_find_first_of);
+ bm.operator()<std::list<int>>("std::find_first_of(list<int>) (large needle)", std_find_first_of);
+ bm.operator()<std::vector<int>>("rng::find_first_of(vector<int>) (large needle)", std::ranges::find_first_of);
+ bm.operator()<std::deque<int>>("rng::find_first_of(deque<int>) (large needle)", std::ranges::find_first_of);
+ bm.operator()<std::list<int>>("rng::find_first_of(list<int>) (large needle)", std::ranges::find_first_of);
+
+ // {std,ranges}::find_first_of(it1, it1, it2, it2, pred)
+ bm.operator()<std::vector<int>>("std::find_first_of(vector<int>, pred) (large needle)", std_find_first_of_pred);
+ bm.operator()<std::deque<int>>("std::find_first_of(deque<int>, pred) (large needle)", std_find_first_of_pred);
+ bm.operator()<std::list<int>>("std::find_first_of(list<int>, pred) (large needle)", std_find_first_of_pred);
+ bm.operator()<std::vector<int>>("rng::find_first_of(vector<int>, pred) (large needle)", ranges_find_first_of_pred);
+ bm.operator()<std::deque<int>>("rng::find_first_of(deque<int>, pred) (large needle)", ranges_find_first_of_pred);
+ bm.operator()<std::list<int>>("rng::find_first_of(list<int>, pred) (large needle)", ranges_find_first_of_pred);
+ }
+
+ benchmark::Initialize(&argc, argv);
+ benchmark::RunSpecifiedBenchmarks();
+ benchmark::Shutdown();
+ return 0;
+}
diff --git a/libcxx/test/benchmarks/algorithms/nonmodifying/find_last.bench.cpp b/libcxx/test/benchmarks/algorithms/nonmodifying/find_last.bench.cpp
new file mode 100644
index 0000000000000..17074250c6c72
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/nonmodifying/find_last.bench.cpp
@@ -0,0 +1,145 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+#include <algorithm>
+#include <cstddef>
+#include <deque>
+#include <forward_list>
+#include <list>
+#include <string>
+#include <vector>
+
+#include <benchmark/benchmark.h>
+#include "../../GenerateInput.h"
+
+int main(int argc, char** argv) {
+ auto ranges_find_last_if = [](auto first, auto last, auto const& value) {
+ return std::ranges::find_last_if(first, last, [&](auto element) {
+ benchmark::DoNotOptimize(element);
+ return element == value;
+ });
+ };
+ auto ranges_find_last_if_not = [](auto first, auto last, auto const& value) {
+ return std::ranges::find_last_if_not(first, last, [&](auto element) {
+ benchmark::DoNotOptimize(element);
+ return element != value;
+ });
+ };
+
+ // Benchmark ranges::{find_last,find_last_if,find_last_if_not} where the last element
+ // is found 10% into the sequence
+ {
+ auto bm = []<class Container>(std::string name, auto find_last) {
+ benchmark::RegisterBenchmark(
+ name,
+ [find_last](auto& st) {
+ std::size_t const size = st.range(0);
+ using ValueType = typename Container::value_type;
+ ValueType x = Generate<ValueType>::random();
+ ValueType y = random_
diff erent_from({x});
+ Container c(size, x);
+
+ // put the element we're searching for at 10% of the sequence
+ *std::next(c.begin(), size / 10) = y;
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(c);
+ benchmark::DoNotOptimize(y);
+ auto result = find_last(c.begin(), c.end(), y);
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(8)
+ ->Arg(50) // non power-of-two
+ ->Arg(1024)
+ ->Arg(8192)
+ ->Arg(1 << 20);
+ };
+
+ // find_last
+ bm.operator()<std::vector<char>>("rng::find_last(vector<char>) (bail 10%)", std::ranges::find_last);
+ bm.operator()<std::vector<int>>("rng::find_last(vector<int>) (bail 10%)", std::ranges::find_last);
+ bm.operator()<std::deque<int>>("rng::find_last(deque<int>) (bail 10%)", std::ranges::find_last);
+ bm.operator()<std::list<int>>("rng::find_last(list<int>) (bail 10%)", std::ranges::find_last);
+ bm.operator()<std::forward_list<int>>("rng::find_last(forward_list<int>) (bail 10%)", std::ranges::find_last);
+
+ // find_last_if
+ bm.operator()<std::vector<char>>("rng::find_last_if(vector<char>) (bail 10%)", ranges_find_last_if);
+ bm.operator()<std::vector<int>>("rng::find_last_if(vector<int>) (bail 10%)", ranges_find_last_if);
+ bm.operator()<std::deque<int>>("rng::find_last_if(deque<int>) (bail 10%)", ranges_find_last_if);
+ bm.operator()<std::list<int>>("rng::find_last_if(list<int>) (bail 10%)", ranges_find_last_if);
+ bm.operator()<std::forward_list<int>>("rng::find_last_if(forward_list<int>) (bail 10%)", ranges_find_last_if);
+
+ // find_last_if_not
+ bm.operator()<std::vector<char>>("rng::find_last_if_not(vector<char>) (bail 10%)", ranges_find_last_if_not);
+ bm.operator()<std::vector<int>>("rng::find_last_if_not(vector<int>) (bail 10%)", ranges_find_last_if_not);
+ bm.operator()<std::deque<int>>("rng::find_last_if_not(deque<int>) (bail 10%)", ranges_find_last_if_not);
+ bm.operator()<std::list<int>>("rng::find_last_if_not(list<int>) (bail 10%)", ranges_find_last_if_not);
+ bm.operator()<std::forward_list<int>>(
+ "rng::find_last_if_not(forward_list<int>) (bail 10%)", ranges_find_last_if_not);
+ }
+
+ // Benchmark ranges::{find_last,find_last_if,find_last_if_not} where the last element
+ // is found 90% into the sequence (i.e. near the end)
+ {
+ auto bm = []<class Container>(std::string name, auto find_last) {
+ benchmark::RegisterBenchmark(
+ name,
+ [find_last](auto& st) {
+ std::size_t const size = st.range(0);
+ using ValueType = typename Container::value_type;
+ ValueType x = Generate<ValueType>::random();
+ ValueType y = random_
diff erent_from({x});
+ Container c(size, x);
+
+ // put the element we're searching for at 90% of the sequence
+ *std::next(c.begin(), (9 * size) / 10) = y;
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(c);
+ benchmark::DoNotOptimize(y);
+ auto result = find_last(c.begin(), c.end(), y);
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(8)
+ ->Arg(50) // non power-of-two
+ ->Arg(1024)
+ ->Arg(8192)
+ ->Arg(1 << 20);
+ };
+ // find_last
+ bm.operator()<std::vector<char>>("rng::find_last(vector<char>) (bail 90%)", std::ranges::find_last);
+ bm.operator()<std::vector<int>>("rng::find_last(vector<int>) (bail 90%)", std::ranges::find_last);
+ bm.operator()<std::deque<int>>("rng::find_last(deque<int>) (bail 90%)", std::ranges::find_last);
+ bm.operator()<std::list<int>>("rng::find_last(list<int>) (bail 90%)", std::ranges::find_last);
+ bm.operator()<std::forward_list<int>>("rng::find_last(forward_list<int>) (bail 90%)", std::ranges::find_last);
+
+ // find_last_if
+ bm.operator()<std::vector<char>>("rng::find_last_if(vector<char>) (bail 90%)", ranges_find_last_if);
+ bm.operator()<std::vector<int>>("rng::find_last_if(vector<int>) (bail 90%)", ranges_find_last_if);
+ bm.operator()<std::deque<int>>("rng::find_last_if(deque<int>) (bail 90%)", ranges_find_last_if);
+ bm.operator()<std::list<int>>("rng::find_last_if(list<int>) (bail 90%)", ranges_find_last_if);
+ bm.operator()<std::forward_list<int>>("rng::find_last_if(forward_list<int>) (bail 90%)", ranges_find_last_if);
+
+ // find_last_if_not
+ bm.operator()<std::vector<char>>("rng::find_last_if_not(vector<char>) (bail 90%)", ranges_find_last_if_not);
+ bm.operator()<std::vector<int>>("rng::find_last_if_not(vector<int>) (bail 90%)", ranges_find_last_if_not);
+ bm.operator()<std::deque<int>>("rng::find_last_if_not(deque<int>) (bail 90%)", ranges_find_last_if_not);
+ bm.operator()<std::list<int>>("rng::find_last_if_not(list<int>) (bail 90%)", ranges_find_last_if_not);
+ bm.operator()<std::forward_list<int>>(
+ "rng::find_last_if_not(forward_list<int>) (bail 90%)", ranges_find_last_if_not);
+ }
+
+ benchmark::Initialize(&argc, argv);
+ benchmark::RunSpecifiedBenchmarks();
+ benchmark::Shutdown();
+ return 0;
+}
diff --git a/libcxx/test/benchmarks/algorithms/nonmodifying/fold.bench.cpp b/libcxx/test/benchmarks/algorithms/nonmodifying/fold.bench.cpp
new file mode 100644
index 0000000000000..a795b5df7f7f4
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/nonmodifying/fold.bench.cpp
@@ -0,0 +1,73 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+#include <algorithm>
+#include <cstddef>
+#include <deque>
+#include <iterator>
+#include <list>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include <benchmark/benchmark.h>
+#include "../../GenerateInput.h"
+
+int main(int argc, char** argv) {
+ // ranges::{fold_left,fold_right}
+ {
+ auto bm = []<class Container>(std::string name, auto fold) {
+ benchmark::RegisterBenchmark(
+ name,
+ [fold](auto& st) {
+ std::size_t const size = st.range(0);
+ using ValueType = typename Container::value_type;
+ static_assert(std::is_unsigned_v<ValueType>,
+ "We could encounter UB if signed arithmetic overflows in this benchmark");
+
+ Container c;
+ std::generate_n(std::back_inserter(c), size, [&] { return Generate<ValueType>::random(); });
+ ValueType init = c.back();
+ c.pop_back();
+
+ auto f = [](auto x, auto y) {
+ benchmark::DoNotOptimize(x);
+ benchmark::DoNotOptimize(y);
+ return x + y;
+ };
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(c);
+ benchmark::DoNotOptimize(init);
+ auto result = fold(c.begin(), c.end(), init, f);
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(8)
+ ->Arg(32)
+ ->Arg(50) // non power-of-two
+ ->Arg(8192)
+ ->Arg(1 << 20);
+ };
+ bm.operator()<std::vector<unsigned int>>("rng::fold_left(vector<int>)", std::ranges::fold_left);
+ bm.operator()<std::deque<unsigned int>>("rng::fold_left(deque<int>)", std::ranges::fold_left);
+ bm.operator()<std::list<unsigned int>>("rng::fold_left(list<int>)", std::ranges::fold_left);
+
+ // TODO: fold_right not implemented yet
+ // bm.operator()<std::vector<unsigned int>>("rng::fold_right(vector<int>)", std::ranges::fold_right);
+ // bm.operator()<std::deque<unsigned int>>("rng::fold_right(deque<int>)", std::ranges::fold_right);
+ // bm.operator()<std::list<unsigned int>>("rng::fold_right(list<int>)", std::ranges::fold_right);
+ }
+
+ benchmark::Initialize(&argc, argv);
+ benchmark::RunSpecifiedBenchmarks();
+ benchmark::Shutdown();
+ return 0;
+}
diff --git a/libcxx/test/benchmarks/algorithms/nonmodifying/for_each.bench.cpp b/libcxx/test/benchmarks/algorithms/nonmodifying/for_each.bench.cpp
new file mode 100644
index 0000000000000..760accbe4d929
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/nonmodifying/for_each.bench.cpp
@@ -0,0 +1,58 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <algorithm>
+#include <cstddef>
+#include <deque>
+#include <list>
+#include <string>
+#include <vector>
+
+#include <benchmark/benchmark.h>
+
+int main(int argc, char** argv) {
+ auto std_for_each = [](auto first, auto last, auto f) { return std::for_each(first, last, f); };
+
+ // {std,ranges}::for_each
+ {
+ auto bm = []<class Container>(std::string name, auto for_each) {
+ benchmark::RegisterBenchmark(
+ name,
+ [for_each](auto& st) {
+ std::size_t const size = st.range(0);
+ Container c(size, 1);
+ auto first = c.begin();
+ auto last = c.end();
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(c);
+ auto result = for_each(first, last, [](int& x) { x = std::clamp(x, 10, 100); });
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(8)
+ ->Arg(32)
+ ->Arg(50) // non power-of-two
+ ->Arg(8192)
+ ->Arg(1 << 20);
+ };
+ bm.operator()<std::vector<int>>("std::for_each(vector<int>)", std_for_each);
+ bm.operator()<std::deque<int>>("std::for_each(deque<int>)", std_for_each);
+ bm.operator()<std::list<int>>("std::for_each(list<int>)", std_for_each);
+ bm.operator()<std::vector<int>>("rng::for_each(vector<int>)", std::ranges::for_each);
+ bm.operator()<std::deque<int>>("rng::for_each(deque<int>)", std::ranges::for_each);
+ bm.operator()<std::list<int>>("rng::for_each(list<int>)", std::ranges::for_each);
+ }
+
+ benchmark::Initialize(&argc, argv);
+ benchmark::RunSpecifiedBenchmarks();
+ benchmark::Shutdown();
+ return 0;
+}
diff --git a/libcxx/test/benchmarks/algorithms/nonmodifying/is_permutation.bench.cpp b/libcxx/test/benchmarks/algorithms/nonmodifying/is_permutation.bench.cpp
new file mode 100644
index 0000000000000..3e4d21945bf06
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/nonmodifying/is_permutation.bench.cpp
@@ -0,0 +1,158 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <algorithm>
+#include <cstddef>
+#include <deque>
+#include <iterator>
+#include <list>
+#include <string>
+#include <vector>
+
+#include <benchmark/benchmark.h>
+#include "../../GenerateInput.h"
+
+int main(int argc, char** argv) {
+ auto std_is_permutation_3leg = [](auto first1, auto last1, auto first2, auto) {
+ return std::is_permutation(first1, last1, first2);
+ };
+ auto std_is_permutation_4leg = [](auto first1, auto last1, auto first2, auto last2) {
+ return std::is_permutation(first1, last1, first2, last2);
+ };
+ auto std_is_permutation_3leg_pred = [](auto first1, auto last1, auto first2, auto) {
+ return std::is_permutation(first1, last1, first2, [](auto x, auto y) {
+ benchmark::DoNotOptimize(x);
+ benchmark::DoNotOptimize(y);
+ return x == y;
+ });
+ };
+ auto std_is_permutation_4leg_pred = [](auto first1, auto last1, auto first2, auto last2) {
+ return std::is_permutation(first1, last1, first2, last2, [](auto x, auto y) {
+ benchmark::DoNotOptimize(x);
+ benchmark::DoNotOptimize(y);
+ return x == y;
+ });
+ };
+ auto ranges_is_permutation_4leg_pred = [](auto first1, auto last1, auto first2, auto last2) {
+ return std::ranges::is_permutation(first1, last1, first2, last2, [](auto x, auto y) {
+ benchmark::DoNotOptimize(x);
+ benchmark::DoNotOptimize(y);
+ return x == y;
+ });
+ };
+
+ auto register_benchmarks = [&](auto bm, std::string comment) {
+ // std::is_permutation(it, it, it)
+ bm.template operator()<std::vector<int>>(
+ "std::is_permutation(vector<int>) (3leg) (" + comment + ")", std_is_permutation_3leg);
+ bm.template operator()<std::deque<int>>(
+ "std::is_permutation(deque<int>) (3leg) (" + comment + ")", std_is_permutation_3leg);
+ bm.template operator()<std::list<int>>(
+ "std::is_permutation(list<int>) (3leg) (" + comment + ")", std_is_permutation_3leg);
+
+ // std::is_permutation(it, it, it, pred)
+ bm.template operator()<std::vector<int>>(
+ "std::is_permutation(vector<int>) (3leg, pred) (" + comment + ")", std_is_permutation_3leg_pred);
+ bm.template operator()<std::deque<int>>(
+ "std::is_permutation(deque<int>) (3leg, pred) (" + comment + ")", std_is_permutation_3leg_pred);
+ bm.template operator()<std::list<int>>(
+ "std::is_permutation(list<int>) (3leg, pred) (" + comment + ")", std_is_permutation_3leg_pred);
+
+ // {std,ranges}::is_permutation(it, it, it, it)
+ bm.template operator()<std::vector<int>>(
+ "std::is_permutation(vector<int>) (4leg) (" + comment + ")", std_is_permutation_4leg);
+ bm.template operator()<std::deque<int>>(
+ "std::is_permutation(deque<int>) (4leg) (" + comment + ")", std_is_permutation_4leg);
+ bm.template operator()<std::list<int>>(
+ "std::is_permutation(list<int>) (4leg) (" + comment + ")", std_is_permutation_4leg);
+ bm.template operator()<std::vector<int>>(
+ "rng::is_permutation(vector<int>) (4leg) (" + comment + ")", std::ranges::is_permutation);
+ bm.template operator()<std::deque<int>>(
+ "rng::is_permutation(deque<int>) (4leg) (" + comment + ")", std::ranges::is_permutation);
+ bm.template operator()<std::list<int>>(
+ "rng::is_permutation(list<int>) (4leg) (" + comment + ")", std::ranges::is_permutation);
+
+ // {std,ranges}::is_permutation(it, it, it, it, pred)
+ bm.template operator()<std::vector<int>>(
+ "std::is_permutation(vector<int>) (4leg, pred) (" + comment + ")", std_is_permutation_4leg_pred);
+ bm.template operator()<std::deque<int>>(
+ "std::is_permutation(deque<int>) (4leg, pred) (" + comment + ")", std_is_permutation_4leg_pred);
+ bm.template operator()<std::list<int>>(
+ "std::is_permutation(list<int>) (4leg, pred) (" + comment + ")", std_is_permutation_4leg_pred);
+ bm.template operator()<std::vector<int>>(
+ "rng::is_permutation(vector<int>) (4leg, pred) (" + comment + ")", ranges_is_permutation_4leg_pred);
+ bm.template operator()<std::deque<int>>(
+ "rng::is_permutation(deque<int>) (4leg, pred) (" + comment + ")", ranges_is_permutation_4leg_pred);
+ bm.template operator()<std::list<int>>(
+ "rng::is_permutation(list<int>) (4leg, pred) (" + comment + ")", ranges_is_permutation_4leg_pred);
+ };
+
+ // Benchmark {std,ranges}::is_permutation where both sequences share a common prefix (this can be optimized).
+ {
+ auto bm = []<class Container>(std::string name, auto is_permutation) {
+ benchmark::RegisterBenchmark(
+ name,
+ [is_permutation](auto& st) {
+ std::size_t const size = st.range(0);
+ using ValueType = typename Container::value_type;
+ ValueType x = Generate<ValueType>::random();
+ ValueType y = random_
diff erent_from({x});
+ Container c1(size, x);
+ Container c2(size, x);
+ c2.back() = y;
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(c1);
+ benchmark::DoNotOptimize(c2);
+ auto result = is_permutation(c1.begin(), c1.end(), c2.begin(), c2.end());
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(8)
+ ->Arg(1024)
+ ->Arg(8192);
+ };
+ register_benchmarks(bm, "common prefix");
+ }
+
+ // Benchmark {std,ranges}::is_permutation on fully shuffled sequences.
+ {
+ auto bm = []<class Container>(std::string name, auto is_permutation) {
+ benchmark::RegisterBenchmark(
+ name,
+ [is_permutation](auto& st) {
+ std::size_t const size = st.range(0);
+ using ValueType = typename Container::value_type;
+ std::vector<ValueType> data;
+ std::generate_n(std::back_inserter(data), size, [] { return Generate<ValueType>::random(); });
+ Container c1(data.begin(), data.end());
+
+ std::mt19937 rng;
+ std::shuffle(data.begin(), data.end(), rng);
+ Container c2(data.begin(), data.end());
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(c1);
+ benchmark::DoNotOptimize(c2);
+ auto result = is_permutation(c1.begin(), c1.end(), c2.begin(), c2.end());
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(8)
+ ->Arg(1024); // this one is very slow, no need for large sequences
+ };
+ register_benchmarks(bm, "shuffled");
+ }
+
+ benchmark::Initialize(&argc, argv);
+ benchmark::RunSpecifiedBenchmarks();
+ benchmark::Shutdown();
+ return 0;
+}
diff --git a/libcxx/test/benchmarks/algorithms/nonmodifying/mismatch.bench.cpp b/libcxx/test/benchmarks/algorithms/nonmodifying/mismatch.bench.cpp
new file mode 100644
index 0000000000000..5c5961adcd05d
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/nonmodifying/mismatch.bench.cpp
@@ -0,0 +1,112 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <algorithm>
+#include <cstddef>
+#include <deque>
+#include <list>
+#include <string>
+#include <vector>
+
+#include <benchmark/benchmark.h>
+#include "../../GenerateInput.h"
+
+int main(int argc, char** argv) {
+ auto std_mismatch_3leg = [](auto first1, auto last1, auto first2, auto) {
+ return std::mismatch(first1, last1, first2);
+ };
+ auto std_mismatch_4leg = [](auto first1, auto last1, auto first2, auto last2) {
+ return std::mismatch(first1, last1, first2, last2);
+ };
+ auto std_mismatch_3leg_pred = [](auto first1, auto last1, auto first2, auto) {
+ return std::mismatch(first1, last1, first2, [](auto x, auto y) {
+ benchmark::DoNotOptimize(x);
+ benchmark::DoNotOptimize(y);
+ return x == y;
+ });
+ };
+ auto std_mismatch_4leg_pred = [](auto first1, auto last1, auto first2, auto last2) {
+ return std::mismatch(first1, last1, first2, last2, [](auto x, auto y) {
+ benchmark::DoNotOptimize(x);
+ benchmark::DoNotOptimize(y);
+ return x == y;
+ });
+ };
+ auto ranges_mismatch_4leg_pred = [](auto first1, auto last1, auto first2, auto last2) {
+ return std::ranges::mismatch(first1, last1, first2, last2, [](auto x, auto y) {
+ benchmark::DoNotOptimize(x);
+ benchmark::DoNotOptimize(y);
+ return x == y;
+ });
+ };
+
+ // Benchmark {std,ranges}::mismatch where we find the mismatching element at the very end (worst case).
+ //
+ // TODO: Look into benchmarking aligned and unaligned memory explicitly
+ // (currently things happen to be aligned because they are malloced that way)
+ {
+ auto bm = []<class Container>(std::string name, auto mismatch) {
+ benchmark::RegisterBenchmark(
+ name,
+ [mismatch](auto& st) {
+ std::size_t const size = st.range(0);
+ using ValueType = typename Container::value_type;
+ ValueType x = Generate<ValueType>::random();
+ ValueType y = random_
diff erent_from({x});
+ Container c1(size, x);
+ Container c2(size, x);
+ c2.back() = y;
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(c1);
+ benchmark::DoNotOptimize(c2);
+ auto result = mismatch(c1.begin(), c1.end(), c2.begin(), c2.end());
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(8)
+ ->Arg(1000) // non power-of-two
+ ->Arg(1024)
+ ->Arg(8192)
+ ->Arg(1 << 20);
+ };
+
+ // std::mismatch(it, it, it)
+ bm.operator()<std::vector<int>>("std::mismatch(vector<int>) (it, it, it)", std_mismatch_3leg);
+ bm.operator()<std::deque<int>>("std::mismatch(deque<int>) (it, it, it)", std_mismatch_3leg);
+ bm.operator()<std::list<int>>("std::mismatch(list<int>) (it, it, it)", std_mismatch_3leg);
+
+ // std::mismatch(it, it, it, pred)
+ bm.operator()<std::vector<int>>("std::mismatch(vector<int>) (it, it, it, pred)", std_mismatch_3leg_pred);
+ bm.operator()<std::deque<int>>("std::mismatch(deque<int>) (it, it, it, pred)", std_mismatch_3leg_pred);
+ bm.operator()<std::list<int>>("std::mismatch(list<int>) (it, it, it, pred)", std_mismatch_3leg_pred);
+
+ // {std,ranges}::mismatch(it, it, it, it)
+ bm.operator()<std::vector<int>>("std::mismatch(vector<int>) (it, it, it, it)", std_mismatch_4leg);
+ bm.operator()<std::deque<int>>("std::mismatch(deque<int>) (it, it, it, it)", std_mismatch_4leg);
+ bm.operator()<std::list<int>>("std::mismatch(list<int>) (it, it, it, it)", std_mismatch_4leg);
+ bm.operator()<std::vector<int>>("rng::mismatch(vector<int>) (it, it, it, it)", std::ranges::mismatch);
+ bm.operator()<std::deque<int>>("rng::mismatch(deque<int>) (it, it, it, it)", std::ranges::mismatch);
+ bm.operator()<std::list<int>>("rng::mismatch(list<int>) (it, it, it, it)", std::ranges::mismatch);
+
+ // {std,ranges}::mismatch(it, it, it, it, pred)
+ bm.operator()<std::vector<int>>("std::mismatch(vector<int>) (it, it, it, it, pred)", std_mismatch_4leg_pred);
+ bm.operator()<std::deque<int>>("std::mismatch(deque<int>) (it, it, it, it, pred)", std_mismatch_4leg_pred);
+ bm.operator()<std::list<int>>("std::mismatch(list<int>) (it, it, it, it, pred)", std_mismatch_4leg_pred);
+ bm.operator()<std::vector<int>>("rng::mismatch(vector<int>) (it, it, it, it, pred)", ranges_mismatch_4leg_pred);
+ bm.operator()<std::deque<int>>("rng::mismatch(deque<int>) (it, it, it, it, pred)", ranges_mismatch_4leg_pred);
+ bm.operator()<std::list<int>>("rng::mismatch(list<int>) (it, it, it, it, pred)", ranges_mismatch_4leg_pred);
+ }
+
+ benchmark::Initialize(&argc, argv);
+ benchmark::RunSpecifiedBenchmarks();
+ benchmark::Shutdown();
+ return 0;
+}
diff --git a/libcxx/test/benchmarks/algorithms/nonmodifying/search.bench.cpp b/libcxx/test/benchmarks/algorithms/nonmodifying/search.bench.cpp
new file mode 100644
index 0000000000000..a9d4a788d1b03
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/nonmodifying/search.bench.cpp
@@ -0,0 +1,220 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <deque>
+#include <list>
+#include <string>
+#include <vector>
+
+#include <benchmark/benchmark.h>
+#include "../../GenerateInput.h"
+
+int main(int argc, char** argv) {
+ auto std_search = [](auto first1, auto last1, auto first2, auto last2) {
+ return std::search(first1, last1, first2, last2);
+ };
+ auto std_search_pred = [](auto first1, auto last1, auto first2, auto last2) {
+ return std::search(first1, last1, first2, last2, [](auto x, auto y) {
+ benchmark::DoNotOptimize(x);
+ benchmark::DoNotOptimize(y);
+ return x == y;
+ });
+ };
+ auto ranges_search_pred = [](auto first1, auto last1, auto first2, auto last2) {
+ return std::ranges::search(first1, last1, first2, last2, [](auto x, auto y) {
+ benchmark::DoNotOptimize(x);
+ benchmark::DoNotOptimize(y);
+ return x == y;
+ });
+ };
+
+ // Benchmark {std,ranges}::search where the needle is never found (worst case).
+ {
+ auto bm = []<class Container>(std::string name, auto search) {
+ benchmark::RegisterBenchmark(
+ name,
+ [search](auto& st) {
+ std::size_t const size = st.range(0);
+ using ValueType = typename Container::value_type;
+ ValueType x = Generate<ValueType>::random();
+ ValueType y = random_
diff erent_from({x});
+ Container haystack(size, x);
+ Container needle(size / 10, y); // needle size is 10% of the haystack
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(haystack);
+ benchmark::DoNotOptimize(needle);
+ auto result = search(haystack.begin(), haystack.end(), needle.begin(), needle.end());
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(1000) // non power-of-two
+ ->Arg(1024)
+ ->Arg(8192)
+ ->Arg(1 << 20);
+ };
+ // {std,ranges}::search
+ bm.operator()<std::vector<int>>("std::search(vector<int>) (no match)", std_search);
+ bm.operator()<std::deque<int>>("std::search(deque<int>) (no match)", std_search);
+ bm.operator()<std::list<int>>("std::search(list<int>) (no match)", std_search);
+ bm.operator()<std::vector<int>>("rng::search(vector<int>) (no match)", std::ranges::search);
+ bm.operator()<std::deque<int>>("rng::search(deque<int>) (no match)", std::ranges::search);
+ bm.operator()<std::list<int>>("rng::search(list<int>) (no match)", std::ranges::search);
+
+ // {std,ranges}::search(pred)
+ bm.operator()<std::vector<int>>("std::search(vector<int>, pred) (no match)", std_search_pred);
+ bm.operator()<std::deque<int>>("std::search(deque<int>, pred) (no match)", std_search_pred);
+ bm.operator()<std::list<int>>("std::search(list<int>, pred) (no match)", std_search_pred);
+ bm.operator()<std::vector<int>>("rng::search(vector<int>, pred) (no match)", ranges_search_pred);
+ bm.operator()<std::deque<int>>("rng::search(deque<int>, pred) (no match)", ranges_search_pred);
+ bm.operator()<std::list<int>>("rng::search(list<int>, pred) (no match)", ranges_search_pred);
+ }
+
+ // Benchmark {std,ranges}::search where we intersperse "near matches" inside the haystack.
+ {
+ auto bm = []<class Container>(std::string name, auto search) {
+ benchmark::RegisterBenchmark(
+ name,
+ [search](auto& st) {
+ std::size_t const size = st.range(0);
+ using ValueType = typename Container::value_type;
+ ValueType x = Generate<ValueType>::random();
+ ValueType y = random_
diff erent_from({x});
+ Container haystack(size, x);
+ std::size_t n = size / 10; // needle size is 10% of the haystack
+ assert(n > 0);
+ Container needle(n, y);
+
+ // intersperse near-matches inside the haystack
+ {
+ auto first = haystack.begin();
+ for (int i = 0; i != 10; ++i) {
+ first = std::copy_n(needle.begin(), n - 1, first);
+ ++first; // this causes the subsequence not to match because it has length n-1
+ }
+ }
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(haystack);
+ benchmark::DoNotOptimize(needle);
+ auto result = search(haystack.begin(), haystack.end(), needle.begin(), needle.end());
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(1000) // non power-of-two
+ ->Arg(1024)
+ ->Arg(8192);
+ };
+ // {std,ranges}::search
+ bm.operator()<std::vector<int>>("std::search(vector<int>) (near matches)", std_search);
+ bm.operator()<std::deque<int>>("std::search(deque<int>) (near matches)", std_search);
+ bm.operator()<std::list<int>>("std::search(list<int>) (near matches)", std_search);
+ bm.operator()<std::vector<int>>("rng::search(vector<int>) (near matches)", std::ranges::search);
+ bm.operator()<std::deque<int>>("rng::search(deque<int>) (near matches)", std::ranges::search);
+ bm.operator()<std::list<int>>("rng::search(list<int>) (near matches)", std::ranges::search);
+
+ // {std,ranges}::search(pred)
+ bm.operator()<std::vector<int>>("std::search(vector<int>, pred) (near matches)", std_search_pred);
+ bm.operator()<std::deque<int>>("std::search(deque<int>, pred) (near matches)", std_search_pred);
+ bm.operator()<std::list<int>>("std::search(list<int>, pred) (near matches)", std_search_pred);
+ bm.operator()<std::vector<int>>("rng::search(vector<int>, pred) (near matches)", ranges_search_pred);
+ bm.operator()<std::deque<int>>("rng::search(deque<int>, pred) (near matches)", ranges_search_pred);
+ bm.operator()<std::list<int>>("rng::search(list<int>, pred) (near matches)", ranges_search_pred);
+ }
+
+ // Special case: the two ranges are the same length (and they are equal, which is the worst case).
+ {
+ auto bm = []<class Container>(std::string name, auto search) {
+ benchmark::RegisterBenchmark(
+ name,
+ [search](auto& st) {
+ std::size_t const size = st.range(0);
+ using ValueType = typename Container::value_type;
+ ValueType x = Generate<ValueType>::random();
+ Container haystack(size, x);
+ Container needle(size, x);
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(haystack);
+ benchmark::DoNotOptimize(needle);
+ auto result = search(haystack.begin(), haystack.end(), needle.begin(), needle.end());
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(1000) // non power-of-two
+ ->Arg(1024)
+ ->Arg(8192);
+ };
+ // {std,ranges}::search
+ bm.operator()<std::vector<int>>("std::search(vector<int>) (same length)", std_search);
+ bm.operator()<std::deque<int>>("std::search(deque<int>) (same length)", std_search);
+ bm.operator()<std::list<int>>("std::search(list<int>) (same length)", std_search);
+ bm.operator()<std::vector<int>>("rng::search(vector<int>) (same length)", std::ranges::search);
+ bm.operator()<std::deque<int>>("rng::search(deque<int>) (same length)", std::ranges::search);
+ bm.operator()<std::list<int>>("rng::search(list<int>) (same length)", std::ranges::search);
+
+ // {std,ranges}::search(pred)
+ bm.operator()<std::vector<int>>("std::search(vector<int>, pred) (same length)", std_search_pred);
+ bm.operator()<std::deque<int>>("std::search(deque<int>, pred) (same length)", std_search_pred);
+ bm.operator()<std::list<int>>("std::search(list<int>, pred) (same length)", std_search_pred);
+ bm.operator()<std::vector<int>>("rng::search(vector<int>, pred) (same length)", ranges_search_pred);
+ bm.operator()<std::deque<int>>("rng::search(deque<int>, pred) (same length)", ranges_search_pred);
+ bm.operator()<std::list<int>>("rng::search(list<int>, pred) (same length)", ranges_search_pred);
+ }
+
+ // Special case: the needle contains a single element (which we never find, i.e. the worst case).
+ {
+ auto bm = []<class Container>(std::string name, auto search) {
+ benchmark::RegisterBenchmark(
+ name,
+ [search](auto& st) {
+ std::size_t const size = st.range(0);
+ using ValueType = typename Container::value_type;
+ ValueType x = Generate<ValueType>::random();
+ ValueType y = random_
diff erent_from({x});
+ Container haystack(size, x);
+ Container needle(1, y);
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(haystack);
+ benchmark::DoNotOptimize(needle);
+ auto result = search(haystack.begin(), haystack.end(), needle.begin(), needle.end());
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(1000) // non power-of-two
+ ->Arg(1024)
+ ->Arg(8192);
+ };
+ // {std,ranges}::search
+ bm.operator()<std::vector<int>>("std::search(vector<int>) (single element)", std_search);
+ bm.operator()<std::deque<int>>("std::search(deque<int>) (single element)", std_search);
+ bm.operator()<std::list<int>>("std::search(list<int>) (single element)", std_search);
+ bm.operator()<std::vector<int>>("rng::search(vector<int>) (single element)", std::ranges::search);
+ bm.operator()<std::deque<int>>("rng::search(deque<int>) (single element)", std::ranges::search);
+ bm.operator()<std::list<int>>("rng::search(list<int>) (single element)", std::ranges::search);
+
+ // {std,ranges}::search(pred)
+ bm.operator()<std::vector<int>>("std::search(vector<int>, pred) (single element)", std_search_pred);
+ bm.operator()<std::deque<int>>("std::search(deque<int>, pred) (single element)", std_search_pred);
+ bm.operator()<std::list<int>>("std::search(list<int>, pred) (single element)", std_search_pred);
+ bm.operator()<std::vector<int>>("rng::search(vector<int>, pred) (single element)", ranges_search_pred);
+ bm.operator()<std::deque<int>>("rng::search(deque<int>, pred) (single element)", ranges_search_pred);
+ bm.operator()<std::list<int>>("rng::search(list<int>, pred) (single element)", ranges_search_pred);
+ }
+
+ benchmark::Initialize(&argc, argv);
+ benchmark::RunSpecifiedBenchmarks();
+ benchmark::Shutdown();
+ return 0;
+}
diff --git a/libcxx/test/benchmarks/algorithms/nonmodifying/search_n.bench.cpp b/libcxx/test/benchmarks/algorithms/nonmodifying/search_n.bench.cpp
new file mode 100644
index 0000000000000..de404fedaed3a
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/nonmodifying/search_n.bench.cpp
@@ -0,0 +1,88 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <deque>
+#include <list>
+#include <string>
+#include <vector>
+
+#include <benchmark/benchmark.h>
+#include "../../GenerateInput.h"
+
+int main(int argc, char** argv) {
+ auto std_search_n = [](auto first, auto last, auto n, auto const& value) {
+ return std::search_n(first, last, n, value);
+ };
+ auto std_search_n_pred = [](auto first, auto last, auto n, auto const& value) {
+ return std::search_n(first, last, n, value, [](auto x, auto y) {
+ benchmark::DoNotOptimize(x);
+ benchmark::DoNotOptimize(y);
+ return x == y;
+ });
+ };
+ auto ranges_search_n_pred = [](auto first, auto last, auto n, auto const& value) {
+ return std::ranges::search_n(first, last, n, value, [](auto x, auto y) {
+ benchmark::DoNotOptimize(x);
+ benchmark::DoNotOptimize(y);
+ return x == y;
+ });
+ };
+
+ // Benchmark {std,ranges}::search_n where the needle is never found (worst case).
+ {
+ auto bm = []<class Container>(std::string name, auto search_n) {
+ benchmark::RegisterBenchmark(
+ name,
+ [search_n](auto& st) {
+ std::size_t const size = st.range(0);
+ using ValueType = typename Container::value_type;
+ ValueType x = Generate<ValueType>::random();
+ ValueType y = random_
diff erent_from({x});
+ Container haystack(size, x);
+ std::size_t n = size / 10; // needle size is 10% of the haystack
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(haystack);
+ benchmark::DoNotOptimize(n);
+ benchmark::DoNotOptimize(y);
+ auto result = search_n(haystack.begin(), haystack.end(), n, y);
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(1000) // non power-of-two
+ ->Arg(1024)
+ ->Arg(8192)
+ ->Arg(1 << 20);
+ };
+ // {std,ranges}::search_n
+ bm.operator()<std::vector<int>>("std::search_n(vector<int>) (no match)", std_search_n);
+ bm.operator()<std::deque<int>>("std::search_n(deque<int>) (no match)", std_search_n);
+ bm.operator()<std::list<int>>("std::search_n(list<int>) (no match)", std_search_n);
+ bm.operator()<std::vector<int>>("rng::search_n(vector<int>) (no match)", std::ranges::search_n);
+ bm.operator()<std::deque<int>>("rng::search_n(deque<int>) (no match)", std::ranges::search_n);
+ bm.operator()<std::list<int>>("rng::search_n(list<int>) (no match)", std::ranges::search_n);
+
+ // {std,ranges}::search_n(pred)
+ bm.operator()<std::vector<int>>("std::search_n(vector<int>, pred) (no match)", std_search_n_pred);
+ bm.operator()<std::deque<int>>("std::search_n(deque<int>, pred) (no match)", std_search_n_pred);
+ bm.operator()<std::list<int>>("std::search_n(list<int>, pred) (no match)", std_search_n_pred);
+ bm.operator()<std::vector<int>>("rng::search_n(vector<int>, pred) (no match)", ranges_search_n_pred);
+ bm.operator()<std::deque<int>>("rng::search_n(deque<int>, pred) (no match)", ranges_search_n_pred);
+ bm.operator()<std::list<int>>("rng::search_n(list<int>, pred) (no match)", ranges_search_n_pred);
+ }
+
+ benchmark::Initialize(&argc, argv);
+ benchmark::RunSpecifiedBenchmarks();
+ benchmark::Shutdown();
+ return 0;
+}
diff --git a/libcxx/test/benchmarks/algorithms/nonmodifying/starts_with.bench.cpp b/libcxx/test/benchmarks/algorithms/nonmodifying/starts_with.bench.cpp
new file mode 100644
index 0000000000000..2950ad5322e84
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/nonmodifying/starts_with.bench.cpp
@@ -0,0 +1,70 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+#include <algorithm>
+#include <cstddef>
+#include <deque>
+#include <list>
+#include <string>
+#include <vector>
+
+#include <benchmark/benchmark.h>
+#include "../../GenerateInput.h"
+
+int main(int argc, char** argv) {
+ auto ranges_starts_with_pred = [](auto first1, auto last1, auto first2, auto last2) {
+ return std::ranges::starts_with(first1, last1, first2, last2, [](auto x, auto y) {
+ benchmark::DoNotOptimize(x);
+ benchmark::DoNotOptimize(y);
+ return x == y;
+ });
+ };
+
+ // Benchmark ranges::starts_with where we find the mismatching element at the very end (worst case).
+ {
+ auto bm = []<class Container>(std::string name, auto starts_with) {
+ benchmark::RegisterBenchmark(
+ name,
+ [starts_with](auto& st) {
+ std::size_t const size = st.range(0);
+ using ValueType = typename Container::value_type;
+ ValueType x = Generate<ValueType>::random();
+ ValueType y = random_
diff erent_from({x});
+ Container c1(size, x);
+ Container c2(size, x);
+ c2.back() = y;
+
+ for ([[maybe_unused]] auto _ : st) {
+ benchmark::DoNotOptimize(c1);
+ benchmark::DoNotOptimize(c2);
+ auto result = starts_with(c1.begin(), c1.end(), c2.begin(), c2.end());
+ benchmark::DoNotOptimize(result);
+ }
+ })
+ ->Arg(8)
+ ->Arg(1000) // non power-of-two
+ ->Arg(1024)
+ ->Arg(8192)
+ ->Arg(1 << 20);
+ };
+ bm.operator()<std::vector<int>>("rng::starts_with(vector<int>)", std::ranges::starts_with);
+ bm.operator()<std::deque<int>>("rng::starts_with(deque<int>)", std::ranges::starts_with);
+ bm.operator()<std::list<int>>("rng::starts_with(list<int>)", std::ranges::starts_with);
+
+ bm.operator()<std::vector<int>>("rng::starts_with(vector<int>, pred)", ranges_starts_with_pred);
+ bm.operator()<std::deque<int>>("rng::starts_with(deque<int>, pred)", ranges_starts_with_pred);
+ bm.operator()<std::list<int>>("rng::starts_with(list<int>, pred)", ranges_starts_with_pred);
+ }
+
+ benchmark::Initialize(&argc, argv);
+ benchmark::RunSpecifiedBenchmarks();
+ benchmark::Shutdown();
+ return 0;
+}
diff --git a/libcxx/test/benchmarks/algorithms/ranges_contains.bench.cpp b/libcxx/test/benchmarks/algorithms/ranges_contains.bench.cpp
deleted file mode 100644
index c9a10202c8cfc..0000000000000
--- a/libcxx/test/benchmarks/algorithms/ranges_contains.bench.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-
-#include <algorithm>
-#include <benchmark/benchmark.h>
-#include <iterator>
-#include <vector>
-
-#include "test_iterators.h"
-
-static void bm_contains_vector_char(benchmark::State& state) {
- std::vector<char> a(state.range(), 'a');
-
- for (auto _ : state) {
- benchmark::DoNotOptimize(a);
-
- benchmark::DoNotOptimize(std::ranges::contains(a.begin(), a.end(), 'B'));
- }
-}
-BENCHMARK(bm_contains_vector_char)->RangeMultiplier(16)->Range(16, 16 << 20);
-
-static void bm_contains_vector_int(benchmark::State& state) {
- std::vector<int> a(state.range(), 1);
-
- for (auto _ : state) {
- benchmark::DoNotOptimize(a);
-
- benchmark::DoNotOptimize(std::ranges::contains(a.begin(), a.end(), 2));
- }
-}
-BENCHMARK(bm_contains_vector_int)->RangeMultiplier(16)->Range(16, 16 << 20);
-
-static void bm_contains_vector_bool(benchmark::State& state) {
- std::vector<bool> a(state.range(), true);
-
- for (auto _ : state) {
- benchmark::DoNotOptimize(a);
-
- benchmark::DoNotOptimize(std::ranges::contains(a.begin(), a.end(), false));
- }
-}
-BENCHMARK(bm_contains_vector_bool)->RangeMultiplier(16)->Range(16, 16 << 20);
-
-BENCHMARK_MAIN();
diff --git a/libcxx/test/benchmarks/algorithms/ranges_ends_with.bench.cpp b/libcxx/test/benchmarks/algorithms/ranges_ends_with.bench.cpp
deleted file mode 100644
index c975d164c16d4..0000000000000
--- a/libcxx/test/benchmarks/algorithms/ranges_ends_with.bench.cpp
+++ /dev/null
@@ -1,109 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-
-#include <algorithm>
-#include <benchmark/benchmark.h>
-#include <iterator>
-
-#include "test_iterators.h"
-#include <vector>
-
-static void bm_ends_with_contiguous_iter(benchmark::State& state) {
- std::vector<int> a(state.range(), 1);
- std::vector<int> p(state.range(), 1);
-
- for (auto _ : state) {
- benchmark::DoNotOptimize(a);
- benchmark::DoNotOptimize(p);
-
- auto begin1 = contiguous_iterator(a.data());
- auto end1 = contiguous_iterator(a.data() + a.size());
- auto begin2 = contiguous_iterator(p.data());
- auto end2 = contiguous_iterator(p.data() + p.size());
-
- benchmark::DoNotOptimize(std::ranges::ends_with(begin1, end1, begin2, end2));
- }
-}
-BENCHMARK(bm_ends_with_contiguous_iter)->RangeMultiplier(16)->Range(16, 16 << 20);
-
-static void bm_ends_with_random_iter(benchmark::State& state) {
- std::vector<int> a(state.range(), 1);
- std::vector<int> p(state.range(), 1);
-
- for (auto _ : state) {
- benchmark::DoNotOptimize(a);
- benchmark::DoNotOptimize(p);
-
- auto begin1 = random_access_iterator(a.begin());
- auto end1 = random_access_iterator(a.end());
- auto begin2 = random_access_iterator(p.begin());
- auto end2 = random_access_iterator(p.end());
-
- benchmark::DoNotOptimize(std::ranges::ends_with(begin1, end1, begin2, end2));
- }
-}
-BENCHMARK(bm_ends_with_random_iter)->RangeMultiplier(16)->Range(16, 16 << 20);
-
-static void bm_ends_with_bidirectional_iter(benchmark::State& state) {
- std::vector<int> a(state.range(), 1);
- std::vector<int> p(state.range(), 1);
-
- for (auto _ : state) {
- benchmark::DoNotOptimize(a);
- benchmark::DoNotOptimize(p);
-
- auto begin1 = bidirectional_iterator(a.begin());
- auto end1 = bidirectional_iterator(a.end());
- auto begin2 = bidirectional_iterator(p.begin());
- auto end2 = bidirectional_iterator(p.end());
-
- benchmark::DoNotOptimize(std::ranges::ends_with(begin1, end1, begin2, end2));
- }
-}
-BENCHMARK(bm_ends_with_bidirectional_iter)->RangeMultiplier(16)->Range(16, 16 << 20);
-
-static void bm_ends_with_forward_iter(benchmark::State& state) {
- std::vector<int> a(state.range(), 1);
- std::vector<int> p(state.range(), 1);
-
- for (auto _ : state) {
- benchmark::DoNotOptimize(a);
- benchmark::DoNotOptimize(p);
-
- auto begin1 = forward_iterator(a.begin());
- auto end1 = forward_iterator(a.end());
- auto begin2 = forward_iterator(p.begin());
- auto end2 = forward_iterator(p.end());
-
- benchmark::DoNotOptimize(std::ranges::ends_with(begin1, end1, begin2, end2));
- }
-}
-BENCHMARK(bm_ends_with_forward_iter)->RangeMultiplier(16)->Range(16, 16 << 20);
-
-static void bm_ends_with_forward_iter_with_size_optimization(benchmark::State& state) {
- std::vector<int> a(state.range(), 1);
- std::vector<int> p(state.range(), 1);
- p.push_back(2);
-
- for (auto _ : state) {
- benchmark::DoNotOptimize(a);
- benchmark::DoNotOptimize(p);
-
- auto begin1 = forward_iterator(a.begin());
- auto end1 = forward_iterator(a.end());
- auto begin2 = forward_iterator(p.begin());
- auto end2 = forward_iterator(p.end());
-
- benchmark::DoNotOptimize(std::ranges::ends_with(begin1, end1, begin2, end2));
- }
-}
-BENCHMARK(bm_ends_with_forward_iter_with_size_optimization)->RangeMultiplier(16)->Range(16, 16 << 20);
-
-BENCHMARK_MAIN();
More information about the libcxx-commits
mailing list