[libcxx-commits] [libcxx] 24e88b0 - [libc++] Add remaining benchmarks from [alg.modifying.operations] (#127354)

via libcxx-commits libcxx-commits at lists.llvm.org
Mon Mar 17 12:11:17 PDT 2025


Author: Louis Dionne
Date: 2025-03-17T15:11:13-04:00
New Revision: 24e88b0e6bc04f16d7353ad9ef07398836adf244

URL: https://github.com/llvm/llvm-project/commit/24e88b0e6bc04f16d7353ad9ef07398836adf244
DIFF: https://github.com/llvm/llvm-project/commit/24e88b0e6bc04f16d7353ad9ef07398836adf244.diff

LOG: [libc++] Add remaining benchmarks from [alg.modifying.operations] (#127354)

This patch adds benchmarks for all the remaining algorithms in
[alg.modifying.operations] that we didn't already have a benchmark for.

Added: 
    libcxx/test/benchmarks/algorithms/modifying/fill.bench.cpp
    libcxx/test/benchmarks/algorithms/modifying/fill_n.bench.cpp
    libcxx/test/benchmarks/algorithms/modifying/generate.bench.cpp
    libcxx/test/benchmarks/algorithms/modifying/generate_n.bench.cpp
    libcxx/test/benchmarks/algorithms/modifying/move.bench.cpp
    libcxx/test/benchmarks/algorithms/modifying/move_backward.bench.cpp
    libcxx/test/benchmarks/algorithms/modifying/remove.bench.cpp
    libcxx/test/benchmarks/algorithms/modifying/remove_copy.bench.cpp
    libcxx/test/benchmarks/algorithms/modifying/replace.bench.cpp
    libcxx/test/benchmarks/algorithms/modifying/reverse.bench.cpp
    libcxx/test/benchmarks/algorithms/modifying/reverse_copy.bench.cpp
    libcxx/test/benchmarks/algorithms/modifying/rotate_copy.bench.cpp
    libcxx/test/benchmarks/algorithms/modifying/sample.bench.cpp
    libcxx/test/benchmarks/algorithms/modifying/shift_left.bench.cpp
    libcxx/test/benchmarks/algorithms/modifying/shift_right.bench.cpp
    libcxx/test/benchmarks/algorithms/modifying/shuffle.bench.cpp
    libcxx/test/benchmarks/algorithms/modifying/swap_ranges.bench.cpp
    libcxx/test/benchmarks/algorithms/modifying/transform.binary.bench.cpp
    libcxx/test/benchmarks/algorithms/modifying/transform.unary.bench.cpp
    libcxx/test/benchmarks/algorithms/modifying/unique.bench.cpp
    libcxx/test/benchmarks/algorithms/modifying/unique_copy.bench.cpp

Modified: 
    libcxx/include/module.modulemap
    libcxx/test/benchmarks/GenerateInput.h
    libcxx/test/benchmarks/algorithms/modifying/rotate.bench.cpp

Removed: 
    libcxx/test/benchmarks/algorithms/fill.bench.cpp
    libcxx/test/benchmarks/algorithms/move.bench.cpp
    libcxx/test/benchmarks/algorithms/move_backward.bench.cpp
    libcxx/test/benchmarks/algorithms/reverse.bench.cpp


################################################################################
diff  --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index b9964dac84acd..406b26f86a4c5 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -708,6 +708,7 @@ module std [system] {
     }
     module ranges_remove {
       header "__algorithm/ranges_remove.h"
+      export std.ranges.subrange // return type
     }
     module ranges_replace_copy_if {
       header "__algorithm/ranges_replace_copy_if.h"
@@ -732,7 +733,7 @@ module std [system] {
     }
     module ranges_rotate_copy {
       header "__algorithm/ranges_rotate_copy.h"
-      export std.algorithm.in_out_result
+      export std.ranges.subrange // return type
     }
     module ranges_rotate                          { header "__algorithm/ranges_rotate.h" }
     module ranges_sample                          { header "__algorithm/ranges_sample.h" }

diff  --git a/libcxx/test/benchmarks/GenerateInput.h b/libcxx/test/benchmarks/GenerateInput.h
index c87fd69162e9d..9be76f55c2774 100644
--- a/libcxx/test/benchmarks/GenerateInput.h
+++ b/libcxx/test/benchmarks/GenerateInput.h
@@ -204,4 +204,13 @@ struct Generate<std::string> {
   }
 };
 
+template <class T>
+T random_
diff erent_from(std::initializer_list<T> others) {
+  T value;
+  do {
+    value = Generate<T>::random();
+  } while (std::find(others.begin(), others.end(), value) != others.end());
+  return value;
+}
+
 #endif // BENCHMARK_GENERATE_INPUT_H

diff  --git a/libcxx/test/benchmarks/algorithms/fill.bench.cpp b/libcxx/test/benchmarks/algorithms/fill.bench.cpp
deleted file mode 100644
index 6a48b25b7eb63..0000000000000
--- a/libcxx/test/benchmarks/algorithms/fill.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 <vector>
-
-static void bm_fill_n_vector_bool(benchmark::State& state) {
-  std::vector<bool> vec1(state.range());
-  for (auto _ : state) {
-    benchmark::DoNotOptimize(vec1);
-    benchmark::DoNotOptimize(std::fill_n(vec1.begin(), vec1.size(), false));
-  }
-}
-BENCHMARK(bm_fill_n_vector_bool)->DenseRange(1, 8)->Range(16, 1 << 20);
-
-static void bm_ranges_fill_n_vector_bool(benchmark::State& state) {
-  std::vector<bool> vec1(state.range());
-  for (auto _ : state) {
-    benchmark::DoNotOptimize(vec1);
-    benchmark::DoNotOptimize(std::ranges::fill_n(vec1.begin(), vec1.size(), false));
-  }
-}
-BENCHMARK(bm_ranges_fill_n_vector_bool)->DenseRange(1, 8)->Range(16, 1 << 20);
-
-static void bm_fill_vector_bool(benchmark::State& state) {
-  std::vector<bool> vec1(state.range());
-  for (auto _ : state) {
-    benchmark::DoNotOptimize(vec1);
-    std::fill(vec1.begin(), vec1.end(), false);
-  }
-}
-BENCHMARK(bm_fill_vector_bool)->DenseRange(1, 8)->Range(16, 1 << 20);
-
-static void bm_ranges_fill_vector_bool(benchmark::State& state) {
-  std::vector<bool> vec1(state.range());
-  for (auto _ : state) {
-    benchmark::DoNotOptimize(vec1);
-    benchmark::DoNotOptimize(std::ranges::fill(vec1, false));
-  }
-}
-BENCHMARK(bm_ranges_fill_vector_bool)->DenseRange(1, 8)->Range(16, 1 << 20);
-
-BENCHMARK_MAIN();

diff  --git a/libcxx/test/benchmarks/algorithms/modifying/fill.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/fill.bench.cpp
new file mode 100644
index 0000000000000..9060752259eb9
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/modifying/fill.bench.cpp
@@ -0,0 +1,83 @@
+//===----------------------------------------------------------------------===//
+//
+// 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"
+#include "test_macros.h"
+
+int main(int argc, char** argv) {
+  auto std_fill = [](auto first, auto last, auto const& value) { return std::fill(first, last, value); };
+
+  // {std,ranges}::fill(normal container)
+  {
+    auto bm = []<class Container>(std::string name, auto fill) {
+      benchmark::RegisterBenchmark(
+          name,
+          [fill](auto& st) {
+            std::size_t const size = st.range(0);
+            using ValueType        = typename Container::value_type;
+            ValueType x            = Generate<ValueType>::random();
+            Container c(size, x);
+
+            for ([[maybe_unused]] auto _ : st) {
+              benchmark::DoNotOptimize(c);
+              benchmark::DoNotOptimize(x);
+              fill(c.begin(), c.end(), x);
+              benchmark::DoNotOptimize(c);
+            }
+          })
+          ->Arg(32)
+          ->Arg(50) // non power-of-two
+          ->Arg(1024)
+          ->Arg(8192);
+    };
+    bm.operator()<std::vector<int>>("std::fill(vector<int>)", std_fill);
+    bm.operator()<std::deque<int>>("std::fill(deque<int>)", std_fill);
+    bm.operator()<std::list<int>>("std::fill(list<int>)", std_fill);
+    bm.operator()<std::vector<int>>("rng::fill(vector<int>)", std::ranges::fill);
+    bm.operator()<std::deque<int>>("rng::fill(deque<int>)", std::ranges::fill);
+    bm.operator()<std::list<int>>("rng::fill(list<int>)", std::ranges::fill);
+  }
+
+  // {std,ranges}::fill(vector<bool>)
+  {
+    auto bm = [](std::string name, auto fill) {
+      benchmark::RegisterBenchmark(name, [fill](auto& st) {
+        std::size_t const size = st.range(0);
+        bool x                 = true;
+        std::vector<bool> c(size, x);
+
+        for ([[maybe_unused]] auto _ : st) {
+          benchmark::DoNotOptimize(c);
+          benchmark::DoNotOptimize(x);
+          fill(c.begin(), c.end(), x);
+          benchmark::DoNotOptimize(c);
+        }
+      })->Range(64, 1 << 20);
+    };
+    bm("std::fill(vector<bool>)", std_fill);
+#if TEST_STD_VER >= 23 // vector<bool>::iterator is not an output_iterator before C++23
+    bm("rng::fill(vector<bool>)", std::ranges::fill);
+#endif
+  }
+
+  benchmark::Initialize(&argc, argv);
+  benchmark::RunSpecifiedBenchmarks();
+  benchmark::Shutdown();
+  return 0;
+}

diff  --git a/libcxx/test/benchmarks/algorithms/modifying/fill_n.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/fill_n.bench.cpp
new file mode 100644
index 0000000000000..8ad3e7534b1ef
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/modifying/fill_n.bench.cpp
@@ -0,0 +1,83 @@
+//===----------------------------------------------------------------------===//
+//
+// 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"
+#include "test_macros.h"
+
+int main(int argc, char** argv) {
+  auto std_fill_n = [](auto out, auto n, auto const& value) { return std::fill_n(out, n, value); };
+
+  // {std,ranges}::fill_n(normal container)
+  {
+    auto bm = []<class Container>(std::string name, auto fill_n) {
+      benchmark::RegisterBenchmark(
+          name,
+          [fill_n](auto& st) {
+            std::size_t const size = st.range(0);
+            using ValueType        = typename Container::value_type;
+            ValueType x            = Generate<ValueType>::random();
+            Container c(size, x);
+
+            for ([[maybe_unused]] auto _ : st) {
+              benchmark::DoNotOptimize(c);
+              benchmark::DoNotOptimize(x);
+              fill_n(c.begin(), size, x);
+              benchmark::DoNotOptimize(c);
+            }
+          })
+          ->Arg(32)
+          ->Arg(50) // non power-of-two
+          ->Arg(1024)
+          ->Arg(8192);
+    };
+    bm.operator()<std::vector<int>>("std::fill_n(vector<int>)", std_fill_n);
+    bm.operator()<std::deque<int>>("std::fill_n(deque<int>)", std_fill_n);
+    bm.operator()<std::list<int>>("std::fill_n(list<int>)", std_fill_n);
+    bm.operator()<std::vector<int>>("rng::fill_n(vector<int>)", std::ranges::fill_n);
+    bm.operator()<std::deque<int>>("rng::fill_n(deque<int>)", std::ranges::fill_n);
+    bm.operator()<std::list<int>>("rng::fill_n(list<int>)", std::ranges::fill_n);
+  }
+
+  // {std,ranges}::fill_n(vector<bool>)
+  {
+    auto bm = [](std::string name, auto fill_n) {
+      benchmark::RegisterBenchmark(name, [fill_n](auto& st) {
+        std::size_t const size = st.range(0);
+        bool x                 = true;
+        std::vector<bool> c(size, x);
+
+        for ([[maybe_unused]] auto _ : st) {
+          benchmark::DoNotOptimize(c);
+          benchmark::DoNotOptimize(x);
+          fill_n(c.begin(), size, x);
+          benchmark::DoNotOptimize(c);
+        }
+      })->Range(64, 1 << 20);
+    };
+    bm("std::fill_n(vector<bool>)", std_fill_n);
+#if TEST_STD_VER >= 23 // vector<bool>::iterator is not an output_iterator before C++23
+    bm("rng::fill_n(vector<bool>)", std::ranges::fill_n);
+#endif
+  }
+
+  benchmark::Initialize(&argc, argv);
+  benchmark::RunSpecifiedBenchmarks();
+  benchmark::Shutdown();
+  return 0;
+}

diff  --git a/libcxx/test/benchmarks/algorithms/modifying/generate.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/generate.bench.cpp
new file mode 100644
index 0000000000000..34354e5af0efb
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/modifying/generate.bench.cpp
@@ -0,0 +1,62 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_generate = [](auto first, auto last, auto f) { return std::generate(first, last, f); };
+
+  // {std,ranges}::generate
+  {
+    auto bm = []<class Container>(std::string name, auto generate) {
+      benchmark::RegisterBenchmark(
+          name,
+          [generate](auto& st) {
+            std::size_t const size = st.range(0);
+            Container c(size);
+            using ValueType = typename Container::value_type;
+            ValueType x     = Generate<ValueType>::random();
+
+            for ([[maybe_unused]] auto _ : st) {
+              benchmark::DoNotOptimize(c);
+              generate(c.begin(), c.end(), [&x] {
+                benchmark::DoNotOptimize(x);
+                return x;
+              });
+              benchmark::DoNotOptimize(c);
+            }
+          })
+          ->Arg(32)
+          ->Arg(50) // non power-of-two
+          ->Arg(1024)
+          ->Arg(8192);
+    };
+    bm.operator()<std::vector<int>>("std::generate(vector<int>)", std_generate);
+    bm.operator()<std::deque<int>>("std::generate(deque<int>)", std_generate);
+    bm.operator()<std::list<int>>("std::generate(list<int>)", std_generate);
+    bm.operator()<std::vector<int>>("rng::generate(vector<int>)", std::ranges::generate);
+    bm.operator()<std::deque<int>>("rng::generate(deque<int>)", std::ranges::generate);
+    bm.operator()<std::list<int>>("rng::generate(list<int>)", std::ranges::generate);
+  }
+
+  benchmark::Initialize(&argc, argv);
+  benchmark::RunSpecifiedBenchmarks();
+  benchmark::Shutdown();
+  return 0;
+}

diff  --git a/libcxx/test/benchmarks/algorithms/modifying/generate_n.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/generate_n.bench.cpp
new file mode 100644
index 0000000000000..9f8fb1e07524d
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/modifying/generate_n.bench.cpp
@@ -0,0 +1,62 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_generate_n = [](auto out, auto n, auto f) { return std::generate_n(out, n, f); };
+
+  // {std,ranges}::generate_n
+  {
+    auto bm = []<class Container>(std::string name, auto generate_n) {
+      benchmark::RegisterBenchmark(
+          name,
+          [generate_n](auto& st) {
+            std::size_t const size = st.range(0);
+            Container c(size);
+            using ValueType = typename Container::value_type;
+            ValueType x     = Generate<ValueType>::random();
+
+            for ([[maybe_unused]] auto _ : st) {
+              benchmark::DoNotOptimize(c);
+              generate_n(c.begin(), size, [&x] {
+                benchmark::DoNotOptimize(x);
+                return x;
+              });
+              benchmark::DoNotOptimize(c);
+            }
+          })
+          ->Arg(32)
+          ->Arg(50) // non power-of-two
+          ->Arg(1024)
+          ->Arg(8192);
+    };
+    bm.operator()<std::vector<int>>("std::generate_n(vector<int>)", std_generate_n);
+    bm.operator()<std::deque<int>>("std::generate_n(deque<int>)", std_generate_n);
+    bm.operator()<std::list<int>>("std::generate_n(list<int>)", std_generate_n);
+    bm.operator()<std::vector<int>>("rng::generate_n(vector<int>)", std::ranges::generate_n);
+    bm.operator()<std::deque<int>>("rng::generate_n(deque<int>)", std::ranges::generate_n);
+    bm.operator()<std::list<int>>("rng::generate_n(list<int>)", std::ranges::generate_n);
+  }
+
+  benchmark::Initialize(&argc, argv);
+  benchmark::RunSpecifiedBenchmarks();
+  benchmark::Shutdown();
+  return 0;
+}

diff  --git a/libcxx/test/benchmarks/algorithms/modifying/move.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/move.bench.cpp
new file mode 100644
index 0000000000000..7473dffc123ce
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/modifying/move.bench.cpp
@@ -0,0 +1,87 @@
+//===----------------------------------------------------------------------===//
+//
+// 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"
+#include "test_macros.h"
+
+int main(int argc, char** argv) {
+  auto std_move = [](auto first, auto last, auto out) { return std::move(first, last, out); };
+
+  // {std,ranges}::move(normal container)
+  {
+    auto bm = []<class Container>(std::string name, auto move) {
+      benchmark::RegisterBenchmark(name, [move](auto& st) {
+        std::size_t const size = st.range(0);
+        using ValueType        = typename Container::value_type;
+        Container c1(size);
+        Container c2(size);
+        std::generate_n(c1.begin(), size, [] { return Generate<ValueType>::random(); });
+
+        Container* in  = &c1;
+        Container* out = &c2;
+        for ([[maybe_unused]] auto _ : st) {
+          benchmark::DoNotOptimize(in);
+          benchmark::DoNotOptimize(out);
+          auto result = move(in->begin(), in->end(), out->begin());
+          benchmark::DoNotOptimize(result);
+          std::swap(in, out);
+        }
+      })->Range(8, 1 << 20);
+    };
+    bm.operator()<std::vector<int>>("std::move(vector<int>)", std_move);
+    bm.operator()<std::deque<int>>("std::move(deque<int>)", std_move);
+    bm.operator()<std::list<int>>("std::move(list<int>)", std_move);
+    bm.operator()<std::vector<int>>("rng::move(vector<int>)", std::ranges::move);
+    bm.operator()<std::deque<int>>("rng::move(deque<int>)", std::ranges::move);
+    bm.operator()<std::list<int>>("rng::move(list<int>)", std::ranges::move);
+  }
+
+  // {std,ranges}::move(vector<bool>)
+  {
+    auto bm = []<bool Aligned>(std::string name, auto move) {
+      benchmark::RegisterBenchmark(name, [move](auto& st) {
+        std::size_t const size = st.range(0);
+        std::vector<bool> c1(size, true);
+        std::vector<bool> c2(size, false);
+
+        std::vector<bool>* in  = &c1;
+        std::vector<bool>* out = &c2;
+        for ([[maybe_unused]] auto _ : st) {
+          benchmark::DoNotOptimize(in);
+          benchmark::DoNotOptimize(out);
+          auto first  = Aligned ? in->begin() : in->begin() + 4;
+          auto result = move(first, in->end(), out->begin());
+          benchmark::DoNotOptimize(result);
+          std::swap(in, out);
+        }
+      })->Range(64, 1 << 20);
+    };
+    bm.operator()<true>("std::move(vector<bool>) (aligned)", std_move);
+    bm.operator()<false>("std::move(vector<bool>) (unaligned)", std_move);
+#if TEST_STD_VER >= 23 // vector<bool>::iterator is not an output_iterator before C++23
+    bm.operator()<true>("rng::move(vector<bool>) (aligned)", std::ranges::move);
+    bm.operator()<false>("rng::move(vector<bool>) (unaligned)", std::ranges::move);
+#endif
+  }
+
+  benchmark::Initialize(&argc, argv);
+  benchmark::RunSpecifiedBenchmarks();
+  benchmark::Shutdown();
+  return 0;
+}

diff  --git a/libcxx/test/benchmarks/algorithms/modifying/move_backward.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/move_backward.bench.cpp
new file mode 100644
index 0000000000000..1cdc880910686
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/modifying/move_backward.bench.cpp
@@ -0,0 +1,87 @@
+//===----------------------------------------------------------------------===//
+//
+// 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"
+#include "test_macros.h"
+
+int main(int argc, char** argv) {
+  auto std_move_backward = [](auto first, auto last, auto out) { return std::move_backward(first, last, out); };
+
+  // {std,ranges}::move_backward(normal container)
+  {
+    auto bm = []<class Container>(std::string name, auto move_backward) {
+      benchmark::RegisterBenchmark(name, [move_backward](auto& st) {
+        std::size_t const size = st.range(0);
+        using ValueType        = typename Container::value_type;
+        Container c1(size);
+        Container c2(size);
+        std::generate_n(c1.begin(), size, [] { return Generate<ValueType>::random(); });
+
+        Container* in  = &c1;
+        Container* out = &c2;
+        for ([[maybe_unused]] auto _ : st) {
+          benchmark::DoNotOptimize(in);
+          benchmark::DoNotOptimize(out);
+          auto result = move_backward(in->begin(), in->end(), out->end());
+          benchmark::DoNotOptimize(result);
+          std::swap(in, out);
+        }
+      })->Range(8, 1 << 20);
+    };
+    bm.operator()<std::vector<int>>("std::move_backward(vector<int>)", std_move_backward);
+    bm.operator()<std::deque<int>>("std::move_backward(deque<int>)", std_move_backward);
+    bm.operator()<std::list<int>>("std::move_backward(list<int>)", std_move_backward);
+    bm.operator()<std::vector<int>>("rng::move_backward(vector<int>)", std::ranges::move_backward);
+    bm.operator()<std::deque<int>>("rng::move_backward(deque<int>)", std::ranges::move_backward);
+    bm.operator()<std::list<int>>("rng::move_backward(list<int>)", std::ranges::move_backward);
+  }
+
+  // {std,ranges}::move_backward(vector<bool>)
+  {
+    auto bm = []<bool Aligned>(std::string name, auto move_backward) {
+      benchmark::RegisterBenchmark(name, [move_backward](auto& st) {
+        std::size_t const size = st.range(0);
+        std::vector<bool> c1(size, true);
+        std::vector<bool> c2(size, false);
+
+        std::vector<bool>* in  = &c1;
+        std::vector<bool>* out = &c2;
+        for ([[maybe_unused]] auto _ : st) {
+          benchmark::DoNotOptimize(in);
+          benchmark::DoNotOptimize(out);
+          auto last   = Aligned ? in->end() : in->end() - 4;
+          auto result = move_backward(in->begin(), last, out->end());
+          benchmark::DoNotOptimize(result);
+          std::swap(in, out);
+        }
+      })->Range(64, 1 << 20);
+    };
+    bm.operator()<true>("std::move_backward(vector<bool>) (aligned)", std_move_backward);
+    bm.operator()<false>("std::move_backward(vector<bool>) (unaligned)", std_move_backward);
+#if TEST_STD_VER >= 23 // vector<bool>::iterator is not an output_iterator before C++23
+    bm.operator()<true>("rng::move_backward(vector<bool>) (aligned)", std::ranges::move_backward);
+    bm.operator()<false>("rng::move_backward(vector<bool>) (unaligned)", std::ranges::move_backward);
+#endif
+  }
+
+  benchmark::Initialize(&argc, argv);
+  benchmark::RunSpecifiedBenchmarks();
+  benchmark::Shutdown();
+  return 0;
+}

diff  --git a/libcxx/test/benchmarks/algorithms/modifying/remove.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/remove.bench.cpp
new file mode 100644
index 0000000000000..19cd49641e173
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/modifying/remove.bench.cpp
@@ -0,0 +1,167 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_remove    = [](auto first, auto last, auto const& value) { return std::remove(first, last, value); };
+  auto std_remove_if = [](auto first, auto last, auto const& value) {
+    return std::remove_if(first, last, [&](auto element) {
+      benchmark::DoNotOptimize(element);
+      return element == value;
+    });
+  };
+  auto ranges_remove_if = [](auto first, auto last, auto const& value) {
+    return std::ranges::remove_if(first, last, [&](auto element) {
+      benchmark::DoNotOptimize(element);
+      return element == value;
+    });
+  };
+
+  // Benchmark {std,ranges}::{remove,remove_if} on a sequence of the form xxxxxxxxxxyyyyyyyyyy
+  // where we remove the prefix of x's from the sequence.
+  //
+  // We perform this benchmark in a batch because we need to restore the
+  // state of the container after the operation.
+  {
+    auto bm = []<class Container>(std::string name, auto remove) {
+      benchmark::RegisterBenchmark(
+          name,
+          [remove](auto& st) {
+            std::size_t const size          = st.range(0);
+            constexpr std::size_t BatchSize = 10;
+            using ValueType                 = typename Container::value_type;
+            Container c[BatchSize];
+            ValueType x   = Generate<ValueType>::random();
+            ValueType y   = random_
diff erent_from({x});
+            auto populate = [&](Container& cont) {
+              auto half = cont.size() / 2;
+              std::fill_n(std::fill_n(cont.begin(), half, x), half, y);
+            };
+            for (std::size_t i = 0; i != BatchSize; ++i) {
+              c[i] = Container(size);
+              populate(c[i]);
+            }
+
+            while (st.KeepRunningBatch(BatchSize)) {
+              for (std::size_t i = 0; i != BatchSize; ++i) {
+                benchmark::DoNotOptimize(c[i]);
+                benchmark::DoNotOptimize(x);
+                auto result = remove(c[i].begin(), c[i].end(), x);
+                benchmark::DoNotOptimize(result);
+              }
+
+              st.PauseTiming();
+              for (std::size_t i = 0; i != BatchSize; ++i) {
+                populate(c[i]);
+              }
+              st.ResumeTiming();
+            }
+          })
+          ->Arg(32)
+          ->Arg(50) // non power-of-two
+          ->Arg(1024)
+          ->Arg(8192);
+    };
+    // {std,ranges}::remove
+    bm.operator()<std::vector<int>>("std::remove(vector<int>) (prefix)", std_remove);
+    bm.operator()<std::deque<int>>("std::remove(deque<int>) (prefix)", std_remove);
+    bm.operator()<std::list<int>>("std::remove(list<int>) (prefix)", std_remove);
+    bm.operator()<std::vector<int>>("rng::remove(vector<int>) (prefix)", std::ranges::remove);
+    bm.operator()<std::deque<int>>("rng::remove(deque<int>) (prefix)", std::ranges::remove);
+    bm.operator()<std::list<int>>("rng::remove(list<int>) (prefix)", std::ranges::remove);
+
+    // {std,ranges}::remove_if
+    bm.operator()<std::vector<int>>("std::remove_if(vector<int>) (prefix)", std_remove_if);
+    bm.operator()<std::deque<int>>("std::remove_if(deque<int>) (prefix)", std_remove_if);
+    bm.operator()<std::list<int>>("std::remove_if(list<int>) (prefix)", std_remove_if);
+    bm.operator()<std::vector<int>>("rng::remove_if(vector<int>) (prefix)", ranges_remove_if);
+    bm.operator()<std::deque<int>>("rng::remove_if(deque<int>) (prefix)", ranges_remove_if);
+    bm.operator()<std::list<int>>("rng::remove_if(list<int>) (prefix)", ranges_remove_if);
+  }
+
+  // Benchmark {std,ranges}::remove on a sequence of the form xyxyxyxyxyxyxyxyxyxy
+  // where we remove the x's from the sequence.
+  //
+  // We perform this benchmark in a batch because we need to restore the
+  // state of the container after the operation.
+  {
+    auto bm = []<class Container>(std::string name, auto remove) {
+      benchmark::RegisterBenchmark(
+          name,
+          [remove](auto& st) {
+            std::size_t const size          = st.range(0);
+            constexpr std::size_t BatchSize = 10;
+            using ValueType                 = typename Container::value_type;
+            Container c[BatchSize];
+            ValueType x   = Generate<ValueType>::random();
+            ValueType y   = random_
diff erent_from({x});
+            auto populate = [&](Container& cont) {
+              auto out = cont.begin();
+              for (std::size_t i = 0; i != cont.size(); ++i) {
+                *out++ = (i % 2 == 0 ? x : y);
+              }
+            };
+            for (std::size_t i = 0; i != BatchSize; ++i) {
+              c[i] = Container(size);
+              populate(c[i]);
+            }
+
+            while (st.KeepRunningBatch(BatchSize)) {
+              for (std::size_t i = 0; i != BatchSize; ++i) {
+                benchmark::DoNotOptimize(c[i]);
+                benchmark::DoNotOptimize(x);
+                auto result = remove(c[i].begin(), c[i].end(), x);
+                benchmark::DoNotOptimize(result);
+              }
+
+              st.PauseTiming();
+              for (std::size_t i = 0; i != BatchSize; ++i) {
+                populate(c[i]);
+              }
+              st.ResumeTiming();
+            }
+          })
+          ->Arg(32)
+          ->Arg(50) // non power-of-two
+          ->Arg(1024)
+          ->Arg(8192);
+    };
+    // {std,ranges}::remove
+    bm.operator()<std::vector<int>>("std::remove(vector<int>) (sprinkled)", std_remove);
+    bm.operator()<std::deque<int>>("std::remove(deque<int>) (sprinkled)", std_remove);
+    bm.operator()<std::list<int>>("std::remove(list<int>) (sprinkled)", std_remove);
+    bm.operator()<std::vector<int>>("rng::remove(vector<int>) (sprinkled)", std::ranges::remove);
+    bm.operator()<std::deque<int>>("rng::remove(deque<int>) (sprinkled)", std::ranges::remove);
+    bm.operator()<std::list<int>>("rng::remove(list<int>) (sprinkled)", std::ranges::remove);
+
+    // {std,ranges}::remove_if
+    bm.operator()<std::vector<int>>("std::remove_if(vector<int>) (sprinkled)", std_remove_if);
+    bm.operator()<std::deque<int>>("std::remove_if(deque<int>) (sprinkled)", std_remove_if);
+    bm.operator()<std::list<int>>("std::remove_if(list<int>) (sprinkled)", std_remove_if);
+    bm.operator()<std::vector<int>>("rng::remove_if(vector<int>) (sprinkled)", ranges_remove_if);
+    bm.operator()<std::deque<int>>("rng::remove_if(deque<int>) (sprinkled)", ranges_remove_if);
+    bm.operator()<std::list<int>>("rng::remove_if(list<int>) (sprinkled)", ranges_remove_if);
+  }
+
+  benchmark::Initialize(&argc, argv);
+  benchmark::RunSpecifiedBenchmarks();
+  benchmark::Shutdown();
+  return 0;
+}

diff  --git a/libcxx/test/benchmarks/algorithms/modifying/remove_copy.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/remove_copy.bench.cpp
new file mode 100644
index 0000000000000..582175b8a32cc
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/modifying/remove_copy.bench.cpp
@@ -0,0 +1,138 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_remove_copy = [](auto first, auto last, auto out, auto const& value) {
+    return std::remove_copy(first, last, out, value);
+  };
+  auto std_remove_copy_if = [](auto first, auto last, auto out, auto const& value) {
+    return std::remove_copy_if(first, last, out, [&](auto element) {
+      benchmark::DoNotOptimize(element);
+      return element == value;
+    });
+  };
+  auto ranges_remove_copy_if = [](auto first, auto last, auto out, auto const& value) {
+    return std::ranges::remove_copy_if(first, last, out, [&](auto element) {
+      benchmark::DoNotOptimize(element);
+      return element == value;
+    });
+  };
+
+  // Benchmark {std,ranges}::{remove_copy,remove_copy_if} on a sequence of the form xxxxxxxxxxyyyyyyyyyy
+  // where we remove the prefix of x's from the sequence.
+  {
+    auto bm = []<class Container>(std::string name, auto remove_copy) {
+      benchmark::RegisterBenchmark(
+          name,
+          [remove_copy](auto& st) {
+            std::size_t const size = st.range(0);
+            using ValueType        = typename Container::value_type;
+            Container c;
+            ValueType x = Generate<ValueType>::random();
+            ValueType y = random_
diff erent_from({x});
+            std::fill_n(std::back_inserter(c), size / 2, x);
+            std::fill_n(std::back_inserter(c), size / 2, y);
+
+            std::vector<ValueType> out(size);
+
+            for ([[maybe_unused]] auto _ : st) {
+              benchmark::DoNotOptimize(c);
+              benchmark::DoNotOptimize(out);
+              benchmark::DoNotOptimize(x);
+              auto result = remove_copy(c.begin(), c.end(), out.begin(), x);
+              benchmark::DoNotOptimize(result);
+            }
+          })
+          ->Arg(32)
+          ->Arg(50) // non power-of-two
+          ->Arg(1024)
+          ->Arg(8192);
+    };
+    // {std,ranges}::remove_copy
+    bm.operator()<std::vector<int>>("std::remove_copy(vector<int>) (prefix)", std_remove_copy);
+    bm.operator()<std::deque<int>>("std::remove_copy(deque<int>) (prefix)", std_remove_copy);
+    bm.operator()<std::list<int>>("std::remove_copy(list<int>) (prefix)", std_remove_copy);
+    bm.operator()<std::vector<int>>("rng::remove_copy(vector<int>) (prefix)", std::ranges::remove_copy);
+    bm.operator()<std::deque<int>>("rng::remove_copy(deque<int>) (prefix)", std::ranges::remove_copy);
+    bm.operator()<std::list<int>>("rng::remove_copy(list<int>) (prefix)", std::ranges::remove_copy);
+
+    // {std,ranges}::remove_copy_if
+    bm.operator()<std::vector<int>>("std::remove_copy_if(vector<int>) (prefix)", std_remove_copy_if);
+    bm.operator()<std::deque<int>>("std::remove_copy_if(deque<int>) (prefix)", std_remove_copy_if);
+    bm.operator()<std::list<int>>("std::remove_copy_if(list<int>) (prefix)", std_remove_copy_if);
+    bm.operator()<std::vector<int>>("rng::remove_copy_if(vector<int>) (prefix)", ranges_remove_copy_if);
+    bm.operator()<std::deque<int>>("rng::remove_copy_if(deque<int>) (prefix)", ranges_remove_copy_if);
+    bm.operator()<std::list<int>>("rng::remove_copy_if(list<int>) (prefix)", ranges_remove_copy_if);
+  }
+
+  // Benchmark {std,ranges}::{remove_copy,remove_copy_if} on a sequence of the form xyxyxyxyxyxyxyxyxyxy
+  // where we remove the x's from the sequence.
+  {
+    auto bm = []<class Container>(std::string name, auto remove_copy) {
+      benchmark::RegisterBenchmark(
+          name,
+          [remove_copy](auto& st) {
+            std::size_t const size = st.range(0);
+            using ValueType        = typename Container::value_type;
+            Container c;
+            ValueType x = Generate<ValueType>::random();
+            ValueType y = random_
diff erent_from({x});
+            for (std::size_t i = 0; i != size; ++i) {
+              c.push_back(i % 2 == 0 ? x : y);
+            }
+
+            std::vector<ValueType> out(size);
+
+            for ([[maybe_unused]] auto _ : st) {
+              benchmark::DoNotOptimize(c);
+              benchmark::DoNotOptimize(out);
+              benchmark::DoNotOptimize(x);
+              auto result = remove_copy(c.begin(), c.end(), out.begin(), x);
+              benchmark::DoNotOptimize(result);
+            }
+          })
+          ->Arg(32)
+          ->Arg(50) // non power-of-two
+          ->Arg(1024)
+          ->Arg(8192);
+    };
+    // {std,ranges}::remove_copy
+    bm.operator()<std::vector<int>>("std::remove_copy(vector<int>) (sprinkled)", std_remove_copy);
+    bm.operator()<std::deque<int>>("std::remove_copy(deque<int>) (sprinkled)", std_remove_copy);
+    bm.operator()<std::list<int>>("std::remove_copy(list<int>) (sprinkled)", std_remove_copy);
+    bm.operator()<std::vector<int>>("rng::remove_copy(vector<int>) (sprinkled)", std::ranges::remove_copy);
+    bm.operator()<std::deque<int>>("rng::remove_copy(deque<int>) (sprinkled)", std::ranges::remove_copy);
+    bm.operator()<std::list<int>>("rng::remove_copy(list<int>) (sprinkled)", std::ranges::remove_copy);
+
+    // {std,ranges}::remove_copy_if
+    bm.operator()<std::vector<int>>("std::remove_copy_if(vector<int>) (sprinkled)", std_remove_copy_if);
+    bm.operator()<std::deque<int>>("std::remove_copy_if(deque<int>) (sprinkled)", std_remove_copy_if);
+    bm.operator()<std::list<int>>("std::remove_copy_if(list<int>) (sprinkled)", std_remove_copy_if);
+    bm.operator()<std::vector<int>>("rng::remove_copy_if(vector<int>) (sprinkled)", ranges_remove_copy_if);
+    bm.operator()<std::deque<int>>("rng::remove_copy_if(deque<int>) (sprinkled)", ranges_remove_copy_if);
+    bm.operator()<std::list<int>>("rng::remove_copy_if(list<int>) (sprinkled)", ranges_remove_copy_if);
+  }
+
+  benchmark::Initialize(&argc, argv);
+  benchmark::RunSpecifiedBenchmarks();
+  benchmark::Shutdown();
+  return 0;
+}

diff  --git a/libcxx/test/benchmarks/algorithms/modifying/replace.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/replace.bench.cpp
new file mode 100644
index 0000000000000..bdf26acb8d07f
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/modifying/replace.bench.cpp
@@ -0,0 +1,140 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_replace    = [](auto first, auto last, auto old, auto new_) { return std::replace(first, last, old, new_); };
+  auto std_replace_if = [](auto first, auto last, auto old, auto new_) {
+    auto pred = [&](auto element) {
+      benchmark::DoNotOptimize(element);
+      return element == old;
+    };
+    return std::replace_if(first, last, pred, new_);
+  };
+  auto ranges_replace_if = [](auto first, auto last, auto old, auto new_) {
+    auto pred = [&](auto element) {
+      benchmark::DoNotOptimize(element);
+      return element == old;
+    };
+    return std::ranges::replace_if(first, last, pred, new_);
+  };
+
+  // Create a sequence of the form xxxxxxxxxxyyyyyyyyyy, replace
+  // into zzzzzzzzzzzyyyyyyyyyy and then back.
+  //
+  // This measures the performance of replace() when replacing a large
+  // contiguous sequence of equal values.
+  {
+    auto bm = []<class Container>(std::string name, auto replace) {
+      benchmark::RegisterBenchmark(
+          name,
+          [replace](auto& st) {
+            std::size_t const size = st.range(0);
+            using ValueType        = typename Container::value_type;
+            Container c;
+            ValueType x = Generate<ValueType>::random();
+            ValueType y = random_
diff erent_from({x});
+            ValueType z = random_
diff erent_from({x, y});
+            std::fill_n(std::back_inserter(c), size / 2, x);
+            std::fill_n(std::back_inserter(c), size / 2, y);
+
+            for ([[maybe_unused]] auto _ : st) {
+              benchmark::DoNotOptimize(c);
+              benchmark::DoNotOptimize(x);
+              benchmark::DoNotOptimize(z);
+              replace(c.begin(), c.end(), x, z);
+              benchmark::DoNotOptimize(c);
+              std::swap(x, z);
+            }
+          })
+          ->Arg(32)
+          ->Arg(50) // non power-of-two
+          ->Arg(1024)
+          ->Arg(8192);
+    };
+    // {std,ranges}::replace
+    bm.operator()<std::vector<int>>("std::replace(vector<int>) (prefix)", std_replace);
+    bm.operator()<std::deque<int>>("std::replace(deque<int>) (prefix)", std_replace);
+    bm.operator()<std::list<int>>("std::replace(list<int>) (prefix)", std_replace);
+    bm.operator()<std::vector<int>>("rng::replace(vector<int>) (prefix)", std::ranges::replace);
+    bm.operator()<std::deque<int>>("rng::replace(deque<int>) (prefix)", std::ranges::replace);
+    bm.operator()<std::list<int>>("rng::replace(list<int>) (prefix)", std::ranges::replace);
+
+    // {std,ranges}::replace_if
+    bm.operator()<std::vector<int>>("std::replace_if(vector<int>) (prefix)", std_replace_if);
+    bm.operator()<std::deque<int>>("std::replace_if(deque<int>) (prefix)", std_replace_if);
+    bm.operator()<std::list<int>>("std::replace_if(list<int>) (prefix)", std_replace_if);
+    bm.operator()<std::vector<int>>("rng::replace_if(vector<int>) (prefix)", ranges_replace_if);
+    bm.operator()<std::deque<int>>("rng::replace_if(deque<int>) (prefix)", ranges_replace_if);
+    bm.operator()<std::list<int>>("rng::replace_if(list<int>) (prefix)", ranges_replace_if);
+  }
+
+  // Sprinkle elements to replace inside the range, like xyxyxyxyxyxyxyxyxyxy.
+  {
+    auto bm = []<class Container>(std::string name, auto replace) {
+      benchmark::RegisterBenchmark(
+          name,
+          [replace](auto& st) {
+            std::size_t const size = st.range(0);
+            using ValueType        = typename Container::value_type;
+            Container c;
+            ValueType x = Generate<ValueType>::random();
+            ValueType y = random_
diff erent_from({x});
+            ValueType z = random_
diff erent_from({x, y});
+            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);
+              benchmark::DoNotOptimize(z);
+              replace(c.begin(), c.end(), x, z);
+              benchmark::DoNotOptimize(c);
+              std::swap(x, z);
+            }
+          })
+          ->Arg(32)
+          ->Arg(50) // non power-of-two
+          ->Arg(1024)
+          ->Arg(8192);
+    };
+    // {std,ranges}::replace
+    bm.operator()<std::vector<int>>("std::replace(vector<int>) (sprinkled)", std_replace);
+    bm.operator()<std::deque<int>>("std::replace(deque<int>) (sprinkled)", std_replace);
+    bm.operator()<std::list<int>>("std::replace(list<int>) (sprinkled)", std_replace);
+    bm.operator()<std::vector<int>>("rng::replace(vector<int>) (sprinkled)", std::ranges::replace);
+    bm.operator()<std::deque<int>>("rng::replace(deque<int>) (sprinkled)", std::ranges::replace);
+    bm.operator()<std::list<int>>("rng::replace(list<int>) (sprinkled)", std::ranges::replace);
+
+    // {std,ranges}::replace_if
+    bm.operator()<std::vector<int>>("std::replace_if(vector<int>) (sprinkled)", std_replace_if);
+    bm.operator()<std::deque<int>>("std::replace_if(deque<int>) (sprinkled)", std_replace_if);
+    bm.operator()<std::list<int>>("std::replace_if(list<int>) (sprinkled)", std_replace_if);
+    bm.operator()<std::vector<int>>("rng::replace_if(vector<int>) (sprinkled)", ranges_replace_if);
+    bm.operator()<std::deque<int>>("rng::replace_if(deque<int>) (sprinkled)", ranges_replace_if);
+    bm.operator()<std::list<int>>("rng::replace_if(list<int>) (sprinkled)", ranges_replace_if);
+  }
+
+  benchmark::Initialize(&argc, argv);
+  benchmark::RunSpecifiedBenchmarks();
+  benchmark::Shutdown();
+  return 0;
+}

diff  --git a/libcxx/test/benchmarks/algorithms/modifying/reverse.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/reverse.bench.cpp
new file mode 100644
index 0000000000000..ded7d5018cdbe
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/modifying/reverse.bench.cpp
@@ -0,0 +1,53 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_reverse = [](auto first, auto last) { return std::reverse(first, last); };
+
+  // {std,ranges}::reverse(normal container)
+  {
+    auto bm = []<class Container>(std::string name, auto reverse) {
+      benchmark::RegisterBenchmark(name, [reverse](auto& st) {
+        std::size_t const size = st.range(0);
+        using ValueType        = typename Container::value_type;
+        Container c;
+        std::generate_n(std::back_inserter(c), size, [] { return Generate<ValueType>::random(); });
+
+        for ([[maybe_unused]] auto _ : st) {
+          benchmark::DoNotOptimize(c);
+          reverse(c.begin(), c.end());
+          benchmark::DoNotOptimize(c);
+        }
+      })->Range(8, 1 << 15);
+    };
+    bm.operator()<std::vector<int>>("std::reverse(vector<int>)", std_reverse);
+    bm.operator()<std::deque<int>>("std::reverse(deque<int>)", std_reverse);
+    bm.operator()<std::list<int>>("std::reverse(list<int>)", std_reverse);
+    bm.operator()<std::vector<int>>("rng::reverse(vector<int>)", std::ranges::reverse);
+    bm.operator()<std::deque<int>>("rng::reverse(deque<int>)", std::ranges::reverse);
+    bm.operator()<std::list<int>>("rng::reverse(list<int>)", std::ranges::reverse);
+  }
+
+  benchmark::Initialize(&argc, argv);
+  benchmark::RunSpecifiedBenchmarks();
+  benchmark::Shutdown();
+  return 0;
+}

diff  --git a/libcxx/test/benchmarks/algorithms/modifying/reverse_copy.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/reverse_copy.bench.cpp
new file mode 100644
index 0000000000000..7e19eb71f059a
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/modifying/reverse_copy.bench.cpp
@@ -0,0 +1,56 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_reverse_copy = [](auto first, auto last, auto out) { return std::reverse_copy(first, last, out); };
+
+  // {std,ranges}::reverse_copy(normal container)
+  {
+    auto bm = []<class Container>(std::string name, auto reverse_copy) {
+      benchmark::RegisterBenchmark(name, [reverse_copy](auto& st) {
+        std::size_t const size = st.range(0);
+        using ValueType        = typename Container::value_type;
+        Container c;
+        std::generate_n(std::back_inserter(c), size, [] { return Generate<ValueType>::random(); });
+
+        std::vector<ValueType> out(size);
+
+        for ([[maybe_unused]] auto _ : st) {
+          benchmark::DoNotOptimize(c);
+          benchmark::DoNotOptimize(out);
+          auto result = reverse_copy(c.begin(), c.end(), out.begin());
+          benchmark::DoNotOptimize(result);
+        }
+      })->Range(8, 1 << 15);
+    };
+    bm.operator()<std::vector<int>>("std::reverse_copy(vector<int>)", std_reverse_copy);
+    bm.operator()<std::deque<int>>("std::reverse_copy(deque<int>)", std_reverse_copy);
+    bm.operator()<std::list<int>>("std::reverse_copy(list<int>)", std_reverse_copy);
+    bm.operator()<std::vector<int>>("rng::reverse_copy(vector<int>)", std::ranges::reverse_copy);
+    bm.operator()<std::deque<int>>("rng::reverse_copy(deque<int>)", std::ranges::reverse_copy);
+    bm.operator()<std::list<int>>("rng::reverse_copy(list<int>)", std::ranges::reverse_copy);
+  }
+
+  benchmark::Initialize(&argc, argv);
+  benchmark::RunSpecifiedBenchmarks();
+  benchmark::Shutdown();
+  return 0;
+}

diff  --git a/libcxx/test/benchmarks/algorithms/modifying/rotate.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/rotate.bench.cpp
index eb84eb5cdf25c..d9548a3c176d2 100644
--- a/libcxx/test/benchmarks/algorithms/modifying/rotate.bench.cpp
+++ b/libcxx/test/benchmarks/algorithms/modifying/rotate.bench.cpp
@@ -13,7 +13,6 @@
 #include <deque>
 #include <iterator>
 #include <list>
-#include <ranges>
 #include <string>
 #include <vector>
 
@@ -45,15 +44,110 @@ int main(int argc, char** argv) {
           })
           ->Arg(32)
           ->Arg(50) // non power-of-two
-          ->RangeMultiplier(2)
-          ->Range(64, 1 << 20);
+          ->Arg(1024)
+          ->Arg(8192);
     };
+    bm.operator()<std::vector<int>>("std::rotate(vector<int>) (by 1/4)", std_rotate, 0.25);
+    bm.operator()<std::deque<int>>("std::rotate(deque<int>) (by 1/4)", std_rotate, 0.25);
+    bm.operator()<std::list<int>>("std::rotate(list<int>) (by 1/4)", std_rotate, 0.25);
+    bm.operator()<std::vector<int>>("rng::rotate(vector<int>) (by 1/4)", std::ranges::rotate, 0.25);
+    bm.operator()<std::deque<int>>("rng::rotate(deque<int>) (by 1/4)", std::ranges::rotate, 0.25);
+    bm.operator()<std::list<int>>("rng::rotate(list<int>) (by 1/4)", std::ranges::rotate, 0.25);
+
+    bm.operator()<std::vector<int>>("std::rotate(vector<int>) (by 1/3)", std_rotate, 0.33);
+    bm.operator()<std::deque<int>>("std::rotate(deque<int>) (by 1/3)", std_rotate, 0.33);
+    bm.operator()<std::list<int>>("std::rotate(list<int>) (by 1/3)", std_rotate, 0.33);
+    bm.operator()<std::vector<int>>("rng::rotate(vector<int>) (by 1/3)", std::ranges::rotate, 0.33);
+    bm.operator()<std::deque<int>>("rng::rotate(deque<int>) (by 1/3)", std::ranges::rotate, 0.33);
+    bm.operator()<std::list<int>>("rng::rotate(list<int>) (by 1/3)", std::ranges::rotate, 0.33);
+
+    bm.operator()<std::vector<int>>("std::rotate(vector<int>) (by 1/2)", std_rotate, 0.50);
+    bm.operator()<std::deque<int>>("std::rotate(deque<int>) (by 1/2)", std_rotate, 0.50);
+    bm.operator()<std::list<int>>("std::rotate(list<int>) (by 1/2)", std_rotate, 0.50);
+    bm.operator()<std::vector<int>>("rng::rotate(vector<int>) (by 1/2)", std::ranges::rotate, 0.50);
+    bm.operator()<std::deque<int>>("rng::rotate(deque<int>) (by 1/2)", std::ranges::rotate, 0.50);
+    bm.operator()<std::list<int>>("rng::rotate(list<int>) (by 1/2)", std::ranges::rotate, 0.50);
 
     bm.operator()<std::vector<bool>>("std::rotate(vector<bool>) (by 1/4)", std_rotate, 0.25);
-    bm.operator()<std::vector<bool>>("std::rotate(vector<bool>) (by 51%)", std_rotate, 0.51);
+    bm.operator()<std::vector<bool>>("std::rotate(vector<bool>) (by 1/3)", std_rotate, 0.33);
+    bm.operator()<std::vector<bool>>("std::rotate(vector<bool>) (by 1/2)", std_rotate, 0.50);
+
 #if TEST_STD_VER >= 23 // vector<bool>::iterator is not std::permutable before C++23
     bm.operator()<std::vector<bool>>("rng::rotate(vector<bool>) (by 1/4)", std::ranges::rotate, 0.25);
-    bm.operator()<std::vector<bool>>("rng::rotate(vector<bool>) (by 51%)", std::ranges::rotate, 0.51);
+    bm.operator()<std::vector<bool>>("rng::rotate(vector<bool>) (by 1/3)", std::ranges::rotate, 0.33);
+    bm.operator()<std::vector<bool>>("rng::rotate(vector<bool>) (by 1/2)", std::ranges::rotate, 0.50);
+#endif
+  }
+
+  // Benchmark {std,ranges}::rotate where we rotate a single element from the beginning to the end of the range.
+  {
+    auto bm = []<class Container>(std::string name, auto rotate) {
+      benchmark::RegisterBenchmark(
+          name,
+          [rotate](auto& st) {
+            std::size_t const size = st.range(0);
+            using ValueType        = typename Container::value_type;
+            Container c;
+            std::generate_n(std::back_inserter(c), size, [] { return Generate<ValueType>::random(); });
+
+            auto pivot = std::next(c.begin());
+            for ([[maybe_unused]] auto _ : st) {
+              benchmark::DoNotOptimize(c);
+              auto result = rotate(c.begin(), pivot, c.end());
+              benchmark::DoNotOptimize(result);
+            }
+          })
+          ->Arg(32)
+          ->Arg(50) // non power-of-two
+          ->Arg(1024)
+          ->Arg(8192);
+    };
+    bm.operator()<std::vector<int>>("std::rotate(vector<int>) (1 element forward)", std_rotate);
+    bm.operator()<std::deque<int>>("std::rotate(deque<int>) (1 element forward)", std_rotate);
+    bm.operator()<std::list<int>>("std::rotate(list<int>) (1 element forward)", std_rotate);
+    bm.operator()<std::vector<int>>("rng::rotate(vector<int>) (1 element forward)", std::ranges::rotate);
+    bm.operator()<std::deque<int>>("rng::rotate(deque<int>) (1 element forward)", std::ranges::rotate);
+    bm.operator()<std::list<int>>("rng::rotate(list<int>) (1 element forward)", std::ranges::rotate);
+
+    bm.operator()<std::vector<bool>>("std::rotate(vector<bool>) (1 element forward)", std_rotate);
+#if TEST_STD_VER >= 23 // vector<bool>::iterator is not std::permutable before C++23
+    bm.operator()<std::vector<bool>>("rng::rotate(vector<bool>) (1 element forward)", std::ranges::rotate);
+#endif
+  }
+
+  // Benchmark {std,ranges}::rotate where we rotate a single element from the end to the beginning of the range.
+  {
+    auto bm = []<class Container>(std::string name, auto rotate) {
+      benchmark::RegisterBenchmark(
+          name,
+          [rotate](auto& st) {
+            std::size_t const size = st.range(0);
+            using ValueType        = typename Container::value_type;
+            Container c;
+            std::generate_n(std::back_inserter(c), size, [] { return Generate<ValueType>::random(); });
+
+            auto pivot = std::next(c.begin(), size - 1);
+            for ([[maybe_unused]] auto _ : st) {
+              benchmark::DoNotOptimize(c);
+              auto result = rotate(c.begin(), pivot, c.end());
+              benchmark::DoNotOptimize(result);
+            }
+          })
+          ->Arg(32)
+          ->Arg(50) // non power-of-two
+          ->Arg(1024)
+          ->Arg(8192);
+    };
+    bm.operator()<std::vector<int>>("std::rotate(vector<int>) (1 element backward)", std_rotate);
+    bm.operator()<std::deque<int>>("std::rotate(deque<int>) (1 element backward)", std_rotate);
+    bm.operator()<std::list<int>>("std::rotate(list<int>) (1 element backward)", std_rotate);
+    bm.operator()<std::vector<int>>("rng::rotate(vector<int>) (1 element backward)", std::ranges::rotate);
+    bm.operator()<std::deque<int>>("rng::rotate(deque<int>) (1 element backward)", std::ranges::rotate);
+    bm.operator()<std::list<int>>("rng::rotate(list<int>) (1 element backward)", std::ranges::rotate);
+
+    bm.operator()<std::vector<bool>>("std::rotate(vector<bool>) (1 element backward)", std_rotate);
+#if TEST_STD_VER >= 23 // vector<bool>::iterator is not std::permutable before C++23
+    bm.operator()<std::vector<bool>>("rng::rotate(vector<bool>) (1 element backward)", std::ranges::rotate);
 #endif
   }
 

diff  --git a/libcxx/test/benchmarks/algorithms/modifying/rotate_copy.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/rotate_copy.bench.cpp
new file mode 100644
index 0000000000000..4ba9110552807
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/modifying/rotate_copy.bench.cpp
@@ -0,0 +1,65 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_rotate_copy = [](auto first, auto middle, auto last, auto out) {
+    return std::rotate_copy(first, middle, last, out);
+  };
+
+  // {std,ranges}::rotate_copy(normal container)
+  {
+    auto bm = []<class Container>(std::string name, auto rotate_copy) {
+      benchmark::RegisterBenchmark(
+          name,
+          [rotate_copy](auto& st) {
+            std::size_t const size = st.range(0);
+            using ValueType        = typename Container::value_type;
+            Container c;
+            std::generate_n(std::back_inserter(c), size, [] { return Generate<ValueType>::random(); });
+
+            std::vector<ValueType> out(size);
+
+            auto middle = std::next(c.begin(), size / 2);
+            for ([[maybe_unused]] auto _ : st) {
+              benchmark::DoNotOptimize(c);
+              benchmark::DoNotOptimize(out);
+              auto result = rotate_copy(c.begin(), middle, c.end(), out.begin());
+              benchmark::DoNotOptimize(result);
+            }
+          })
+          ->Arg(32)
+          ->Arg(50) // non power-of-two
+          ->Arg(1024)
+          ->Arg(8192);
+    };
+    bm.operator()<std::vector<int>>("std::rotate_copy(vector<int>)", std_rotate_copy);
+    bm.operator()<std::deque<int>>("std::rotate_copy(deque<int>)", std_rotate_copy);
+    bm.operator()<std::list<int>>("std::rotate_copy(list<int>)", std_rotate_copy);
+    bm.operator()<std::vector<int>>("rng::rotate_copy(vector<int>)", std::ranges::rotate_copy);
+    bm.operator()<std::deque<int>>("rng::rotate_copy(deque<int>)", std::ranges::rotate_copy);
+    bm.operator()<std::list<int>>("rng::rotate_copy(list<int>)", std::ranges::rotate_copy);
+  }
+
+  benchmark::Initialize(&argc, argv);
+  benchmark::RunSpecifiedBenchmarks();
+  benchmark::Shutdown();
+  return 0;
+}

diff  --git a/libcxx/test/benchmarks/algorithms/modifying/sample.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/sample.bench.cpp
new file mode 100644
index 0000000000000..6cc789f460700
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/modifying/sample.bench.cpp
@@ -0,0 +1,66 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 <random>
+#include <string>
+#include <vector>
+
+#include "benchmark/benchmark.h"
+#include "../../GenerateInput.h"
+
+int main(int argc, char** argv) {
+  auto std_sample = [](auto first, auto last, auto out, auto n, auto& rng) {
+    return std::sample(first, last, out, n, rng);
+  };
+
+  // {std,ranges}::sample(normal container)
+  {
+    auto bm = []<class Container>(std::string name, auto sample) {
+      benchmark::RegisterBenchmark(
+          name,
+          [sample](auto& st) {
+            std::size_t const size = st.range(0);
+            using ValueType        = typename Container::value_type;
+            Container c;
+            std::generate_n(std::back_inserter(c), size, [] { return Generate<ValueType>::random(); });
+
+            std::vector<ValueType> out(size);
+            auto const n = size / 4; // sample 1/4 of the range
+            std::mt19937 rng;
+
+            for ([[maybe_unused]] auto _ : st) {
+              benchmark::DoNotOptimize(c);
+              benchmark::DoNotOptimize(out);
+              auto result = sample(c.begin(), c.end(), out.begin(), n, rng);
+              benchmark::DoNotOptimize(result);
+            }
+          })
+          ->Arg(32)
+          ->Arg(1024)
+          ->Arg(8192);
+    };
+    bm.operator()<std::vector<int>>("std::sample(vector<int>)", std_sample);
+    bm.operator()<std::deque<int>>("std::sample(deque<int>)", std_sample);
+    bm.operator()<std::list<int>>("std::sample(list<int>)", std_sample);
+    bm.operator()<std::vector<int>>("rng::sample(vector<int>)", std::ranges::sample);
+    bm.operator()<std::deque<int>>("rng::sample(deque<int>)", std::ranges::sample);
+    bm.operator()<std::list<int>>("rng::sample(list<int>)", std::ranges::sample);
+  }
+
+  benchmark::Initialize(&argc, argv);
+  benchmark::RunSpecifiedBenchmarks();
+  benchmark::Shutdown();
+  return 0;
+}

diff  --git a/libcxx/test/benchmarks/algorithms/modifying/shift_left.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/shift_left.bench.cpp
new file mode 100644
index 0000000000000..b26526484c66a
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/modifying/shift_left.bench.cpp
@@ -0,0 +1,67 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 <utility>
+#include <vector>
+
+#include "benchmark/benchmark.h"
+#include "../../GenerateInput.h"
+
+int main(int argc, char** argv) {
+  auto std_shift_left = [](auto first, auto last, auto n) { return std::shift_left(first, last, n); };
+
+  // Benchmark std::shift_left where we shift exactly one element, which is the worst case.
+  {
+    auto bm = []<class Container>(std::string name, auto shift_left) {
+      benchmark::RegisterBenchmark(
+          name,
+          [shift_left](auto& st) {
+            std::size_t const size = st.range(0);
+            using ValueType        = typename Container::value_type;
+            Container c;
+            std::generate_n(std::back_inserter(c), size, [] { return Generate<ValueType>::random(); });
+            std::size_t n = 1;
+
+            // To avoid ending up with a fully moved-from range, restore the element that gets
+            // overwritten by the shift after performing the shift.
+            auto first_element = c.begin();
+            auto last_element  = std::next(c.begin(), size - 1);
+
+            for ([[maybe_unused]] auto _ : st) {
+              benchmark::DoNotOptimize(c);
+              benchmark::DoNotOptimize(n);
+              ValueType tmp = *first_element;
+              auto result   = shift_left(c.begin(), c.end(), n);
+              *last_element = std::move(tmp);
+              benchmark::DoNotOptimize(result);
+            }
+          })
+          ->Arg(32)
+          ->Arg(50) // non power-of-two
+          ->Arg(1024)
+          ->Arg(8192);
+    };
+    bm.operator()<std::vector<int>>("std::shift_left(vector<int>)", std_shift_left);
+    bm.operator()<std::deque<int>>("std::shift_left(deque<int>)", std_shift_left);
+    bm.operator()<std::list<int>>("std::shift_left(list<int>)", std_shift_left);
+    // ranges::shift_left not implemented yet
+  }
+
+  benchmark::Initialize(&argc, argv);
+  benchmark::RunSpecifiedBenchmarks();
+  benchmark::Shutdown();
+  return 0;
+}

diff  --git a/libcxx/test/benchmarks/algorithms/modifying/shift_right.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/shift_right.bench.cpp
new file mode 100644
index 0000000000000..42946760fc8a3
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/modifying/shift_right.bench.cpp
@@ -0,0 +1,67 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 <utility>
+#include <vector>
+
+#include "benchmark/benchmark.h"
+#include "../../GenerateInput.h"
+
+int main(int argc, char** argv) {
+  auto std_shift_right = [](auto first, auto last, auto n) { return std::shift_right(first, last, n); };
+
+  // Benchmark std::shift_right where we shift exactly one element, which is the worst case.
+  {
+    auto bm = []<class Container>(std::string name, auto shift_right) {
+      benchmark::RegisterBenchmark(
+          name,
+          [shift_right](auto& st) {
+            std::size_t const size = st.range(0);
+            using ValueType        = typename Container::value_type;
+            Container c;
+            std::generate_n(std::back_inserter(c), size, [] { return Generate<ValueType>::random(); });
+            std::size_t n = 1;
+
+            // To avoid ending up with a fully moved-from range, restore the element that gets
+            // overwritten by the shift after performing the shift.
+            auto first_element = c.begin();
+            auto last_element  = std::next(c.begin(), size - 1);
+
+            for ([[maybe_unused]] auto _ : st) {
+              benchmark::DoNotOptimize(c);
+              benchmark::DoNotOptimize(n);
+              ValueType tmp  = *last_element;
+              auto result    = shift_right(c.begin(), c.end(), n);
+              *first_element = std::move(tmp);
+              benchmark::DoNotOptimize(result);
+            }
+          })
+          ->Arg(32)
+          ->Arg(50) // non power-of-two
+          ->Arg(1024)
+          ->Arg(8192);
+    };
+    bm.operator()<std::vector<int>>("std::shift_right(vector<int>)", std_shift_right);
+    bm.operator()<std::deque<int>>("std::shift_right(deque<int>)", std_shift_right);
+    bm.operator()<std::list<int>>("std::shift_right(list<int>)", std_shift_right);
+    // ranges::shift_right not implemented yet
+  }
+
+  benchmark::Initialize(&argc, argv);
+  benchmark::RunSpecifiedBenchmarks();
+  benchmark::Shutdown();
+  return 0;
+}

diff  --git a/libcxx/test/benchmarks/algorithms/modifying/shuffle.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/shuffle.bench.cpp
new file mode 100644
index 0000000000000..24f7fb6828977
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/modifying/shuffle.bench.cpp
@@ -0,0 +1,57 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 <random>
+#include <string>
+#include <vector>
+
+#include "benchmark/benchmark.h"
+#include "../../GenerateInput.h"
+
+int main(int argc, char** argv) {
+  auto std_shuffle = [](auto first, auto last, auto& rng) { return std::shuffle(first, last, rng); };
+
+  // {std,ranges}::shuffle(normal container)
+  {
+    auto bm = []<class Container>(std::string name, auto shuffle) {
+      benchmark::RegisterBenchmark(
+          name,
+          [shuffle](auto& st) {
+            std::size_t const size = st.range(0);
+            using ValueType        = typename Container::value_type;
+            Container c;
+            std::generate_n(std::back_inserter(c), size, [] { return Generate<ValueType>::random(); });
+            std::mt19937 rng;
+
+            for ([[maybe_unused]] auto _ : st) {
+              benchmark::DoNotOptimize(c);
+              shuffle(c.begin(), c.end(), rng);
+              benchmark::DoNotOptimize(c);
+            }
+          })
+          ->Arg(32)
+          ->Arg(1024)
+          ->Arg(8192);
+    };
+    bm.operator()<std::vector<int>>("std::shuffle(vector<int>)", std_shuffle);
+    bm.operator()<std::deque<int>>("std::shuffle(deque<int>)", std_shuffle);
+    bm.operator()<std::vector<int>>("rng::shuffle(vector<int>)", std::ranges::shuffle);
+    bm.operator()<std::deque<int>>("rng::shuffle(deque<int>)", std::ranges::shuffle);
+  }
+
+  benchmark::Initialize(&argc, argv);
+  benchmark::RunSpecifiedBenchmarks();
+  benchmark::Shutdown();
+  return 0;
+}

diff  --git a/libcxx/test/benchmarks/algorithms/modifying/swap_ranges.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/swap_ranges.bench.cpp
new file mode 100644
index 0000000000000..e9fb201a57d34
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/modifying/swap_ranges.bench.cpp
@@ -0,0 +1,65 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_swap_ranges = [](auto first1, auto last1, auto first2, auto) {
+    return std::swap_ranges(first1, last1, first2);
+  };
+
+  // {std,ranges}::swap_ranges(normal container)
+  {
+    auto bm = []<class Container>(std::string name, auto swap_ranges) {
+      benchmark::RegisterBenchmark(
+          name,
+          [swap_ranges](auto& st) {
+            std::size_t const size = st.range(0);
+            using ValueType        = typename Container::value_type;
+            Container c1, c2;
+            std::generate_n(std::back_inserter(c1), size, [] { return Generate<ValueType>::random(); });
+            std::generate_n(std::back_inserter(c2), size, [] { return Generate<ValueType>::random(); });
+
+            for ([[maybe_unused]] auto _ : st) {
+              benchmark::DoNotOptimize(c1);
+              benchmark::DoNotOptimize(c2);
+              auto result = swap_ranges(c1.begin(), c1.end(), c2.begin(), c2.end());
+              benchmark::DoNotOptimize(result);
+              benchmark::DoNotOptimize(c1);
+              benchmark::DoNotOptimize(c2);
+            }
+          })
+          ->Arg(32)
+          ->Arg(50) // non power-of-two
+          ->Arg(1024)
+          ->Arg(8192);
+    };
+    bm.operator()<std::vector<int>>("std::swap_ranges(vector<int>)", std_swap_ranges);
+    bm.operator()<std::deque<int>>("std::swap_ranges(deque<int>)", std_swap_ranges);
+    bm.operator()<std::list<int>>("std::swap_ranges(list<int>)", std_swap_ranges);
+    bm.operator()<std::vector<int>>("rng::swap_ranges(vector<int>)", std::ranges::swap_ranges);
+    bm.operator()<std::deque<int>>("rng::swap_ranges(deque<int>)", std::ranges::swap_ranges);
+    bm.operator()<std::list<int>>("rng::swap_ranges(list<int>)", std::ranges::swap_ranges);
+  }
+
+  benchmark::Initialize(&argc, argv);
+  benchmark::RunSpecifiedBenchmarks();
+  benchmark::Shutdown();
+  return 0;
+}

diff  --git a/libcxx/test/benchmarks/algorithms/modifying/transform.binary.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/transform.binary.bench.cpp
new file mode 100644
index 0000000000000..c4ea7535aefef
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/modifying/transform.binary.bench.cpp
@@ -0,0 +1,72 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_transform = [](auto first1, auto last1, auto first2, auto, auto out, auto f) {
+    return std::transform(first1, last1, first2, out, f);
+  };
+
+  // {std,ranges}::transform(normal container, normal container)
+  {
+    auto bm = []<class Container>(std::string name, auto transform) {
+      benchmark::RegisterBenchmark(
+          name,
+          [transform](auto& st) {
+            std::size_t const size = st.range(0);
+            using ValueType        = typename Container::value_type;
+            Container c1, c2;
+            std::generate_n(std::back_inserter(c1), size, [] { return Generate<ValueType>::random(); });
+            std::generate_n(std::back_inserter(c2), size, [] { return Generate<ValueType>::random(); });
+
+            std::vector<ValueType> out(size);
+
+            auto f = [](auto x, auto y) {
+              benchmark::DoNotOptimize(x);
+              benchmark::DoNotOptimize(y);
+              return x + y;
+            };
+
+            for ([[maybe_unused]] auto _ : st) {
+              benchmark::DoNotOptimize(c1);
+              benchmark::DoNotOptimize(c2);
+              benchmark::DoNotOptimize(out);
+              auto result = transform(c1.begin(), c1.end(), c2.begin(), c2.end(), out.begin(), f);
+              benchmark::DoNotOptimize(result);
+            }
+          })
+          ->Arg(32)
+          ->Arg(50) // non power-of-two
+          ->Arg(1024)
+          ->Arg(8192);
+    };
+    bm.operator()<std::vector<int>>("std::transform(vector<int>, vector<int>)", std_transform);
+    bm.operator()<std::deque<int>>("std::transform(deque<int>, deque<int>)", std_transform);
+    bm.operator()<std::list<int>>("std::transform(list<int>, list<int>)", std_transform);
+    bm.operator()<std::vector<int>>("rng::transform(vector<int>, vector<int>)", std::ranges::transform);
+    bm.operator()<std::deque<int>>("rng::transform(deque<int>, deque<int>)", std::ranges::transform);
+    bm.operator()<std::list<int>>("rng::transform(list<int>, list<int>)", std::ranges::transform);
+  }
+
+  benchmark::Initialize(&argc, argv);
+  benchmark::RunSpecifiedBenchmarks();
+  benchmark::Shutdown();
+  return 0;
+}

diff  --git a/libcxx/test/benchmarks/algorithms/modifying/transform.unary.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/transform.unary.bench.cpp
new file mode 100644
index 0000000000000..9ae40cb488085
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/modifying/transform.unary.bench.cpp
@@ -0,0 +1,67 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_transform = [](auto first, auto last, auto out, auto f) { return std::transform(first, last, out, f); };
+
+  // {std,ranges}::transform(normal container)
+  {
+    auto bm = []<class Container>(std::string name, auto transform) {
+      benchmark::RegisterBenchmark(
+          name,
+          [transform](auto& st) {
+            std::size_t const size = st.range(0);
+            using ValueType        = typename Container::value_type;
+            Container c;
+            std::generate_n(std::back_inserter(c), size, [] { return Generate<ValueType>::random(); });
+
+            std::vector<ValueType> out(size);
+
+            auto f = [](auto element) {
+              benchmark::DoNotOptimize(element);
+              return element;
+            };
+
+            for ([[maybe_unused]] auto _ : st) {
+              benchmark::DoNotOptimize(c);
+              benchmark::DoNotOptimize(out);
+              auto result = transform(c.begin(), c.end(), out.begin(), f);
+              benchmark::DoNotOptimize(result);
+            }
+          })
+          ->Arg(32)
+          ->Arg(50) // non power-of-two
+          ->Arg(1024)
+          ->Arg(8192);
+    };
+    bm.operator()<std::vector<int>>("std::transform(vector<int>) (identity transform)", std_transform);
+    bm.operator()<std::deque<int>>("std::transform(deque<int>) (identity transform)", std_transform);
+    bm.operator()<std::list<int>>("std::transform(list<int>) (identity transform)", std_transform);
+    bm.operator()<std::vector<int>>("rng::transform(vector<int>) (identity transform)", std::ranges::transform);
+    bm.operator()<std::deque<int>>("rng::transform(deque<int>) (identity transform)", std::ranges::transform);
+    bm.operator()<std::list<int>>("rng::transform(list<int>) (identity transform)", std::ranges::transform);
+  }
+
+  benchmark::Initialize(&argc, argv);
+  benchmark::RunSpecifiedBenchmarks();
+  benchmark::Shutdown();
+  return 0;
+}

diff  --git a/libcxx/test/benchmarks/algorithms/modifying/unique.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/unique.bench.cpp
new file mode 100644
index 0000000000000..c0aee942eef64
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/modifying/unique.bench.cpp
@@ -0,0 +1,171 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_unique      = [](auto first, auto last) { return std::unique(first, last); };
+  auto std_unique_pred = [](auto first, auto last) {
+    return std::unique(first, last, [](auto a, auto b) {
+      benchmark::DoNotOptimize(a);
+      benchmark::DoNotOptimize(b);
+      return a == b;
+    });
+  };
+  auto ranges_unique_pred = [](auto first, auto last) {
+    return std::ranges::unique(first, last, [](auto a, auto b) {
+      benchmark::DoNotOptimize(a);
+      benchmark::DoNotOptimize(b);
+      return a == b;
+    });
+  };
+
+  // Create a sequence of the form xxxxxxxxxxyyyyyyyyyy and unique the
+  // adjacent equal elements.
+  //
+  // We perform this benchmark in a batch because we need to restore the
+  // state of the container after the operation.
+  {
+    auto bm = []<class Container>(std::string name, auto unique) {
+      benchmark::RegisterBenchmark(
+          name,
+          [unique](auto& st) {
+            std::size_t const size          = st.range(0);
+            constexpr std::size_t BatchSize = 10;
+            using ValueType                 = typename Container::value_type;
+            Container c[BatchSize];
+            ValueType x   = Generate<ValueType>::random();
+            ValueType y   = random_
diff erent_from({x});
+            auto populate = [&](Container& cont) {
+              auto half = cont.size() / 2;
+              std::fill_n(std::fill_n(cont.begin(), half, x), half, y);
+            };
+            for (std::size_t i = 0; i != BatchSize; ++i) {
+              c[i] = Container(size);
+              populate(c[i]);
+            }
+
+            while (st.KeepRunningBatch(BatchSize)) {
+              for (std::size_t i = 0; i != BatchSize; ++i) {
+                benchmark::DoNotOptimize(c[i]);
+                auto result = unique(c[i].begin(), c[i].end());
+                benchmark::DoNotOptimize(result);
+              }
+
+              st.PauseTiming();
+              for (std::size_t i = 0; i != BatchSize; ++i) {
+                populate(c[i]);
+              }
+              st.ResumeTiming();
+            }
+          })
+          ->Arg(32)
+          ->Arg(50) // non power-of-two
+          ->Arg(1024)
+          ->Arg(8192);
+    };
+    // {std,ranges}::unique(it, it)
+    bm.operator()<std::vector<int>>("std::unique(vector<int>) (contiguous)", std_unique);
+    bm.operator()<std::deque<int>>("std::unique(deque<int>) (contiguous)", std_unique);
+    bm.operator()<std::list<int>>("std::unique(list<int>) (contiguous)", std_unique);
+    bm.operator()<std::vector<int>>("rng::unique(vector<int>) (contiguous)", std::ranges::unique);
+    bm.operator()<std::deque<int>>("rng::unique(deque<int>) (contiguous)", std::ranges::unique);
+    bm.operator()<std::list<int>>("rng::unique(list<int>) (contiguous)", std::ranges::unique);
+
+    // {std,ranges}::unique(it, it, pred)
+    bm.operator()<std::vector<int>>("std::unique(vector<int>, pred) (contiguous)", std_unique_pred);
+    bm.operator()<std::deque<int>>("std::unique(deque<int>, pred) (contiguous)", std_unique_pred);
+    bm.operator()<std::list<int>>("std::unique(list<int>, pred) (contiguous)", std_unique_pred);
+    bm.operator()<std::vector<int>>("rng::unique(vector<int>, pred) (contiguous)", ranges_unique_pred);
+    bm.operator()<std::deque<int>>("rng::unique(deque<int>, pred) (contiguous)", ranges_unique_pred);
+    bm.operator()<std::list<int>>("rng::unique(list<int>, pred) (contiguous)", ranges_unique_pred);
+  }
+
+  // Create a sequence of the form xxyyxxyyxxyyxxyyxxyy and unique
+  // adjacent equal elements.
+  //
+  // We perform this benchmark in a batch because we need to restore the
+  // state of the container after the operation.
+  {
+    auto bm = []<class Container>(std::string name, auto unique) {
+      benchmark::RegisterBenchmark(
+          name,
+          [unique](auto& st) {
+            std::size_t const size          = st.range(0);
+            constexpr std::size_t BatchSize = 10;
+            using ValueType                 = typename Container::value_type;
+            Container c[BatchSize];
+            ValueType x   = Generate<ValueType>::random();
+            ValueType y   = random_
diff erent_from({x});
+            auto populate = [&](Container& cont) {
+              assert(cont.size() % 4 == 0);
+              auto out = cont.begin();
+              for (std::size_t i = 0; i != cont.size(); i += 4) {
+                *out++ = x;
+                *out++ = x;
+                *out++ = y;
+                *out++ = y;
+              }
+            };
+            for (std::size_t i = 0; i != BatchSize; ++i) {
+              c[i] = Container(size);
+              populate(c[i]);
+            }
+
+            while (st.KeepRunningBatch(BatchSize)) {
+              for (std::size_t i = 0; i != BatchSize; ++i) {
+                benchmark::DoNotOptimize(c[i]);
+                auto result = unique(c[i].begin(), c[i].end());
+                benchmark::DoNotOptimize(result);
+              }
+
+              st.PauseTiming();
+              for (std::size_t i = 0; i != BatchSize; ++i) {
+                populate(c[i]);
+              }
+              st.ResumeTiming();
+            }
+          })
+          ->Arg(32)
+          ->Arg(50) // non power-of-two
+          ->Arg(1024)
+          ->Arg(8192);
+    };
+    // {std,ranges}::unique(it, it)
+    bm.operator()<std::vector<int>>("std::unique(vector<int>) (sprinkled)", std_unique);
+    bm.operator()<std::deque<int>>("std::unique(deque<int>) (sprinkled)", std_unique);
+    bm.operator()<std::list<int>>("std::unique(list<int>) (sprinkled)", std_unique);
+    bm.operator()<std::vector<int>>("rng::unique(vector<int>) (sprinkled)", std::ranges::unique);
+    bm.operator()<std::deque<int>>("rng::unique(deque<int>) (sprinkled)", std::ranges::unique);
+    bm.operator()<std::list<int>>("rng::unique(list<int>) (sprinkled)", std::ranges::unique);
+
+    // {std,ranges}::unique(it, it, pred)
+    bm.operator()<std::vector<int>>("std::unique(vector<int>, pred) (sprinkled)", std_unique_pred);
+    bm.operator()<std::deque<int>>("std::unique(deque<int>, pred) (sprinkled)", std_unique_pred);
+    bm.operator()<std::list<int>>("std::unique(list<int>, pred) (sprinkled)", std_unique_pred);
+    bm.operator()<std::vector<int>>("rng::unique(vector<int>, pred) (sprinkled)", ranges_unique_pred);
+    bm.operator()<std::deque<int>>("rng::unique(deque<int>, pred) (sprinkled)", ranges_unique_pred);
+    bm.operator()<std::list<int>>("rng::unique(list<int>, pred) (sprinkled)", ranges_unique_pred);
+  }
+
+  benchmark::Initialize(&argc, argv);
+  benchmark::RunSpecifiedBenchmarks();
+  benchmark::Shutdown();
+  return 0;
+}

diff  --git a/libcxx/test/benchmarks/algorithms/modifying/unique_copy.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/unique_copy.bench.cpp
new file mode 100644
index 0000000000000..45b52dd23b695
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/modifying/unique_copy.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 <iterator>
+#include <list>
+#include <string>
+#include <vector>
+
+#include "benchmark/benchmark.h"
+#include "../../GenerateInput.h"
+
+int main(int argc, char** argv) {
+  auto std_unique_copy      = [](auto first, auto last, auto out) { return std::unique_copy(first, last, out); };
+  auto std_unique_copy_pred = [](auto first, auto last, auto out) {
+    return std::unique_copy(first, last, out, [](auto a, auto b) {
+      benchmark::DoNotOptimize(a);
+      benchmark::DoNotOptimize(b);
+      return a == b;
+    });
+  };
+  auto ranges_unique_copy_pred = [](auto first, auto last, auto out) {
+    return std::ranges::unique_copy(first, last, out, [](auto a, auto b) {
+      benchmark::DoNotOptimize(a);
+      benchmark::DoNotOptimize(b);
+      return a == b;
+    });
+  };
+
+  // Create a sequence of the form xxxxxxxxxxyyyyyyyyyy and unique the
+  // adjacent equal elements.
+  {
+    auto bm = []<class Container>(std::string name, auto unique_copy) {
+      benchmark::RegisterBenchmark(
+          name,
+          [unique_copy](auto& st) {
+            std::size_t const size = st.range(0);
+            using ValueType        = typename Container::value_type;
+            Container c(size);
+            ValueType x = Generate<ValueType>::random();
+            ValueType y = random_
diff erent_from({x});
+            auto half   = size / 2;
+            std::fill_n(std::fill_n(c.begin(), half, x), half, y);
+
+            std::vector<ValueType> out(size);
+
+            for ([[maybe_unused]] auto _ : st) {
+              benchmark::DoNotOptimize(c);
+              benchmark::DoNotOptimize(out);
+              auto result = unique_copy(c.begin(), c.end(), out.begin());
+              benchmark::DoNotOptimize(result);
+            }
+          })
+          ->Arg(32)
+          ->Arg(1024)
+          ->Arg(8192);
+    };
+    // {std,ranges}::unique_copy(it, it, out)
+    bm.operator()<std::vector<int>>("std::unique_copy(vector<int>) (contiguous)", std_unique_copy);
+    bm.operator()<std::deque<int>>("std::unique_copy(deque<int>) (contiguous)", std_unique_copy);
+    bm.operator()<std::list<int>>("std::unique_copy(list<int>) (contiguous)", std_unique_copy);
+    bm.operator()<std::vector<int>>("rng::unique_copy(vector<int>) (contiguous)", std::ranges::unique_copy);
+    bm.operator()<std::deque<int>>("rng::unique_copy(deque<int>) (contiguous)", std::ranges::unique_copy);
+    bm.operator()<std::list<int>>("rng::unique_copy(list<int>) (contiguous)", std::ranges::unique_copy);
+
+    // {std,ranges}::unique_copy(it, it, out, pred)
+    bm.operator()<std::vector<int>>("std::unique_copy(vector<int>, pred) (contiguous)", std_unique_copy_pred);
+    bm.operator()<std::deque<int>>("std::unique_copy(deque<int>, pred) (contiguous)", std_unique_copy_pred);
+    bm.operator()<std::list<int>>("std::unique_copy(list<int>, pred) (contiguous)", std_unique_copy_pred);
+    bm.operator()<std::vector<int>>("rng::unique_copy(vector<int>, pred) (contiguous)", ranges_unique_copy_pred);
+    bm.operator()<std::deque<int>>("rng::unique_copy(deque<int>, pred) (contiguous)", ranges_unique_copy_pred);
+    bm.operator()<std::list<int>>("rng::unique_copy(list<int>, pred) (contiguous)", ranges_unique_copy_pred);
+  }
+
+  // Create a sequence of the form xxyyxxyyxxyyxxyyxxyy and unique
+  // adjacent equal elements.
+  {
+    auto bm = []<class Container>(std::string name, auto unique_copy) {
+      benchmark::RegisterBenchmark(
+          name,
+          [unique_copy](auto& st) {
+            std::size_t const size = st.range(0);
+            using ValueType        = typename Container::value_type;
+            Container c(size);
+            ValueType x   = Generate<ValueType>::random();
+            ValueType y   = random_
diff erent_from({x});
+            auto populate = [&](Container& cont) {
+              assert(cont.size() % 4 == 0);
+              auto out = cont.begin();
+              for (std::size_t i = 0; i != cont.size(); i += 4) {
+                *out++ = x;
+                *out++ = x;
+                *out++ = y;
+                *out++ = y;
+              }
+            };
+            populate(c);
+
+            std::vector<ValueType> out(size);
+
+            for ([[maybe_unused]] auto _ : st) {
+              benchmark::DoNotOptimize(c);
+              benchmark::DoNotOptimize(out);
+              auto result = unique_copy(c.begin(), c.end(), out.begin());
+              benchmark::DoNotOptimize(result);
+            }
+          })
+          ->Arg(32)
+          ->Arg(50) // non power-of-two
+          ->Arg(1024)
+          ->Arg(8192);
+    };
+    // {std,ranges}::unique_copy(it, it, out)
+    bm.operator()<std::vector<int>>("std::unique_copy(vector<int>) (sprinkled)", std_unique_copy);
+    bm.operator()<std::deque<int>>("std::unique_copy(deque<int>) (sprinkled)", std_unique_copy);
+    bm.operator()<std::list<int>>("std::unique_copy(list<int>) (sprinkled)", std_unique_copy);
+    bm.operator()<std::vector<int>>("rng::unique_copy(vector<int>) (sprinkled)", std::ranges::unique_copy);
+    bm.operator()<std::deque<int>>("rng::unique_copy(deque<int>) (sprinkled)", std::ranges::unique_copy);
+    bm.operator()<std::list<int>>("rng::unique_copy(list<int>) (sprinkled)", std::ranges::unique_copy);
+
+    // {std,ranges}::unique_copy(it, it, out, pred)
+    bm.operator()<std::vector<int>>("std::unique_copy(vector<int>, pred) (sprinkled)", std_unique_copy_pred);
+    bm.operator()<std::deque<int>>("std::unique_copy(deque<int>, pred) (sprinkled)", std_unique_copy_pred);
+    bm.operator()<std::list<int>>("std::unique_copy(list<int>, pred) (sprinkled)", std_unique_copy_pred);
+    bm.operator()<std::vector<int>>("rng::unique_copy(vector<int>, pred) (sprinkled)", ranges_unique_copy_pred);
+    bm.operator()<std::deque<int>>("rng::unique_copy(deque<int>, pred) (sprinkled)", ranges_unique_copy_pred);
+    bm.operator()<std::list<int>>("rng::unique_copy(list<int>, pred) (sprinkled)", ranges_unique_copy_pred);
+  }
+
+  benchmark::Initialize(&argc, argv);
+  benchmark::RunSpecifiedBenchmarks();
+  benchmark::Shutdown();
+  return 0;
+}

diff  --git a/libcxx/test/benchmarks/algorithms/move.bench.cpp b/libcxx/test/benchmarks/algorithms/move.bench.cpp
deleted file mode 100644
index 73f36f0c129de..0000000000000
--- a/libcxx/test/benchmarks/algorithms/move.bench.cpp
+++ /dev/null
@@ -1,71 +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 <ranges>
-#include <vector>
-
-template <bool aligned>
-void bm_ranges_move_vb(benchmark::State& state) {
-  auto n = state.range();
-  std::vector<bool> v1(n, true);
-  std::vector<bool> v2(n, false);
-  benchmark::DoNotOptimize(v1);
-  benchmark::DoNotOptimize(v2);
-  std::vector<bool>* in  = &v1;
-  std::vector<bool>* out = &v2;
-  for (auto _ : state) {
-    if constexpr (aligned) {
-      benchmark::DoNotOptimize(std::ranges::move(*in, std::ranges::begin(*out)));
-    } else {
-      benchmark::DoNotOptimize(
-          std::ranges::move(std::views::counted(in->begin() + 4, n - 4), std::ranges::begin(*out)));
-    }
-    std::swap(in, out);
-    benchmark::DoNotOptimize(in);
-    benchmark::DoNotOptimize(out);
-  }
-}
-
-template <bool aligned>
-void bm_move_vb(benchmark::State& state) {
-  auto n = state.range();
-  std::vector<bool> v1(n, true);
-  std::vector<bool> v2(n, false);
-  benchmark::DoNotOptimize(v1);
-  benchmark::DoNotOptimize(v2);
-  std::vector<bool>* in  = &v1;
-  std::vector<bool>* out = &v2;
-  for (auto _ : state) {
-    auto first1 = in->begin();
-    auto last1  = in->end();
-    auto first2 = out->begin();
-    if constexpr (aligned) {
-      benchmark::DoNotOptimize(std::move(first1, last1, first2));
-    } else {
-      benchmark::DoNotOptimize(std::move(first1 + 4, last1, first2));
-    }
-    std::swap(in, out);
-    benchmark::DoNotOptimize(in);
-    benchmark::DoNotOptimize(out);
-  }
-}
-
-BENCHMARK(bm_ranges_move_vb<true>)
-    ->Name("bm_ranges_move_vb_aligned")
-    ->Range(8, 1 << 16)
-    ->DenseRange(102400, 204800, 4096);
-BENCHMARK(bm_ranges_move_vb<false>)->Name("bm_ranges_move_vb_unaligned")->Range(8, 1 << 20);
-
-BENCHMARK(bm_move_vb<true>)->Name("bm_move_vb_aligned")->Range(8, 1 << 20);
-BENCHMARK(bm_move_vb<false>)->Name("bm_move_vb_unaligned")->Range(8, 1 << 20);
-
-BENCHMARK_MAIN();

diff  --git a/libcxx/test/benchmarks/algorithms/move_backward.bench.cpp b/libcxx/test/benchmarks/algorithms/move_backward.bench.cpp
deleted file mode 100644
index 23d7395198419..0000000000000
--- a/libcxx/test/benchmarks/algorithms/move_backward.bench.cpp
+++ /dev/null
@@ -1,71 +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 <ranges>
-#include <vector>
-
-template <bool aligned>
-void bm_ranges_move_backward_vb(benchmark::State& state) {
-  auto n = state.range();
-  std::vector<bool> v1(n, true);
-  std::vector<bool> v2(n, false);
-  benchmark::DoNotOptimize(v1);
-  benchmark::DoNotOptimize(v2);
-  std::vector<bool>* in  = &v1;
-  std::vector<bool>* out = &v2;
-  for (auto _ : state) {
-    if constexpr (aligned) {
-      benchmark::DoNotOptimize(std::ranges::move_backward(*in, std::ranges::end(*out)));
-    } else {
-      benchmark::DoNotOptimize(
-          std::ranges::move_backward(std::views::counted(in->begin(), n - 4), std::ranges::end(*out)));
-    }
-    std::swap(in, out);
-    benchmark::DoNotOptimize(in);
-    benchmark::DoNotOptimize(out);
-  }
-}
-
-template <bool aligned>
-void bm_move_backward_vb(benchmark::State& state) {
-  auto n = state.range();
-  std::vector<bool> v1(n, true);
-  std::vector<bool> v2(n, false);
-  benchmark::DoNotOptimize(v1);
-  benchmark::DoNotOptimize(v2);
-  std::vector<bool>* in  = &v1;
-  std::vector<bool>* out = &v2;
-  for (auto _ : state) {
-    auto first1 = in->begin();
-    auto last1  = in->end();
-    auto last2  = out->end();
-    if constexpr (aligned) {
-      benchmark::DoNotOptimize(std::move_backward(first1, last1, last2));
-    } else {
-      benchmark::DoNotOptimize(std::move_backward(first1, last1 - 4, last2));
-    }
-    std::swap(in, out);
-    benchmark::DoNotOptimize(in);
-    benchmark::DoNotOptimize(out);
-  }
-}
-
-BENCHMARK(bm_ranges_move_backward_vb<true>)
-    ->Name("bm_ranges_move_backward_vb_aligned")
-    ->Range(8, 1 << 16)
-    ->DenseRange(102400, 204800, 4096);
-BENCHMARK(bm_ranges_move_backward_vb<false>)->Name("bm_ranges_move_backward_vb_unaligned")->Range(8, 1 << 20);
-
-BENCHMARK(bm_move_backward_vb<true>)->Name("bm_move_backward_vb_aligned")->Range(8, 1 << 20);
-BENCHMARK(bm_move_backward_vb<false>)->Name("bm_move_backward_vb_unaligned")->Range(8, 1 << 20);
-
-BENCHMARK_MAIN();

diff  --git a/libcxx/test/benchmarks/algorithms/reverse.bench.cpp b/libcxx/test/benchmarks/algorithms/reverse.bench.cpp
deleted file mode 100644
index 2d8dd819ac24c..0000000000000
--- a/libcxx/test/benchmarks/algorithms/reverse.bench.cpp
+++ /dev/null
@@ -1,48 +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 <iterator>
-#include <string>
-#include <vector>
-
-#include <benchmark/benchmark.h>
-#include "../GenerateInput.h"
-
-template <class T>
-static void bm_reverse(benchmark::State& state) {
-  std::size_t const n = state.range();
-  std::vector<T> vec;
-  std::generate_n(std::back_inserter(vec), n, [] { return Generate<T>::cheap(); });
-  for (auto _ : state) {
-    std::reverse(vec.begin(), vec.end());
-    benchmark::DoNotOptimize(vec);
-  }
-}
-BENCHMARK(bm_reverse<int>)->Name("std::reverse(vector<int>)")->DenseRange(1, 8)->Range(16, 1 << 20);
-BENCHMARK(bm_reverse<std::string>)->Name("std::reverse(vector<string>)")->DenseRange(1, 8)->Range(16, 1 << 20);
-
-template <class T>
-static void bm_ranges_reverse(benchmark::State& state) {
-  std::size_t const n = state.range();
-  std::vector<T> vec;
-  std::generate_n(std::back_inserter(vec), n, [] { return Generate<T>::cheap(); });
-  for (auto _ : state) {
-    std::ranges::reverse(vec.begin(), vec.end());
-    benchmark::DoNotOptimize(vec);
-  }
-}
-BENCHMARK(bm_ranges_reverse<int>)->Name("ranges::reverse(vector<int>)")->DenseRange(1, 8)->Range(16, 1 << 20);
-BENCHMARK(bm_ranges_reverse<std::string>)
-    ->Name("ranges::reverse(vector<string>)")
-    ->DenseRange(1, 8)
-    ->Range(16, 1 << 20);
-
-BENCHMARK_MAIN();


        


More information about the libcxx-commits mailing list