[libcxx-commits] [libcxx] [libc++] Optimize {std, ranges}::for_each for iterating over __trees (PR #164405)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Tue Dec 2 08:10:27 PST 2025


================
@@ -0,0 +1,131 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <algorithm>
+
+// template<InputIterator Iter, class Function>
+//   constexpr Function   // constexpr since C++20
+//   for_each(Iter first, Iter last, Function f);
+
+#include <algorithm>
+#include <cassert>
+#include <map>
+#include <set>
+
+template <class Container, class Converter>
+void test_node_container(Converter conv) {
+  Container c;
+  using value_type = typename Container::value_type;
+  for (int i = 0; i != 10; ++i)
+    c.insert(conv(i));
+  { // Simple check
+    {
+      int invoke_count = 0;
+      std::ranges::for_each(c.begin(), c.end(), [&c, &invoke_count](const value_type& i) {
+        assert(&i == &*std::next(c.begin(), invoke_count++));
+      });
+      assert(invoke_count == 10);
+    }
+    {
+      int invoke_count = 0;
+      std::ranges::for_each(c, [&c, &invoke_count](const value_type& i) {
+        assert(&i == &*std::next(c.begin(), invoke_count++));
+      });
+      assert(invoke_count == 10);
+    }
+  }
+  { // Make sure that a start within the container works as expected
+    {
+      int invoke_count = 1;
+      std::ranges::for_each(std::next(c.begin()), c.end(), [&c, &invoke_count](const value_type& i) {
+        assert(&i == &*std::next(c.begin(), invoke_count++));
+      });
+      assert(invoke_count == 10);
+    }
+    {
+      int invoke_count = 1;
+      std::ranges::for_each(
+          std::ranges::subrange(std::next(c.begin()), c.end()),
+          [&c, &invoke_count](const value_type& i) { assert(&i == &*std::next(c.begin(), invoke_count++)); });
+      assert(invoke_count == 10);
+    }
+  }
+  { // Make sure that a start within the container works as expected
+    {
+      int invoke_count = 2;
+      std::ranges::for_each(std::next(c.begin(), 2), c.end(), [&c, &invoke_count](const value_type& i) {
+        assert(&i == &*std::next(c.begin(), invoke_count++));
+      });
+      assert(invoke_count == 10);
+    }
+    {
+      int invoke_count = 2;
+      std::ranges::for_each(
+          std::ranges::subrange(std::next(c.begin(), 2), c.end()),
+          [&c, &invoke_count](const value_type& i) { assert(&i == &*std::next(c.begin(), invoke_count++)); });
+      assert(invoke_count == 10);
+    }
+  }
+  { // Make sure that an end within the container works as expected
+    {
+      int invoke_count = 1;
+      std::ranges::for_each(std::next(c.begin()), std::prev(c.end()), [&c, &invoke_count](const value_type& i) {
+        assert(&i == &*std::next(c.begin(), invoke_count++));
+      });
+      assert(invoke_count == 9);
+    }
+    {
+      int invoke_count = 1;
+      std::ranges::for_each(
+          std::ranges::subrange(std::next(c.begin()), std::prev(c.end())),
+          [&c, &invoke_count](const value_type& i) { assert(&i == &*std::next(c.begin(), invoke_count++)); });
+      assert(invoke_count == 9);
+    }
+  }
+  { // Make sure that an empty range works
+    {
+      int invoke_count = 0;
+      std::ranges::for_each(c.begin(), c.begin(), [&c, &invoke_count](const value_type& i) {
----------------
ldionne wrote:

I think we should also test `for_each(c.end(), c.end())`.

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


More information about the libcxx-commits mailing list