[libcxx-commits] [libcxx] [libcxx] Optimize `std::fold_left_with_iter` for segmented iterators (PR #177853)

via libcxx-commits libcxx-commits at lists.llvm.org
Sun Jan 25 04:40:55 PST 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: Connector Switch (c8ef)

<details>
<summary>Changes</summary>

Part of https://github.com/llvm/llvm-project/issues/102817.

This patch attempts to optimize the performance of `std::fold_left_with_iter` for segmented iterators.

- before

```
# | rng::fold_left(vector<int>)/8             2.78 ns         2.78 ns    241953718
# | rng::fold_left(vector<int>)/32            12.2 ns         12.2 ns     57579851
# | rng::fold_left(vector<int>)/50            19.2 ns         19.2 ns     36487764
# | rng::fold_left(vector<int>)/8192          3226 ns         3226 ns       216811
# | rng::fold_left(vector<int>)/1048576     441842 ns       441839 ns         1592
# | rng::fold_left(deque<int>)/8              2.83 ns         2.83 ns    243888678
# | rng::fold_left(deque<int>)/32             16.6 ns         16.6 ns     42297458
# | rng::fold_left(deque<int>)/50             22.3 ns         22.3 ns     31387998
# | rng::fold_left(deque<int>)/8192           2492 ns         2492 ns       281637
# | rng::fold_left(deque<int>)/1048576      324936 ns       324936 ns         2154
# | rng::fold_left(list<int>)/8               2.54 ns         2.54 ns    275946635
# | rng::fold_left(list<int>)/32              16.2 ns         16.2 ns     42901634
# | rng::fold_left(list<int>)/50              54.7 ns         54.7 ns     12767450
# | rng::fold_left(list<int>)/8192           15154 ns        15154 ns        56744
# | rng::fold_left(list<int>)/1048576      4976906 ns      4976867 ns          158
```

- after

```
# | rng::fold_left(vector<int>)/8             2.74 ns         2.74 ns    255954900
# | rng::fold_left(vector<int>)/32            12.1 ns         12.1 ns     57843462
# | rng::fold_left(vector<int>)/50            19.2 ns         19.2 ns     36422594
# | rng::fold_left(vector<int>)/8192          3202 ns         3202 ns       218265
# | rng::fold_left(vector<int>)/1048576     435718 ns       435709 ns         1609
# | rng::fold_left(deque<int>)/8              2.52 ns         2.52 ns    277288254
# | rng::fold_left(deque<int>)/32             14.1 ns         14.1 ns     52244463
# | rng::fold_left(deque<int>)/50             16.2 ns         16.2 ns     43131857
# | rng::fold_left(deque<int>)/8192           1695 ns         1695 ns       415620
# | rng::fold_left(deque<int>)/1048576      277729 ns       277731 ns         2532
# | rng::fold_left(list<int>)/8               2.55 ns         2.55 ns    277025050
# | rng::fold_left(list<int>)/32              16.2 ns         16.2 ns     43058857
# | rng::fold_left(list<int>)/50              54.7 ns         54.7 ns     12705516
# | rng::fold_left(list<int>)/8192           15236 ns        15235 ns        56840
# | rng::fold_left(list<int>)/1048576      4827263 ns      4827147 ns          152
```

---
Full diff: https://github.com/llvm/llvm-project/pull/177853.diff


2 Files Affected:

- (modified) libcxx/docs/ReleaseNotes/23.rst (+4) 
- (modified) libcxx/include/__algorithm/ranges_fold.h (+12-6) 


``````````diff
diff --git a/libcxx/docs/ReleaseNotes/23.rst b/libcxx/docs/ReleaseNotes/23.rst
index 73f5984768592..046ce4ad22b51 100644
--- a/libcxx/docs/ReleaseNotes/23.rst
+++ b/libcxx/docs/ReleaseNotes/23.rst
@@ -41,6 +41,10 @@ Implemented Papers
 Improvements and New Features
 -----------------------------
 
+- The ``std::ranges::fold_left_with_iter`` algorithm has been optimized for
+  segmented iterators, resulting in a performance improvement for
+  ``std::deque<int>`` iterators.
+
 Deprecations and Removals
 -------------------------
 
diff --git a/libcxx/include/__algorithm/ranges_fold.h b/libcxx/include/__algorithm/ranges_fold.h
index d2c3921398504..82614ec311164 100644
--- a/libcxx/include/__algorithm/ranges_fold.h
+++ b/libcxx/include/__algorithm/ranges_fold.h
@@ -10,12 +10,14 @@
 #ifndef _LIBCPP___ALGORITHM_RANGES_FOLD_H
 #define _LIBCPP___ALGORITHM_RANGES_FOLD_H
 
+#include <__algorithm/for_each.h>
 #include <__concepts/assignable.h>
 #include <__concepts/constructible.h>
 #include <__concepts/convertible_to.h>
 #include <__concepts/invocable.h>
 #include <__concepts/movable.h>
 #include <__config>
+#include <__functional/identity.h>
 #include <__functional/invoke.h>
 #include <__functional/reference_wrapper.h>
 #include <__iterator/concepts.h>
@@ -80,18 +82,22 @@ concept __indirectly_binary_left_foldable =
 struct __fold_left_with_iter {
   template <input_iterator _Ip, sentinel_for<_Ip> _Sp, class _Tp, __indirectly_binary_left_foldable<_Tp, _Ip> _Fp>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Ip __first, _Sp __last, _Tp __init, _Fp __f) {
-    using _Up = decay_t<invoke_result_t<_Fp&, _Tp, iter_reference_t<_Ip>>>;
+    using _Up        = decay_t<invoke_result_t<_Fp&, _Tp, iter_reference_t<_Ip>>>;
+    using __iter_ref = decltype(*__first);
 
     if (__first == __last) {
       return fold_left_with_iter_result<_Ip, _Up>{std::move(__first), _Up(std::move(__init))};
     }
 
     _Up __result = std::invoke(__f, std::move(__init), *__first);
-    for (++__first; __first != __last; ++__first) {
-      __result = std::invoke(__f, std::move(__result), *__first);
-    }
-
-    return fold_left_with_iter_result<_Ip, _Up>{std::move(__first), std::move(__result)};
+    ++__first;
+    auto __for_each_f = [&](__iter_ref __element) {
+      __result = std::invoke(__f, std::move(__result), std::forward<__iter_ref>(__element));
+    };
+    __identity __proj;
+    auto __end = std::__for_each(std::move(__first), std::move(__last), __for_each_f, __proj);
+
+    return fold_left_with_iter_result<_Ip, _Up>{std::move(__end), std::move(__result)};
   }
 
   template <input_range _Rp, class _Tp, __indirectly_binary_left_foldable<_Tp, iterator_t<_Rp>> _Fp>

``````````

</details>


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


More information about the libcxx-commits mailing list