[libcxx-commits] [libcxx] [libc++] Optimize ranges::{for_each, for_each_n} for segmented iterators (PR #132896)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Thu Mar 27 06:40:47 PDT 2025


================
@@ -40,11 +43,18 @@ struct __for_each_n {
   template <input_iterator _Iter, class _Proj = identity, indirectly_unary_invocable<projected<_Iter, _Proj>> _Func>
   _LIBCPP_HIDE_FROM_ABI constexpr for_each_n_result<_Iter, _Func>
   operator()(_Iter __first, iter_difference_t<_Iter> __count, _Func __func, _Proj __proj = {}) const {
-    while (__count-- > 0) {
-      std::invoke(__func, std::invoke(__proj, *__first));
-      ++__first;
+    if constexpr (forward_iterator<_Iter>) {
+      auto __last = std::ranges::next(__first, __count);
----------------
ldionne wrote:

This is bad if we have a non random-access iterator. For example for a linked list, we have `forward_iterator`s but we'd end up walking the list once to get the `__last`, and then we'd walk it again inside `__for_each`. Did that not show up in the benchmarks? I'd be curious to understand why.

Instead I think what you want here is:

```
if constexpr (random_access_iterator<_Iter>) {
  std::__for_each(__first, __first + __count, __func, __proj);
} else {
  // the loop
}
```

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


More information about the libcxx-commits mailing list