Skip to content

Commit 18bf207

Browse files
committed
Address ldionne's comments
1 parent 05161a1 commit 18bf207

File tree

4 files changed

+11
-31
lines changed

4 files changed

+11
-31
lines changed

libcxx/docs/ReleaseNotes/21.rst

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,16 +70,13 @@ Improvements and New Features
7070
- The segmented iterator optimization for ``std::for_each`` has been backported to C++11. Previously it was only available
7171
in C++23 and later.
7272

73-
- The ``std::for_each_n`` algorithm has been optimized for segmented iterators, resulting in a performance improvement of
74-
up to 17.7x for ``std::deque<short>`` iterators, and up to 13.9x for ``std::join_view<vector<vector<short>>>`` iterators.
73+
- The ``std::for_each_n``, ``std::ranges::for_each`` and ``std::ranges::for_each_n`` algorithms have been optimized for
74+
segmented iterators, resulting in a performance improvement of up to 17.7x for ``std::deque<short>`` iterators, and up
75+
to 13.9x for ``std::join_view<vector<vector<short>>>`` iterators.
7576

7677
- The ``bitset::to_string`` function has been optimized, resulting in a performance improvement of up to 8.3x for bitsets
7778
with uniformly distributed zeros and ones, and up to 13.5x and 16.1x for sparse and dense bitsets, respectively.
7879

79-
- The ``std::ranges::for_each`` and ``std::ranges::for_each_n`` algorithms have been optimized for segmented iterators,
80-
resulting in performance improvements of up to 21.3x for ``std::deque::iterator`` and 24.9x for ``join_view`` of
81-
``vector<vector<char>>``.
82-
8380
Deprecations and Removals
8481
-------------------------
8582

libcxx/include/__algorithm/ranges_for_each.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,10 @@ struct __for_each {
4343
template <class _Iter, class _Sent, class _Proj, class _Func>
4444
_LIBCPP_HIDE_FROM_ABI constexpr static for_each_result<_Iter, _Func>
4545
__for_each_impl(_Iter __first, _Sent __last, _Func& __func, _Proj& __proj) {
46-
if constexpr (!std::assignable_from<_Iter&, _Sent> && sized_sentinel_for<_Sent, _Iter>) {
46+
// In the case where we have different iterator and sentinel types, the segmented iterator optimization
47+
// in std::for_each will not kick in. Therefore, we prefer std::for_each_n in that case (whenever we can
48+
// obtain the `n`).
49+
if constexpr (!std::assignable_from<_Iter&, _Sent> && std::sized_sentinel_for<_Sent, _Iter>) {
4750
auto __n = __last - __first;
4851
auto __end = std::__for_each_n(std::move(__first), __n, __func, __proj);
4952
return {std::move(__end), std::move(__func)};

libcxx/test/benchmarks/algorithms/nonmodifying/for_each.bench.cpp

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,7 @@ int main(int argc, char** argv) {
4242
->Arg(8)
4343
->Arg(32)
4444
->Arg(50) // non power-of-two
45-
->Arg(1024)
46-
->Arg(4096)
47-
->Arg(8192)
48-
->Arg(1 << 14)
49-
->Arg(1 << 16)
50-
->Arg(1 << 18);
45+
->Arg(8192);
5146
};
5247
bm.operator()<std::vector<int>>("std::for_each(vector<int>)", std_for_each);
5348
bm.operator()<std::deque<int>>("std::for_each(deque<int>)", std_for_each);
@@ -87,12 +82,7 @@ int main(int argc, char** argv) {
8782
->Arg(8)
8883
->Arg(32)
8984
->Arg(50) // non power-of-two
90-
->Arg(1024)
91-
->Arg(4096)
92-
->Arg(8192)
93-
->Arg(1 << 14)
94-
->Arg(1 << 16)
95-
->Arg(1 << 18);
85+
->Arg(8192);
9686
};
9787
bm.operator()<std::vector<std::vector<int>>>("std::for_each(join_view(vector<vector<int>>))", std_for_each);
9888
bm.operator()<std::vector<std::vector<int>>>("rng::for_each(join_view(vector<vector<int>>)", std::ranges::for_each);

libcxx/test/benchmarks/algorithms/nonmodifying/for_each_n.bench.cpp

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,7 @@ int main(int argc, char** argv) {
4141
->Arg(8)
4242
->Arg(32)
4343
->Arg(50) // non power-of-two
44-
->Arg(1024)
45-
->Arg(4096)
46-
->Arg(8192)
47-
->Arg(1 << 14)
48-
->Arg(1 << 16)
49-
->Arg(1 << 18);
44+
->Arg(8192);
5045
};
5146
bm.operator()<std::vector<int>>("std::for_each_n(vector<int>)", std_for_each_n);
5247
bm.operator()<std::deque<int>>("std::for_each_n(deque<int>)", std_for_each_n);
@@ -84,12 +79,7 @@ int main(int argc, char** argv) {
8479
->Arg(8)
8580
->Arg(32)
8681
->Arg(50) // non power-of-two
87-
->Arg(1024)
88-
->Arg(4096)
89-
->Arg(8192)
90-
->Arg(1 << 14)
91-
->Arg(1 << 16)
92-
->Arg(1 << 18);
82+
->Arg(8192);
9383
};
9484
bm.operator()<std::vector<std::vector<int>>>("std::for_each_n(join_view(vector<vector<int>>))", std_for_each_n);
9585
bm.operator()<std::vector<std::vector<int>>>(

0 commit comments

Comments
 (0)