diff --git a/libcxx/include/__algorithm/for_each_n.h b/libcxx/include/__algorithm/for_each_n.h index 04650e15b6362..24664c4517300 100644 --- a/libcxx/include/__algorithm/for_each_n.h +++ b/libcxx/include/__algorithm/for_each_n.h @@ -12,15 +12,16 @@ #include <__algorithm/for_each.h> #include <__algorithm/for_each_n_segment.h> +#include <__algorithm/min.h> #include <__config> +#include <__cstddef/size_t.h> #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 <__iterator/unreachable_sentinel.h> #include <__type_traits/invoke.h> -#include <__type_traits/negation.h> -#include <__utility/convert_to_integral.h> +#include <__type_traits/is_same.h> +#include <__utility/exchange.h> #include <__utility/move.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -30,73 +31,47 @@ _LIBCPP_PUSH_MACROS #include <__undef_macros> +#if _LIBCPP_STD_VER >= 17 + _LIBCPP_BEGIN_NAMESPACE_STD -template ::value && - _Or >, - _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, _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; +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Iter +__for_each_n(_Iter __first, _Sent __last, _Size& __n, _Func& __func, _Proj& __proj) { + if constexpr (__has_random_access_iterator_category<_Iter>::value) { + if constexpr (is_same_v<_Sent, __unreachable_sentinel_t>) { + return std::__for_each(__first, __first + std::exchange(__n, 0), __func, __proj); + } else { + auto __count = std::min(__n, __last - __first); + __n -= __count; + return std::__for_each(__first, __first + __count, __func, __proj); + } + } else if constexpr (__is_segmented_iterator_v<_Iter>) { + return std::__for_each_n_segment(__first, __n, [&](auto __lfirst, auto __llast, _Size __max) { + std::__for_each_n(__lfirst, __llast, __max, __func, __proj); + return __max; + }); + } else { + while (__n > 0 && __first != __last) { + std::__invoke(__func, std::__invoke(__proj, *__first)); + ++__first; + --__n; + } + return std::move(__first); } - return std::move(__first); -} - -template ::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 ::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); - }); } -#endif // !_LIBCPP_CXX03_LANG - -#if _LIBCPP_STD_VER >= 17 template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _InputIterator for_each_n(_InputIterator __first, _Size __orig_n, _Func __f) { __identity __proj; - return std::__for_each_n(__first, __orig_n, __f, __proj); + return std::__for_each_n(__first, __unreachable_sentinel, __orig_n, __f, __proj); } -#endif // _LIBCPP_STD_VER >= 17 - _LIBCPP_END_NAMESPACE_STD +#endif // _LIBCPP_STD_VER >= 17 + _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 index a433df5d098ae..2e5c8ba2d336a 100644 --- a/libcxx/include/__algorithm/for_each_n_segment.h +++ b/libcxx/include/__algorithm/for_each_n_segment.h @@ -26,36 +26,28 @@ _LIBCPP_BEGIN_NAMESPACE_STD template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _SegmentedIterator -__for_each_n_segment(_SegmentedIterator __first, _Size __orig_n, _Functor __func) { +__for_each_n_segment(_SegmentedIterator __first, _Size __n, _Functor __func) { static_assert(__is_segmented_iterator_v<_SegmentedIterator> && __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) + if (__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 __segment_iter = _Traits::__segment(__first); auto __local_first = _Traits::__local(__first); __local_iter_t __local_last; + __n = __func(_Traits::__local(__first), _Traits::__end(__segment_iter), __n); + 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); + ++__segment_iter; + __n = __func(_Traits::__begin(__segment_iter), _Traits::__end(__segment_iter), __n); } - return _Traits::__compose(__seg, __local_last); + return _Traits::__compose(__segment_iter, __local_last); } _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__algorithm/ranges_for_each_n.h b/libcxx/include/__algorithm/ranges_for_each_n.h index 3aab1b79c10a1..7beba8f2d3693 100644 --- a/libcxx/include/__algorithm/ranges_for_each_n.h +++ b/libcxx/include/__algorithm/ranges_for_each_n.h @@ -15,9 +15,8 @@ #include <__functional/identity.h> #include <__iterator/concepts.h> #include <__iterator/incrementable_traits.h> -#include <__iterator/iterator_traits.h> #include <__iterator/projected.h> -#include <__ranges/concepts.h> +#include <__iterator/unreachable_sentinel.h> #include <__utility/move.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -40,7 +39,7 @@ struct __for_each_n { template > _Func> _LIBCPP_HIDE_FROM_ABI constexpr for_each_n_result<_Iter, _Func> operator()(_Iter __first, iter_difference_t<_Iter> __count, _Func __func, _Proj __proj = {}) const { - auto __last = std::__for_each_n(std::move(__first), __count, __func, __proj); + auto __last = std::__for_each_n(std::move(__first), __unreachable_sentinel, __count, __func, __proj); return {std::move(__last), std::move(__func)}; } }; diff --git a/libcxx/include/__iterator/segmented_iterator.h b/libcxx/include/__iterator/segmented_iterator.h index 5df9737137101..dc56a740130b5 100644 --- a/libcxx/include/__iterator/segmented_iterator.h +++ b/libcxx/include/__iterator/segmented_iterator.h @@ -75,11 +75,6 @@ inline const bool __has_specialization_v<_Tp, sizeof(_Tp) * 0> = true; template inline const bool __is_segmented_iterator_v = __has_specialization_v<__segmented_iterator_traits<_Iterator> >; -template -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 diff --git a/libcxx/include/__iterator/unreachable_sentinel.h b/libcxx/include/__iterator/unreachable_sentinel.h index 77e663da4b3a6..0351b88d4b234 100644 --- a/libcxx/include/__iterator/unreachable_sentinel.h +++ b/libcxx/include/__iterator/unreachable_sentinel.h @@ -12,6 +12,9 @@ #include <__config> #include <__iterator/concepts.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_same.h> +#include <__type_traits/remove_cvref.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -19,6 +22,36 @@ _LIBCPP_BEGIN_NAMESPACE_STD +inline constexpr struct __unreachable_sentinel_t {} __unreachable_sentinel; + +template , __unreachable_sentinel_t>::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(_UnreachableSentinel&&, _Iter&&) { + return false; +} + +template , __unreachable_sentinel_t>::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(_Iter&&, _UnreachableSentinel&&) { + return false; +} + +template , __unreachable_sentinel_t>::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(_UnreachableSentinel&&, _Iter&&) { + return true; +} + +template , __unreachable_sentinel_t>::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(_Iter&&, _UnreachableSentinel&&) { + return true; +} + #if _LIBCPP_STD_VER >= 20 struct unreachable_sentinel_t {