diff options
| author | Peng Liu <winner245@hotmail.com> | 2025-05-21 12:10:50 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-05-21 12:10:50 -0400 |
| commit | 09c266b75db43665b090592782ec13757358a083 (patch) | |
| tree | 608146f3e0f6b4ad59aae0fe6cdfa790c43cb849 /libcxx/include/__algorithm | |
| parent | 5a3776af521b8ddc14a19d1954af64e2960d2397 (diff) | |
[libc++] Optimize std::for_each_n for segmented iterators (#135468)
This patch enhances the performance of `std::for_each_n` when used with
segmented iterators, leading to significant performance improvements,
summarized in the tables below. This addresses a subtask of
https://github.com/llvm/llvm-project/issues/102817.
Diffstat (limited to 'libcxx/include/__algorithm')
| -rw-r--r-- | libcxx/include/__algorithm/for_each_n.h | 69 | ||||
| -rw-r--r-- | libcxx/include/__algorithm/for_each_n_segment.h | 63 |
2 files changed, 125 insertions, 7 deletions
diff --git a/libcxx/include/__algorithm/for_each_n.h b/libcxx/include/__algorithm/for_each_n.h index fce380b49df3..29351ec39f4e 100644 --- a/libcxx/include/__algorithm/for_each_n.h +++ b/libcxx/include/__algorithm/for_each_n.h @@ -10,20 +10,35 @@ #ifndef _LIBCPP___ALGORITHM_FOR_EACH_N_H #define _LIBCPP___ALGORITHM_FOR_EACH_N_H +#include <__algorithm/for_each.h> +#include <__algorithm/for_each_n_segment.h> #include <__config> +#include <__iterator/iterator_traits.h> +#include <__iterator/segmented_iterator.h> +#include <__type_traits/disjunction.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/negation.h> #include <__utility/convert_to_integral.h> +#include <__utility/move.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header #endif -_LIBCPP_BEGIN_NAMESPACE_STD +_LIBCPP_PUSH_MACROS +#include <__undef_macros> -#if _LIBCPP_STD_VER >= 17 +_LIBCPP_BEGIN_NAMESPACE_STD -template <class _InputIterator, class _Size, class _Function> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _InputIterator -for_each_n(_InputIterator __first, _Size __orig_n, _Function __f) { +template <class _InputIterator, + class _Size, + class _Func, + __enable_if_t<!__has_random_access_iterator_category<_InputIterator>::value && + _Or< _Not<__is_segmented_iterator<_InputIterator> >, + _Not<__has_random_access_local_iterator<_InputIterator> > >::value, + int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _InputIterator +__for_each_n(_InputIterator __first, _Size __orig_n, _Func& __f) { typedef decltype(std::__convert_to_integral(__orig_n)) _IntegralSize; _IntegralSize __n = __orig_n; while (__n > 0) { @@ -31,11 +46,51 @@ for_each_n(_InputIterator __first, _Size __orig_n, _Function __f) { ++__first; --__n; } - return __first; + return std::move(__first); } -#endif +template <class _RandIter, + class _Size, + class _Func, + __enable_if_t<__has_random_access_iterator_category<_RandIter>::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _RandIter +__for_each_n(_RandIter __first, _Size __orig_n, _Func& __f) { + typename std::iterator_traits<_RandIter>::difference_type __n = __orig_n; + auto __last = __first + __n; + std::__for_each(__first, __last, __f); + return std::move(__last); +} + +#ifndef _LIBCPP_CXX03_LANG +template <class _SegmentedIterator, + class _Size, + class _Func, + __enable_if_t<!__has_random_access_iterator_category<_SegmentedIterator>::value && + __is_segmented_iterator<_SegmentedIterator>::value && + __has_random_access_iterator_category< + typename __segmented_iterator_traits<_SegmentedIterator>::__local_iterator>::value, + int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _SegmentedIterator +__for_each_n(_SegmentedIterator __first, _Size __orig_n, _Func& __f) { + using __local_iterator_t = typename __segmented_iterator_traits<_SegmentedIterator>::__local_iterator; + return std::__for_each_n_segment(__first, __orig_n, [&](__local_iterator_t __lfirst, __local_iterator_t __llast) { + std::__for_each(__lfirst, __llast, __f); + }); +} +#endif // !_LIBCPP_CXX03_LANG + +#if _LIBCPP_STD_VER >= 17 + +template <class _InputIterator, class _Size, class _Function> +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _InputIterator +for_each_n(_InputIterator __first, _Size __orig_n, _Function __f) { + return std::__for_each_n(__first, __orig_n, __f); +} + +#endif // _LIBCPP_STD_VER >= 17 _LIBCPP_END_NAMESPACE_STD +_LIBCPP_POP_MACROS + #endif // _LIBCPP___ALGORITHM_FOR_EACH_N_H diff --git a/libcxx/include/__algorithm/for_each_n_segment.h b/libcxx/include/__algorithm/for_each_n_segment.h new file mode 100644 index 000000000000..1b522fb373ee --- /dev/null +++ b/libcxx/include/__algorithm/for_each_n_segment.h @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_FOR_EACH_N_SEGMENT_H +#define _LIBCPP___ALGORITHM_FOR_EACH_N_SEGMENT_H + +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__iterator/segmented_iterator.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +// __for_each_n_segment optimizes linear iteration over segmented iterators. It processes a segmented +// input range [__first, __first + __n) by applying the functor __func to each element within the segment. +// The return value of __func is ignored, and the function returns an iterator pointing to one past the +// last processed element in the input range. + +template <class _SegmentedIterator, class _Size, class _Functor> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _SegmentedIterator +__for_each_n_segment(_SegmentedIterator __first, _Size __orig_n, _Functor __func) { + static_assert(__is_segmented_iterator<_SegmentedIterator>::value && + __has_random_access_iterator_category< + typename __segmented_iterator_traits<_SegmentedIterator>::__local_iterator>::value, + "__for_each_n_segment only works with segmented iterators with random-access local iterators"); + if (__orig_n <= 0) + return __first; + + using _Traits = __segmented_iterator_traits<_SegmentedIterator>; + using __local_iter_t = typename _Traits::__local_iterator; + using __difference_t = typename std::iterator_traits<__local_iter_t>::difference_type; + __difference_t __n = __orig_n; + auto __seg = _Traits::__segment(__first); + auto __local_first = _Traits::__local(__first); + __local_iter_t __local_last; + + while (__n > 0) { + __local_last = _Traits::__end(__seg); + auto __seg_size = __local_last - __local_first; + if (__n <= __seg_size) { + __local_last = __local_first + __n; + __func(__local_first, __local_last); + break; + } + __func(__local_first, __local_last); + __n -= __seg_size; + __local_first = _Traits::__begin(++__seg); + } + + return _Traits::__compose(__seg, __local_last); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_FOR_EACH_N_SEGMENT_H |
