Skip to content

Commit a2e451d

Browse files
committed
Make for_each segmented iterator optimization valid for C++03
1 parent 176cd70 commit a2e451d

File tree

3 files changed

+33
-25
lines changed

3 files changed

+33
-25
lines changed

libcxx/include/__algorithm/for_each.h

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
#include <__algorithm/iterator_operations.h>
1515
#include <__config>
1616
#include <__iterator/segmented_iterator.h>
17-
#include <__ranges/movable_box.h>
17+
#include <__type_traits/enable_if.h>
1818
#include <__utility/in_place.h>
1919
#include <__utility/move.h>
2020

@@ -27,32 +27,37 @@ _LIBCPP_PUSH_MACROS
2727

2828
_LIBCPP_BEGIN_NAMESPACE_STD
2929

30-
template <class _InputIterator, class _Function>
31-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Function
32-
for_each(_InputIterator __first, _InputIterator __last, _Function __f);
33-
34-
template <class, class _InputIterator, class _Function>
30+
template <class, class _InputIterator, class _Sent, class _Function>
3531
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Function
36-
__for_each(_InputIterator __first, _InputIterator __last, _Function& __f) {
32+
__for_each(_InputIterator __first, _Sent __last, _Function& __f) {
3733
for (; __first != __last; ++__first)
3834
__f(*__first);
3935
return std::move(__f);
4036
}
4137

42-
// __movable_box is available in C++20, but is actually a copyable-box, so optimization is only correct in C++23
43-
#if _LIBCPP_STD_VER >= 23
44-
template <class, class _SegmentedIterator, class _Function>
45-
requires __is_segmented_iterator<_SegmentedIterator>::value
38+
template <class _InputIterator, class _Function>
39+
struct _ForeachSegment {
40+
using _Traits _LIBCPP_NODEBUG = __segmented_iterator_traits<_InputIterator>;
41+
42+
_Function& __func_;
43+
44+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit _ForeachSegment(_Function& __func) : __func_(__func) {}
45+
46+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void
47+
operator()(typename _Traits::__local_iterator __lfirst, typename _Traits::__local_iterator __llast) {
48+
std::__for_each<_ClassicAlgPolicy>(__lfirst, __llast, __func_);
49+
}
50+
};
51+
52+
template <class,
53+
class _SegmentedIterator,
54+
class _Function,
55+
__enable_if_t<__is_segmented_iterator<_SegmentedIterator>::value, int> = 0>
4656
_LIBCPP_HIDE_FROM_ABI constexpr _Function
47-
for_each(_SegmentedIterator __first, _SegmentedIterator __last, _Function& __func) {
48-
ranges::__movable_box<_Function> __wrapped_func(in_place, std::move(__func));
49-
std::__for_each_segment(__first, __last, [&](auto __lfirst, auto __llast) {
50-
__wrapped_func =
51-
ranges::__movable_box<_Function>(in_place, std::for_each(__lfirst, __llast, std::move(*__wrapped_func)));
52-
});
53-
return std::move(*__wrapped_func);
57+
__for_each(_SegmentedIterator __first, _SegmentedIterator __last, _Function& __func) {
58+
std::__for_each_segment(__first, __last, _ForeachSegment<_SegmentedIterator, _Function>(__func));
59+
return std::move(__func);
5460
}
55-
#endif // _LIBCPP_STD_VER >= 23
5661

5762
template <class _InputIterator, class _Function>
5863
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Function

libcxx/include/__algorithm/for_each_n.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <__algorithm/iterator_operations.h>
1515
#include <__config>
1616
#include <__iterator/iterator_traits.h>
17+
#include <__iterator/next.h>
1718
#include <__iterator/segmented_iterator.h>
1819
#include <__type_traits/enable_if.h>
1920
#include <__utility/convert_to_integral.h>
@@ -30,8 +31,7 @@ template <class _InputIterator,
3031
class _Size,
3132
class _Function,
3233
__enable_if_t<!__is_segmented_iterator<_InputIterator>::value ||
33-
(__has_input_iterator_category<_InputIterator>::value &&
34-
!__has_random_access_iterator_category<_InputIterator>::value),
34+
__has_exactly_input_iterator_category<_InputIterator>::value,
3535
int> = 0>
3636
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _InputIterator
3737
for_each_n(_InputIterator __first, _Size __orig_n, _Function __f) {
@@ -49,11 +49,13 @@ template <class _InputIterator,
4949
class _Size,
5050
class _Function,
5151
__enable_if_t<__is_segmented_iterator<_InputIterator>::value &&
52-
__has_random_access_iterator_category<_InputIterator>::value,
52+
__has_forward_iterator_category<_InputIterator>::value,
5353
int> = 0>
5454
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _InputIterator
5555
for_each_n(_InputIterator __first, _Size __orig_n, _Function __f) {
56-
_InputIterator __last = __first + __orig_n;
56+
typedef decltype(std::__convert_to_integral(__orig_n)) _IntegralSize;
57+
_IntegralSize __n = __orig_n;
58+
_InputIterator __last = std::next(__first, __n);
5759
std::__for_each<_ClassicAlgPolicy>(__first, __last, __f);
5860
return __last;
5961
}

libcxx/include/__algorithm/ranges_for_each_n.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <__iterator/concepts.h>
1919
#include <__iterator/incrementable_traits.h>
2020
#include <__iterator/iterator_traits.h>
21+
#include <__iterator/next.h>
2122
#include <__iterator/projected.h>
2223
#include <__ranges/concepts.h>
2324
#include <__utility/move.h>
@@ -42,8 +43,8 @@ struct __for_each_n {
4243
template <input_iterator _Iter, class _Proj = identity, indirectly_unary_invocable<projected<_Iter, _Proj>> _Func>
4344
_LIBCPP_HIDE_FROM_ABI constexpr for_each_n_result<_Iter, _Func>
4445
operator()(_Iter __first, iter_difference_t<_Iter> __count, _Func __func, _Proj __proj = {}) const {
45-
if constexpr (random_access_iterator<_Iter>) {
46-
auto __last = __first + __count;
46+
if constexpr (forward_iterator<_Iter>) {
47+
auto __last = std::ranges::next(__first, __count);
4748
auto __f = [&](auto&& __val) { std::invoke(__func, std::invoke(__proj, __val)); };
4849
std::__for_each<_RangeAlgPolicy>(__first, __last, __f);
4950
return {std::move(__last), std::move(__func)};

0 commit comments

Comments
 (0)