[libcxx-commits] [libcxx] [libc++] Optimize ranges::copy for random_access_iterator inputs and vector<bool> iterator outputs (PR #120134)

Peng Liu via libcxx-commits libcxx-commits at lists.llvm.org
Thu Jun 26 05:51:36 PDT 2025


================
@@ -448,6 +449,173 @@ void sequence_container_benchmarks(std::string container) {
         }
       });
   }
+
+  ////////////////////////////////////////////////////////////////////////////////////////////////
+  // Additional benchmarks for vector<bool> iterator-pair and range-based operations
+  ////////////////////////////////////////////////////////////////////////////////////////////////
+
+  static constexpr bool is_vector_bool = requires {
+    typename Container::allocator_type;
+  } && std::same_as<std::remove_cvref_t<Container>, std::vector<bool, typename Container::allocator_type>>;
+
+  if constexpr (is_vector_bool) {
+    auto bench_vb = [&](std::string operation, auto f) {
+      benchmark::RegisterBenchmark(container + "::" + operation, f)->Arg(1024)->Arg(1 << 16)->Arg(1 << 20);
+    };
+
+    { // iterator-pair ctor
+      auto bm = [&generators, &bench_vb, &tostr]<template <class> class Iter>(std::string iter) {
+        for (auto gen : generators)
+          bench_vb("ctor(" + iter + ", " + iter + ")" + tostr(gen), [gen](auto& st) {
+            auto const size = st.range(0);
+            std::vector<int> in;
+            std::generate_n(std::back_inserter(in), size, gen);
+            benchmark::DoNotOptimize(in);
+            const auto begin = Iter(in.begin());
+            const auto end   = Iter(in.end());
+            benchmark::DoNotOptimize(in);
+
+            for ([[maybe_unused]] auto _ : st) {
+              Container c(begin, end); // we assume the destructor doesn't dominate the benchmark
+              DoNotOptimizeData(c);
+            }
+          });
+      };
+      bm.template operator()<random_access_iterator>("ra_iter");
+    }
+    { // iterator-pair assignment
+      auto bm = [&generators, &bench_vb, &tostr]<template <class> class Iter>(std::string iter) {
+        for (auto gen : generators)
+          bench_vb("assign(" + iter + ", " + iter + ")" + tostr(gen), [gen](auto& st) {
+            auto const size = st.range(0);
+            std::vector<int> in1, in2;
+            std::generate_n(std::back_inserter(in1), size, gen);
+            std::generate_n(std::back_inserter(in2), size, gen);
+            DoNotOptimizeData(in1);
+            DoNotOptimizeData(in2);
+
+            Container c(in1.begin(), in1.end());
+            bool toggle = true;
+            for ([[maybe_unused]] auto _ : st) {
+              auto& in = toggle ? in2 : in1;
+              c.assign(Iter(in.begin()), Iter(in.end()));
+              toggle = !toggle;
+              DoNotOptimizeData(c);
+            }
+          });
+      };
+      bm.template operator()<random_access_iterator>("ra_iter");
+    }
+    { // Iterator-pair insertion
+      auto bm = [&generators, &bench_vb, &tostr]<template <class> class Iter>(std::string iter) {
+        for (auto gen : generators)
+          bench_vb("insert(begin, " + iter + ", " + iter + ")" + tostr(gen), [gen](auto& st) {
+            auto const size = st.range(0);
+            std::vector<int> in;
+            Container c;
+            std::generate_n(std::back_inserter(in), size, gen);
+            std::generate_n(std::back_inserter(c), size, gen);
+            DoNotOptimizeData(in);
+            DoNotOptimizeData(c);
+
+            for ([[maybe_unused]] auto _ : st) {
+              c.insert(c.begin(), Iter(in.begin()), Iter(in.end()));
+              c.erase(c.begin() + size, c.end()); // avoid growing indefinitely
+              DoNotOptimizeData(c);
+            }
+          });
+      };
+      bm.template operator()<random_access_iterator>("ra_iter");
+    }
+
+#if defined(__cpp_lib_containers_ranges) && __cpp_lib_containers_ranges >= 202202L
+    { // Range-ctor
+      auto bm = [&generators, &bench_vb, &tostr]<template <class, class> class Range>(std::string range) {
+        for (auto gen : generators)
+          bench_vb("ctor(" + range + ")" + tostr(gen), [gen](auto& st) {
+            auto const size = st.range(0);
+            std::vector<int> in;
+            std::generate_n(std::back_inserter(in), size, gen);
+            Range rg(std::ranges::begin(in), std::ranges::end(in));
+            benchmark::DoNotOptimize(in);
+
+            for ([[maybe_unused]] auto _ : st) {
+              Container c(std::from_range, rg); // we assume the destructor doesn't dominate the benchmark
+              DoNotOptimizeData(c);
+            }
+          });
+      };
+      bm.template operator()<random_access_range_wrapper>("ra_range");
+    }
+    { // Range-assignment
+      auto bm = [&generators, &bench_vb, &tostr]<template <class, class> class Range>(std::string range) {
+        for (auto gen : generators)
+          bench_vb("assign_range(" + range + ")" + tostr(gen), [gen](auto& st) {
+            auto const size = st.range(0);
+            std::vector<int> in1, in2;
+            std::generate_n(std::back_inserter(in1), size, gen);
+            std::generate_n(std::back_inserter(in2), size, gen);
+            Range rg1(std::ranges::begin(in1), std::ranges::end(in1));
+            Range rg2(std::ranges::begin(in2), std::ranges::end(in2));
+            DoNotOptimizeData(in1);
+            DoNotOptimizeData(in2);
+
+            Container c(std::from_range, rg1);
+            bool toggle = true;
+            for ([[maybe_unused]] auto _ : st) {
+              auto& in = toggle ? rg2 : rg1;
+              c.assign_range(in);
+              toggle = !toggle;
+              DoNotOptimizeData(c);
+            }
+          });
+      };
+      bm.template operator()<random_access_range_wrapper>("ra_range");
+    }
+    { // Range-insertion
+      auto bm = [&generators, &bench_vb, &tostr]<template <class, class> class Range>(std::string range) {
+        for (auto gen : generators)
+          bench_vb("insert_range(" + range + ")" + tostr(gen), [gen](auto& st) {
+            auto const size = st.range(0);
+            std::vector<int> in;
+            Container c;
+            std::generate_n(std::back_inserter(in), size, gen);
+            std::generate_n(std::back_inserter(c), size, gen);
+            Range rg(std::ranges::begin(in), std::ranges::end(in));
+            DoNotOptimizeData(in);
+            DoNotOptimizeData(c);
+
+            for ([[maybe_unused]] auto _ : st) {
+              c.insert_range(c.begin(), in);
----------------
winner245 wrote:

Done. 

https://github.com/llvm/llvm-project/pull/120134


More information about the libcxx-commits mailing list