Skip to content

Commit 198fe3b

Browse files
committed
Consistently extend segmented iterator optimization to ranges::for_each
1 parent ff5366b commit 198fe3b

File tree

2 files changed

+11
-6
lines changed

2 files changed

+11
-6
lines changed

libcxx/docs/ReleaseNotes/21.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ Improvements and New Features
6161
- Updated formatting library to Unicode 16.0.0.
6262

6363
- The ``std::ranges::for_each`` and ``std::ranges::for_each_n`` algorithms have been optimized for segmented iterators,
64-
resulting in performance improvements of up to 21.2x for ``std::deque::iterator`` segmented inputs and 17.9x for
64+
resulting in performance improvements of up to 21.3x for ``std::deque::iterator`` segmented inputs and 24.9x for
6565
``join_view`` of ``vector<vector<T>>``.
6666

6767
Deprecations and Removals

libcxx/include/__algorithm/ranges_for_each.h

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
#define _LIBCPP___ALGORITHM_RANGES_FOR_EACH_H
1111

1212
#include <__algorithm/for_each.h>
13+
#include <__algorithm/for_each_n.h>
1314
#include <__algorithm/in_fun_result.h>
15+
#include <__concepts/assignable.h>
1416
#include <__config>
1517
#include <__functional/identity.h>
1618
#include <__functional/invoke.h>
@@ -42,11 +44,14 @@ struct __for_each {
4244
template <class _Iter, class _Sent, class _Proj, class _Func>
4345
_LIBCPP_HIDE_FROM_ABI constexpr static for_each_result<_Iter, _Func>
4446
__for_each_impl(_Iter __first, _Sent __last, _Func& __func, _Proj& __proj) {
45-
if constexpr (random_access_iterator<_Iter> && sized_sentinel_for<_Sent, _Iter>) {
46-
auto __n = __last - __first;
47-
auto __end = __first + __n;
48-
auto __f = [&](auto&& __val) { std::invoke(__func, std::invoke(__proj, __val)); };
49-
std::__for_each(__first, __end, __f);
47+
if constexpr (std::assignable_from<_Iter&, _Sent>) {
48+
_Iter __end = std::move(__last);
49+
std::for_each(__first, __end, [&](auto&& __val) { std::invoke(__func, std::invoke(__proj, __val)); });
50+
return {std::move(__end), std::move(__func)};
51+
} else if constexpr (sized_sentinel_for<_Sent, _Iter>) {
52+
auto __end = std::for_each_n(__first, __last - __first, [&](auto&& __val) {
53+
std::invoke(__func, std::invoke(__proj, __val));
54+
});
5055
return {std::move(__end), std::move(__func)};
5156
} else {
5257
for (; __first != __last; ++__first)

0 commit comments

Comments
 (0)