[libc++] Simplify most of the segmented iterator optimizations (#164797)

This patch does two things.
(1) It replaces SFINAE with `if constexpr`, avoiding some overload
resolution and unnecessary boilerplate.
(2) It removes an overload from `__for_each_n` to forward to
`__for_each`, since `__for_each` doesn't provide any further
optimizations.
This commit is contained in:
Nikolas Klauser 2025-11-07 08:27:55 +01:00 committed by GitHub
parent c8adbd7a8b
commit fc5e0c071b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 68 additions and 132 deletions

View file

@ -15,6 +15,7 @@
#include <__iterator/iterator_traits.h>
#include <__iterator/segmented_iterator.h>
#include <__type_traits/enable_if.h>
#include <__type_traits/is_same.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@ -27,6 +28,15 @@ _LIBCPP_BEGIN_NAMESPACE_STD
template <class _ForwardIterator, class _Sentinel, class _Tp>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator
__fill(_ForwardIterator __first, _Sentinel __last, const _Tp& __value) {
#ifndef _LIBCPP_CXX03_LANG
if constexpr (is_same<_ForwardIterator, _Sentinel>::value && __is_segmented_iterator_v<_ForwardIterator>) {
using __local_iterator_t = typename __segmented_iterator_traits<_ForwardIterator>::__local_iterator;
std::__for_each_segment(__first, __last, [&](__local_iterator_t __lfirst, __local_iterator_t __llast) {
std::__fill(__lfirst, __llast, __value);
});
return __last;
}
#endif
for (; __first != __last; ++__first)
*__first = __value;
return __first;
@ -42,18 +52,6 @@ __fill(_RandomAccessIterator __first, _RandomAccessIterator __last, const _Tp& _
return std::__fill_n(__first, __last - __first, __value);
}
#ifndef _LIBCPP_CXX03_LANG
template <class _SegmentedIterator, class _Tp, __enable_if_t<__is_segmented_iterator_v<_SegmentedIterator>, int> = 0>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
_SegmentedIterator __fill(_SegmentedIterator __first, _SegmentedIterator __last, const _Tp& __value) {
using __local_iterator_t = typename __segmented_iterator_traits<_SegmentedIterator>::__local_iterator;
std::__for_each_segment(__first, __last, [&](__local_iterator_t __lfirst, __local_iterator_t __llast) {
std::__fill(__lfirst, __llast, __value);
});
return __last;
}
#endif // !_LIBCPP_CXX03_LANG
template <class _ForwardIterator, class _Tp>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
fill(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) {

View file

@ -16,10 +16,6 @@
#include <__iterator/iterator_traits.h>
#include <__iterator/segmented_iterator.h>
#include <__memory/pointer_traits.h>
#include <__type_traits/conjunction.h>
#include <__type_traits/enable_if.h>
#include <__type_traits/integral_constant.h>
#include <__type_traits/negation.h>
#include <__utility/convert_to_integral.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@ -33,39 +29,24 @@ _LIBCPP_BEGIN_NAMESPACE_STD
// fill_n isn't specialized for std::memset, because the compiler already optimizes the loop to a call to std::memset.
template <class _OutputIterator,
class _Size,
class _Tp
#ifndef _LIBCPP_CXX03_LANG
,
__enable_if_t<!_And<_BoolConstant<__is_segmented_iterator_v<_OutputIterator>>,
__has_random_access_local_iterator<_OutputIterator>>::value,
int> = 0
#endif
>
template <class _OutputIterator, class _Size, class _Tp>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator
__fill_n(_OutputIterator __first, _Size __n, const _Tp& __value) {
#ifndef _LIBCPP_CXX03_LANG
if constexpr (__is_segmented_iterator_v<_OutputIterator>) {
using __local_iterator = typename __segmented_iterator_traits<_OutputIterator>::__local_iterator;
if constexpr (__has_random_access_iterator_category<__local_iterator>::value) {
return std::__for_each_n_segment(__first, __n, [&](__local_iterator __lfirst, __local_iterator __llast) {
std::__fill_n(__lfirst, __llast - __lfirst, __value);
});
}
}
#endif
for (; __n > 0; ++__first, (void)--__n)
*__first = __value;
return __first;
}
#ifndef _LIBCPP_CXX03_LANG
template < class _OutputIterator,
class _Size,
class _Tp,
__enable_if_t<_And<_BoolConstant<__is_segmented_iterator_v<_OutputIterator>>,
__has_random_access_local_iterator<_OutputIterator>>::value,
int> = 0>
inline _LIBCPP_HIDE_FROM_ABI
_LIBCPP_CONSTEXPR_SINCE_CXX14 _OutputIterator __fill_n(_OutputIterator __first, _Size __n, const _Tp& __value) {
using __local_iterator_t = typename __segmented_iterator_traits<_OutputIterator>::__local_iterator;
return std::__for_each_n_segment(__first, __n, [&](__local_iterator_t __lfirst, __local_iterator_t __llast) {
std::__fill_n(__lfirst, __llast - __lfirst, __value);
});
}
#endif // !_LIBCPP_CXX03_LANG
template <bool _FillVal, class _Cp>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
__fill_n_bool(__bit_iterator<_Cp, false> __first, typename __size_difference_type_traits<_Cp>::size_type __n) {

View file

@ -14,8 +14,8 @@
#include <__config>
#include <__functional/identity.h>
#include <__iterator/segmented_iterator.h>
#include <__type_traits/enable_if.h>
#include <__type_traits/invoke.h>
#include <__type_traits/is_same.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@ -25,27 +25,21 @@ _LIBCPP_BEGIN_NAMESPACE_STD
template <class _InputIterator, class _Sent, class _Func, class _Proj>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _InputIterator
__for_each(_InputIterator __first, _Sent __last, _Func& __f, _Proj& __proj) {
__for_each(_InputIterator __first, _Sent __last, _Func& __func, _Proj& __proj) {
#ifndef _LIBCPP_CXX03_LANG
if constexpr (is_same<_InputIterator, _Sent>::value && __is_segmented_iterator_v<_InputIterator>) {
using __local_iterator_t = typename __segmented_iterator_traits<_InputIterator>::__local_iterator;
std::__for_each_segment(__first, __last, [&](__local_iterator_t __lfirst, __local_iterator_t __llast) {
std::__for_each(__lfirst, __llast, __func, __proj);
});
return __last;
}
#endif
for (; __first != __last; ++__first)
std::__invoke(__f, std::__invoke(__proj, *__first));
std::__invoke(__func, std::__invoke(__proj, *__first));
return __first;
}
#ifndef _LIBCPP_CXX03_LANG
template <class _SegmentedIterator,
class _Func,
class _Proj,
__enable_if_t<__is_segmented_iterator_v<_SegmentedIterator>, int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _SegmentedIterator
__for_each(_SegmentedIterator __first, _SegmentedIterator __last, _Func& __func, _Proj& __proj) {
using __local_iterator_t = typename __segmented_iterator_traits<_SegmentedIterator>::__local_iterator;
std::__for_each_segment(__first, __last, [&](__local_iterator_t __lfirst, __local_iterator_t __llast) {
std::__for_each(__lfirst, __llast, __func, __proj);
});
return __last;
}
#endif // !_LIBCPP_CXX03_LANG
template <class _InputIterator, class _Func>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Func
for_each(_InputIterator __first, _InputIterator __last, _Func __f) {

View file

@ -16,10 +16,7 @@
#include <__functional/identity.h>
#include <__iterator/iterator_traits.h>
#include <__iterator/segmented_iterator.h>
#include <__type_traits/disjunction.h>
#include <__type_traits/enable_if.h>
#include <__type_traits/invoke.h>
#include <__type_traits/negation.h>
#include <__utility/convert_to_integral.h>
#include <__utility/move.h>
@ -32,57 +29,33 @@ _LIBCPP_PUSH_MACROS
_LIBCPP_BEGIN_NAMESPACE_STD
template <class _InputIterator,
class _Size,
class _Func,
class _Proj,
__enable_if_t<!__has_random_access_iterator_category<_InputIterator>::value &&
_Or<integral_constant<bool, !__is_segmented_iterator_v<_InputIterator> >,
_Not<__has_random_access_local_iterator<_InputIterator> > >::value,
int> = 0>
template <class _InputIterator, class _Size, class _Func, class _Proj>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _InputIterator
__for_each_n(_InputIterator __first, _Size __orig_n, _Func& __f, _Proj& __proj) {
typedef decltype(std::__convert_to_integral(__orig_n)) _IntegralSize;
_IntegralSize __n = __orig_n;
while (__n > 0) {
std::__invoke(__f, std::__invoke(__proj, *__first));
++__first;
--__n;
}
return std::move(__first);
}
template <class _RandIter,
class _Size,
class _Func,
class _Proj,
__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, _Proj& __proj) {
typename std::iterator_traits<_RandIter>::difference_type __n = __orig_n;
auto __last = __first + __n;
std::__for_each(__first, __last, __f, __proj);
return __last;
}
#ifndef _LIBCPP_CXX03_LANG
template <class _SegmentedIterator,
class _Size,
class _Func,
class _Proj,
__enable_if_t<!__has_random_access_iterator_category<_SegmentedIterator>::value &&
__is_segmented_iterator_v<_SegmentedIterator> &&
__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, _Proj& __proj) {
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, __proj);
});
if constexpr (__is_segmented_iterator_v<_InputIterator>) {
using __local_iterator = typename __segmented_iterator_traits<_InputIterator>::__local_iterator;
if constexpr (__has_random_access_iterator_category<__local_iterator>::value) {
return std::__for_each_n_segment(__first, __orig_n, [&](__local_iterator __lfirst, __local_iterator __llast) {
std::__for_each(__lfirst, __llast, __f, __proj);
});
} else {
return std::__for_each(__first, __first + __n, __f, __proj);
}
} else
#endif
{
while (__n > 0) {
std::__invoke(__f, std::__invoke(__proj, *__first));
++__first;
--__n;
}
return std::move(__first);
}
}
#endif // !_LIBCPP_CXX03_LANG
#if _LIBCPP_STD_VER >= 17

View file

@ -11,6 +11,7 @@
#define _LIBCPP___ITERATOR_DISTANCE_H
#include <__algorithm/for_each_segment.h>
#include <__concepts/same_as.h>
#include <__config>
#include <__iterator/concepts.h>
#include <__iterator/incrementable_traits.h>
@ -41,35 +42,29 @@ template <class _Iter>
using __iter_distance_t _LIBCPP_NODEBUG = typename iterator_traits<_Iter>::difference_type;
#endif
template <class _InputIter, class _Sent>
inline _LIBCPP_HIDE_FROM_ABI
_LIBCPP_CONSTEXPR_SINCE_CXX17 __iter_distance_t<_InputIter> __distance(_InputIter __first, _Sent __last) {
__iter_distance_t<_InputIter> __r(0);
for (; __first != __last; ++__first)
++__r;
return __r;
}
template <class _RandIter, __enable_if_t<__has_random_access_iterator_category<_RandIter>::value, int> = 0>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 __iter_distance_t<_RandIter>
__distance(_RandIter __first, _RandIter __last) {
return __last - __first;
}
template <class _InputIter, class _Sent>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 __iter_distance_t<_InputIter>
__distance(_InputIter __first, _Sent __last) {
__iter_distance_t<_InputIter> __r(0);
#if _LIBCPP_STD_VER >= 20
template <class _SegmentedIter,
__enable_if_t<!__has_random_access_iterator_category<_SegmentedIter>::value &&
__is_segmented_iterator_v<_SegmentedIter>,
int> = 0>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 __iter_distance_t<_SegmentedIter>
__distance(_SegmentedIter __first, _SegmentedIter __last) {
__iter_distance_t<_SegmentedIter> __r(0);
std::__for_each_segment(__first, __last, [&__r](auto __lfirst, auto __llast) {
__r += std::__distance(__lfirst, __llast);
});
if constexpr (same_as<_InputIter, _Sent> && __is_segmented_iterator_v<_InputIter>) {
std::__for_each_segment(__first, __last, [&__r](auto __lfirst, auto __llast) {
__r += std::__distance(__lfirst, __llast);
});
} else
#endif
{
for (; __first != __last; ++__first)
++__r;
}
return __r;
}
#endif // _LIBCPP_STD_VER >= 20
template <class _InputIter>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 typename iterator_traits<_InputIter>::difference_type

View file

@ -75,11 +75,6 @@ inline const bool __has_specialization_v<_Tp, sizeof(_Tp) * 0> = true;
template <class _Iterator>
inline const bool __is_segmented_iterator_v = __has_specialization_v<__segmented_iterator_traits<_Iterator> >;
template <class _SegmentedIterator>
struct __has_random_access_local_iterator
: __has_random_access_iterator_category<
typename __segmented_iterator_traits< _SegmentedIterator >::__local_iterator > {};
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP___SEGMENTED_ITERATOR_H