Path: blob/main/contrib/llvm-project/libcxx/include/__iterator/advance.h
35233 views
// -*- C++ -*-1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//89#ifndef _LIBCPP___ITERATOR_ADVANCE_H10#define _LIBCPP___ITERATOR_ADVANCE_H1112#include <__assert>13#include <__concepts/assignable.h>14#include <__concepts/same_as.h>15#include <__config>16#include <__iterator/concepts.h>17#include <__iterator/incrementable_traits.h>18#include <__iterator/iterator_traits.h>19#include <__type_traits/enable_if.h>20#include <__type_traits/is_integral.h>21#include <__utility/convert_to_integral.h>22#include <__utility/declval.h>23#include <__utility/move.h>24#include <__utility/unreachable.h>25#include <limits>2627#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)28# pragma GCC system_header29#endif3031_LIBCPP_PUSH_MACROS32#include <__undef_macros>3334_LIBCPP_BEGIN_NAMESPACE_STD3536template <class _InputIter>37_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 void38__advance(_InputIter& __i, typename iterator_traits<_InputIter>::difference_type __n, input_iterator_tag) {39for (; __n > 0; --__n)40++__i;41}4243template <class _BiDirIter>44_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 void45__advance(_BiDirIter& __i, typename iterator_traits<_BiDirIter>::difference_type __n, bidirectional_iterator_tag) {46if (__n >= 0)47for (; __n > 0; --__n)48++__i;49else50for (; __n < 0; ++__n)51--__i;52}5354template <class _RandIter>55_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 void56__advance(_RandIter& __i, typename iterator_traits<_RandIter>::difference_type __n, random_access_iterator_tag) {57__i += __n;58}5960template < class _InputIter,61class _Distance,62class _IntegralDistance = decltype(std::__convert_to_integral(std::declval<_Distance>())),63__enable_if_t<is_integral<_IntegralDistance>::value, int> = 0>64_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 void advance(_InputIter& __i, _Distance __orig_n) {65typedef typename iterator_traits<_InputIter>::difference_type _Difference;66_Difference __n = static_cast<_Difference>(std::__convert_to_integral(__orig_n));67// Calling `advance` with a negative value on a non-bidirectional iterator is a no-op in the current implementation.68_LIBCPP_ASSERT_PEDANTIC(__n >= 0 || __has_bidirectional_iterator_category<_InputIter>::value,69"Attempt to advance(it, n) with negative n on a non-bidirectional iterator");70std::__advance(__i, __n, typename iterator_traits<_InputIter>::iterator_category());71}7273#if _LIBCPP_STD_VER >= 207475// [range.iter.op.advance]7677namespace ranges {78namespace __advance {7980struct __fn {81private:82template <class _Ip>83_LIBCPP_HIDE_FROM_ABI static constexpr void __advance_forward(_Ip& __i, iter_difference_t<_Ip> __n) {84while (__n > 0) {85--__n;86++__i;87}88}8990template <class _Ip>91_LIBCPP_HIDE_FROM_ABI static constexpr void __advance_backward(_Ip& __i, iter_difference_t<_Ip> __n) {92while (__n < 0) {93++__n;94--__i;95}96}9798public:99// Preconditions: If `I` does not model `bidirectional_iterator`, `n` is not negative.100template <input_or_output_iterator _Ip>101_LIBCPP_HIDE_FROM_ABI constexpr void operator()(_Ip& __i, iter_difference_t<_Ip> __n) const {102// Calling `advance` with a negative value on a non-bidirectional iterator is a no-op in the current implementation.103_LIBCPP_ASSERT_PEDANTIC(104__n >= 0 || bidirectional_iterator<_Ip>, "If `n < 0`, then `bidirectional_iterator<I>` must be true.");105106// If `I` models `random_access_iterator`, equivalent to `i += n`.107if constexpr (random_access_iterator<_Ip>) {108__i += __n;109return;110} else if constexpr (bidirectional_iterator<_Ip>) {111// Otherwise, if `n` is non-negative, increments `i` by `n`.112__advance_forward(__i, __n);113// Otherwise, decrements `i` by `-n`.114__advance_backward(__i, __n);115return;116} else {117// Otherwise, if `n` is non-negative, increments `i` by `n`.118__advance_forward(__i, __n);119return;120}121}122123// Preconditions: Either `assignable_from<I&, S> || sized_sentinel_for<S, I>` is modeled, or [i, bound_sentinel)124// denotes a range.125template <input_or_output_iterator _Ip, sentinel_for<_Ip> _Sp>126_LIBCPP_HIDE_FROM_ABI constexpr void operator()(_Ip& __i, _Sp __bound_sentinel) const {127// If `I` and `S` model `assignable_from<I&, S>`, equivalent to `i = std::move(bound_sentinel)`.128if constexpr (assignable_from<_Ip&, _Sp>) {129__i = std::move(__bound_sentinel);130}131// Otherwise, if `S` and `I` model `sized_sentinel_for<S, I>`, equivalent to `ranges::advance(i, bound_sentinel -132// i)`.133else if constexpr (sized_sentinel_for<_Sp, _Ip>) {134(*this)(__i, __bound_sentinel - __i);135}136// Otherwise, while `bool(i != bound_sentinel)` is true, increments `i`.137else {138while (__i != __bound_sentinel) {139++__i;140}141}142}143144// Preconditions:145// * If `n > 0`, [i, bound_sentinel) denotes a range.146// * If `n == 0`, [i, bound_sentinel) or [bound_sentinel, i) denotes a range.147// * If `n < 0`, [bound_sentinel, i) denotes a range, `I` models `bidirectional_iterator`, and `I` and `S` model148// `same_as<I, S>`.149// Returns: `n - M`, where `M` is the difference between the ending and starting position.150template <input_or_output_iterator _Ip, sentinel_for<_Ip> _Sp>151_LIBCPP_HIDE_FROM_ABI constexpr iter_difference_t<_Ip>152operator()(_Ip& __i, iter_difference_t<_Ip> __n, _Sp __bound_sentinel) const {153// Calling `advance` with a negative value on a non-bidirectional iterator is a no-op in the current implementation.154_LIBCPP_ASSERT_PEDANTIC((__n >= 0) || (bidirectional_iterator<_Ip> && same_as<_Ip, _Sp>),155"If `n < 0`, then `bidirectional_iterator<I> && same_as<I, S>` must be true.");156// If `S` and `I` model `sized_sentinel_for<S, I>`:157if constexpr (sized_sentinel_for<_Sp, _Ip>) {158// If |n| >= |bound_sentinel - i|, equivalent to `ranges::advance(i, bound_sentinel)`.159// __magnitude_geq(a, b) returns |a| >= |b|, assuming they have the same sign.160auto __magnitude_geq = [](auto __a, auto __b) { return __a == 0 ? __b == 0 : __a > 0 ? __a >= __b : __a <= __b; };161if (const auto __m = __bound_sentinel - __i; __magnitude_geq(__n, __m)) {162(*this)(__i, __bound_sentinel);163return __n - __m;164}165166// Otherwise, equivalent to `ranges::advance(i, n)`.167(*this)(__i, __n);168return 0;169} else {170// Otherwise, if `n` is non-negative, while `bool(i != bound_sentinel)` is true, increments `i` but at171// most `n` times.172while (__n > 0 && __i != __bound_sentinel) {173++__i;174--__n;175}176177// Otherwise, while `bool(i != bound_sentinel)` is true, decrements `i` but at most `-n` times.178if constexpr (bidirectional_iterator<_Ip> && same_as<_Ip, _Sp>) {179while (__n < 0 && __i != __bound_sentinel) {180--__i;181++__n;182}183}184return __n;185}186187__libcpp_unreachable();188}189};190191} // namespace __advance192193inline namespace __cpo {194inline constexpr auto advance = __advance::__fn{};195} // namespace __cpo196} // namespace ranges197198#endif // _LIBCPP_STD_VER >= 20199200_LIBCPP_END_NAMESPACE_STD201202_LIBCPP_POP_MACROS203204#endif // _LIBCPP___ITERATOR_ADVANCE_H205206207