https://gcc.gnu.org/g:63f3f898bbfda3678b28ebf923bda5282b4ae654

commit r17-4229-g63f3f898bbfda3678b28ebf923bda5282b4ae654
Author: Yuao Ma <[email protected]>
Date:   Fri Aug 21 22:31:19 2026 +0800

    libstdc++: optimize ranges::for_each for segmented iterators
    
    Similar to r17-3419-g2d11dfb0e2edd9, we can optimize std::for_each for
    segemented iterators.
    
    libstdc++-v3/ChangeLog:
    
            * include/bits/ranges_algo.h (ranges::__for_each): Add
            segemented iterators logic. Split out naive for-loop from ...
            (__for_each_fn::operator()): ... here.
            * testsuite/performance/25_algorithms/for_each.cc: Add
            benchmark for ranges::for_each.

Diff:
---
 libstdc++-v3/include/bits/ranges_algo.h            | 33 ++++++++++++++++++++--
 .../performance/25_algorithms/for_each.cc          | 22 ++++++++++++++-
 2 files changed, 51 insertions(+), 4 deletions(-)

diff --git a/libstdc++-v3/include/bits/ranges_algo.h 
b/libstdc++-v3/include/bits/ranges_algo.h
index 4330d3e70b84..f4c70dc70291 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -211,6 +211,33 @@ namespace ranges
   template<typename _Iter, typename _Fp>
     using for_each_result = in_fun_result<_Iter, _Fp>;
 
+  // Apply __f to the result of applying __proj to each element in
+  // [__first, __last).
+  // Dispatches to __for_each_segment for segmented iterators
+  // (e.g. deque::iterator).
+  // Returns an iterator equal to __last.
+  template<typename _InputIterator, typename _Sentinel, typename _Function,
+          typename _Proj>
+    constexpr _InputIterator
+    __for_each(_InputIterator __first, _Sentinel __last, _Function&& __f,
+              _Proj& __proj)
+    {
+      if constexpr (__segmented_iterator<_InputIterator>
+                   && same_as<_InputIterator, _Sentinel>)
+       {
+         std::__for_each_segment(__first, __last,
+           [&](auto __lfirst, auto __llast)
+           { return ranges::__for_each(__lfirst, __llast, __f, __proj); });
+         return __last;
+       }
+      else
+       {
+         for (; __first != __last; ++__first)
+           std::__invoke(__f, std::__invoke(__proj, *__first));
+         return __first;
+       }
+    }
+
   struct __for_each_fn
   {
     template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
@@ -219,9 +246,9 @@ namespace ranges
       constexpr for_each_result<_Iter, _Fun>
       operator()(_Iter __first, _Sent __last, _Fun __f, _Proj __proj = {}) 
const
       {
-       for (; __first != __last; ++__first)
-         std::__invoke(__f, std::__invoke(__proj, *__first));
-       return { std::move(__first), std::move(__f) };
+       auto __end = ranges::__for_each(std::move(__first), std::move(__last), 
__f,
+                                       __proj);
+       return { std::move(__end), std::move(__f) };
       }
 
     template<input_range _Range, typename _Proj = identity,
diff --git a/libstdc++-v3/testsuite/performance/25_algorithms/for_each.cc 
b/libstdc++-v3/testsuite/performance/25_algorithms/for_each.cc
index 37af5ab59816..65b13be6c21a 100644
--- a/libstdc++-v3/testsuite/performance/25_algorithms/for_each.cc
+++ b/libstdc++-v3/testsuite/performance/25_algorithms/for_each.cc
@@ -15,7 +15,20 @@ void bench_seq(const char* label, __gnu_test::time_counter& 
time,
   start_counters(time, resource);
   for (int i = 0; i < 20000; ++i)
     std::for_each(c.begin(), c.end(),
-                  [](T& x) { x = std::min<T>(100, std::max<T>(x, 10)); });
+                  [](T& x) { x = std::clamp<T>(x, 10, 100); });
+  stop_counters(time, resource);
+  report_performance(__FILE__, label, time, resource);
+  clear_counters(time, resource);
+}
+
+template <typename Container>
+void bench_seq_ranges(const char* label, __gnu_test::time_counter& time,
+                      __gnu_test::resource_counter& resource) {
+  using T = typename Container::value_type;
+  Container c(size, 1);
+  start_counters(time, resource);
+  for (int i = 0; i < 20000; ++i)
+    std::ranges::for_each(c, [](T& x) { x = std::clamp<T>(x, 10, 100); });
   stop_counters(time, resource);
   report_performance(__FILE__, label, time, resource);
   clear_counters(time, resource);
@@ -29,4 +42,11 @@ int main() {
   bench_seq<std::vector<int>>("std::for_each vector<int>", time, resource);
   bench_seq<std::deque<int>>("std::for_each deque<int>", time, resource);
   bench_seq<std::list<int>>("std::for_each list<int>", time, resource);
+
+  bench_seq_ranges<std::vector<int>>("std::ranges::for_each vector<int>", time,
+                                     resource);
+  bench_seq_ranges<std::deque<int>>("std::ranges::for_each deque<int>", time,
+                                    resource);
+  bench_seq_ranges<std::list<int>>("std::ranges::for_each list<int>", time,
+                                   resource);
 }

Reply via email to