[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:46 PDT 2025


================
@@ -41,9 +43,17 @@ struct __for_each {
   template <class _Iter, class _Sent, class _Proj, class _Func>
   _LIBCPP_HIDE_FROM_ABI constexpr static for_each_result<_Iter, _Func>
   __for_each_impl(_Iter __first, _Sent __last, _Func& __func, _Proj& __proj) {
-    for (; __first != __last; ++__first)
-      std::invoke(__func, std::invoke(__proj, *__first));
-    return {std::move(__first), std::move(__func)};
+    if constexpr (random_access_iterator<_Iter> && sized_sentinel_for<_Sent, _Iter>) {
+      auto __n   = __last - __first;
+      auto __end = __first + __n;
+      auto __f   = [&](auto&& __val) { std::invoke(__func, std::invoke(__proj, __val)); };
+      std::__for_each<_RangeAlgPolicy>(__first, __end, __f);
+      return {std::move(__end), std::move(__func)};
+    } else {
+      for (; __first != __last; ++__first)
+        std::invoke(__func, std::invoke(__proj, *__first));
+      return {std::move(__first), std::move(__func)};
+    }
----------------
ldionne wrote:

Since the underlying `__for_each` accepts an iterator/sentinel pair, I think you could simply call `std::__for_each(__first, __last, __func, __proj)` here unconditionally, right? You'd need to add a projection to `__for_each` but that's okay, that's usually what we do. In other words, this can change to just


```
std::__for_each(__first, __last, __func, __proj);
return {std::move(__first), std::move(__func)};
```

and everything else is handled inside `__for_each` itself.

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


More information about the libcxx-commits mailing list