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

Peng Liu via libcxx-commits libcxx-commits at lists.llvm.org
Thu Apr 3 09:48:33 PDT 2025


================
@@ -41,9 +44,20 @@ 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 (std::assignable_from<_Iter&, _Sent>) {
+      _Iter __end = std::move(__last);
+      std::for_each(__first, __end, [&](auto&& __val) { std::invoke(__func, std::invoke(__proj, __val)); });
+      return {std::move(__end), std::move(__func)};
+    } else if constexpr (sized_sentinel_for<_Sent, _Iter>) {
+      auto __end = std::for_each_n(__first, __last - __first, [&](auto&& __val) {
+        std::invoke(__func, std::invoke(__proj, __val));
+      });
+      return {std::move(__end), std::move(__func)};
+    } else {
----------------
winner245 wrote:

Great advice! I have done all the suggested changes. 

The only thing I want to point out that I do have to introduce `std::__for_each_n`, because I cannot add a projection parameter for the standard API `std::for_each_n`. So with your suggestions applied, we now have: 

- `std::for_each` and `ranges::for_each` are thin veneers over `std::__for_each` without any logic
- `std::for_each_n` and `ranges::for_each_n` are a thin veneer over `std::for_each_n` without any logic
- we handle all cases optimally inside `std::__for_each` directly
- we handle all cases optimally inside `std::__for_each_n` directly

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


More information about the libcxx-commits mailing list