/// \file // Range v3 library // // Copyright Eric Niebler 2014-present // // Use, modification and distribution is subject to the // Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // Project home: https://github.com/ericniebler/range-v3 // #ifndef RANGES_V3_ITERATOR_OPERATIONS_HPP #define RANGES_V3_ITERATOR_OPERATIONS_HPP #include #include #include #include #include #include namespace ranges { /// \addtogroup group-iterator /// @{ /// \cond CPP_template(typename I)( // requires input_or_output_iterator) // struct counted_iterator; /// \endcond struct advance_fn { #if RANGES_CXX_IF_CONSTEXPR >= RANGES_CXX_IF_CONSTEXPR_17 template constexpr auto operator()(I & i, iter_difference_t n) const -> CPP_ret(void)( // requires input_or_output_iterator) // [[expects: n >= 0 || bidirectional_iterator]] { if constexpr(random_access_iterator) { i += n; } else { if constexpr(bidirectional_iterator) for(; 0 > n; ++n) --i; RANGES_EXPECT(0 <= n); for(; 0 < n; --n) ++i; } } template constexpr auto operator()(I & i, S bound) const -> CPP_ret(void)( // requires sentinel_for) // [[expects axiom: reachable(i, bound)]] { if constexpr(assignable_from) { i = std::move(bound); } else if constexpr(sized_sentinel_for) { iter_difference_t d = bound - i; RANGES_EXPECT(0 <= d); (*this)(i, d); } else while(i != bound) ++i; } template constexpr auto operator()(I & i, iter_difference_t n, S bound) const -> CPP_ret(iter_difference_t)( // requires sentinel_for) // [[expects axiom: 0 == n || // (0 < n && reachable(i, bound)) || // (0 > n && same_as && bidirectional_iterator && reachable(bound, // i))]] { if constexpr(sized_sentinel_for) { if(0 == n) return 0; const auto d = bound - i; if constexpr(bidirectional_iterator && same_as) { RANGES_EXPECT(0 <= n ? 0 <= d : 0 >= d); if(0 <= n ? d <= n : d >= n) { i = std::move(bound); return n - d; } } else { RANGES_EXPECT(0 <= n && 0 <= d); if(d <= n) { (*this)(i, std::move(bound)); return n - d; } } (*this)(i, n); return 0; } else { if constexpr(bidirectional_iterator && same_as) { if(0 > n) { do { --i; ++n; } while(0 != n && i != bound); return n; } } RANGES_EXPECT(0 <= n); while(0 != n && i != bound) { ++i; --n; } return n; } } #else private: template static constexpr void n_(I & i, iter_difference_t n, detail::input_iterator_tag_); template static constexpr void n_(I & i, iter_difference_t n, detail::bidirectional_iterator_tag_); template static constexpr void n_(I & i, iter_difference_t n, detail::random_access_iterator_tag_); template static constexpr void to_impl_(I & i, S s, sentinel_tag); template static constexpr void to_impl_(I & i, S s, sized_sentinel_tag); template static constexpr void to_(I & i, S s, std::true_type); // assignable template static constexpr void to_(I & i, S s, std::false_type); // !assignable template static constexpr iter_difference_t bounded_(I & it, iter_difference_t n, S bound, sentinel_tag, detail::input_iterator_tag_); template static constexpr iter_difference_t bounded_( I & it, iter_difference_t n, I bound, sentinel_tag, detail::bidirectional_iterator_tag_); template static constexpr iter_difference_t bounded_(I & it, iter_difference_t n, S bound, sized_sentinel_tag, Concept); public: // Advance a certain number of steps: template constexpr auto operator()(I & i, iter_difference_t n) const -> CPP_ret(void)( // requires input_or_output_iterator) { advance_fn::n_(i, n, iterator_tag_of{}); } // Advance to a certain position: template constexpr auto operator()(I & i, S s) const -> CPP_ret(void)( // requires sentinel_for) { advance_fn::to_( i, static_cast(s), meta::bool_>()); } // Advance a certain number of times, with a bound: template constexpr auto operator()(I & it, iter_difference_t n, S bound) const -> CPP_ret(iter_difference_t)( // requires sentinel_for) { return advance_fn::bounded_(it, n, static_cast(bound), sentinel_tag_of(), iterator_tag_of()); } #endif template constexpr auto operator()(counted_iterator & i, iter_difference_t n) const -> CPP_ret(void)( // requires input_or_output_iterator); }; /// \sa `advance_fn` RANGES_INLINE_VARIABLE(advance_fn, advance) #if RANGES_CXX_IF_CONSTEXPR < RANGES_CXX_IF_CONSTEXPR_17 template constexpr void advance_fn::n_(I & i, iter_difference_t n, detail::input_iterator_tag_) { RANGES_EXPECT(n >= 0); for(; n > 0; --n) ++i; } template constexpr void advance_fn::n_(I & i, iter_difference_t n, detail::bidirectional_iterator_tag_) { if(n > 0) for(; n > 0; --n) ++i; else for(; n < 0; ++n) --i; } template constexpr void advance_fn::n_(I & i, iter_difference_t n, detail::random_access_iterator_tag_) { i += n; } template constexpr void advance_fn::to_impl_(I & i, S s, sentinel_tag) { while(i != s) ++i; } template constexpr void advance_fn::to_impl_(I & i, S s, sized_sentinel_tag) { iter_difference_t d = s - i; RANGES_EXPECT(0 <= d); advance(i, d); } // Advance to a certain position: template constexpr void advance_fn::to_(I & i, S s, std::true_type) { i = static_cast(s); } template constexpr void advance_fn::to_(I & i, S s, std::false_type) { advance_fn::to_impl_(i, static_cast(s), sentinel_tag_of()); } template constexpr iter_difference_t advance_fn::bounded_(I & it, iter_difference_t n, S bound, sentinel_tag, detail::input_iterator_tag_) { RANGES_EXPECT(0 <= n); for(; 0 != n && it != bound; --n) ++it; return n; } template constexpr iter_difference_t advance_fn::bounded_( I & it, iter_difference_t n, I bound, sentinel_tag, detail::bidirectional_iterator_tag_) { if(0 <= n) for(; 0 != n && it != bound; --n) ++it; else for(; 0 != n && it != bound; ++n) --it; return n; } template constexpr iter_difference_t advance_fn::bounded_(I & it, iter_difference_t n, S bound, sized_sentinel_tag, Concept) { RANGES_EXPECT(((bool)same_as || 0 <= n)); if(n == 0) return 0; iter_difference_t d = bound - it; RANGES_EXPECT(0 <= n ? 0 <= d : 0 >= d); if(0 <= n ? n >= d : n <= d) { advance(it, static_cast(bound)); return n - d; } advance(it, n); return 0; } #endif struct next_fn { template constexpr auto operator()(I it) const -> CPP_ret(I)(requires input_or_output_iterator) { return ++it; } template constexpr auto operator()(I it, iter_difference_t n) const -> CPP_ret(I)(requires input_or_output_iterator) { advance(it, n); return it; } template constexpr auto operator()(I it, S s) const -> CPP_ret(I)(requires sentinel_for) { advance(it, static_cast(s)); return it; } template constexpr auto operator()(I it, iter_difference_t n, S bound) const -> CPP_ret(I)(requires sentinel_for) { advance(it, n, static_cast(bound)); return it; } }; /// \sa `next_fn` RANGES_INLINE_VARIABLE(next_fn, next) struct prev_fn { template constexpr auto operator()(I it) const -> CPP_ret(I)(requires bidirectional_iterator) { return --it; } template constexpr auto operator()(I it, iter_difference_t n) const -> CPP_ret(I)(requires bidirectional_iterator) { advance(it, -n); return it; } template constexpr auto operator()(I it, iter_difference_t n, I bound) const -> CPP_ret(I)(requires bidirectional_iterator) { advance(it, -n, static_cast(bound)); return it; } }; /// \sa `prev_fn` RANGES_INLINE_VARIABLE(prev_fn, prev) struct iter_enumerate_fn { private: template static constexpr auto impl_i(I first, S last, sentinel_tag) -> CPP_ret(std::pair, I>)( // requires(!sized_sentinel_for)) { iter_difference_t d = 0; for(; first != last; ++first) ++d; return {d, first}; } template static constexpr auto impl_i(I first, S end_, sentinel_tag) -> CPP_ret(std::pair, I>)( // requires sized_sentinel_for) { I last = ranges::next(first, end_); auto n = static_cast>(last - first); RANGES_EXPECT(((bool)same_as || 0 <= n)); return {n, last}; } template static constexpr std::pair, I> impl_i(I first, S last, sized_sentinel_tag) { auto n = static_cast>(last - first); RANGES_EXPECT(((bool)same_as || 0 <= n)); return {n, ranges::next(first, last)}; } public: template constexpr auto operator()(I first, S last) const -> CPP_ret(std::pair, I>)( // requires sentinel_for) { return iter_enumerate_fn::impl_i(static_cast(first), static_cast(last), sentinel_tag_of()); } }; /// \sa `iter_enumerate_fn` RANGES_INLINE_VARIABLE(iter_enumerate_fn, iter_enumerate) struct iter_distance_fn { private: template static constexpr iter_difference_t impl_i(I first, S last, sentinel_tag) { return iter_enumerate(static_cast(first), static_cast(last)).first; } template static constexpr iter_difference_t impl_i(I first, S last, sized_sentinel_tag) { auto n = static_cast>(last - first); RANGES_EXPECT(((bool)same_as || 0 <= n)); return n; } public: template constexpr auto operator()(I first, S last) const -> CPP_ret(iter_difference_t)( // requires input_or_output_iterator && sentinel_for) { return iter_distance_fn::impl_i(static_cast(first), static_cast(last), sentinel_tag_of()); } }; /// \sa `iter_distance_fn` RANGES_INLINE_VARIABLE(iter_distance_fn, iter_distance) struct iter_distance_compare_fn { private: template static constexpr int impl_i(I first, S last, iter_difference_t n, sentinel_tag) { if(n < 0) return 1; for(; n > 0; --n, ++first) { if(first == last) return -1; } return first == last ? 0 : 1; } template static constexpr int impl_i(I first, S last, iter_difference_t n, sized_sentinel_tag) { iter_difference_t dist = last - first; if(n < dist) return 1; if(dist < n) return -1; return 0; } public: template constexpr auto operator()(I first, S last, iter_difference_t n) const -> CPP_ret(int)( // requires input_iterator && sentinel_for) { return iter_distance_compare_fn::impl_i(static_cast(first), static_cast(last), n, sentinel_tag_of()); } }; /// \sa `iter_distance_compare_fn` RANGES_INLINE_VARIABLE(iter_distance_compare_fn, iter_distance_compare) // Like distance(b,e), but guaranteed to be O(1) struct iter_size_fn { template constexpr auto operator()(I const & first, S last) const -> CPP_ret(meta::_t>>)( // requires sized_sentinel_for) { using size_type = meta::_t>>; iter_difference_t n = last - first; RANGES_EXPECT(0 <= n); return static_cast(n); } }; /// \sa `iter_size_fn` RANGES_INLINE_VARIABLE(iter_size_fn, iter_size) /// \cond namespace adl_uncounted_recounted_detail { template constexpr I uncounted(I i) { return i; } template constexpr I recounted(I const &, I i, iter_difference_t) { return i; } struct uncounted_fn { template constexpr auto operator()(I i) const -> decltype(uncounted((I &&) i)) { return uncounted((I &&) i); } }; struct recounted_fn { template constexpr auto operator()(I i, J j, iter_difference_t n) const -> decltype(recounted((I &&) i, (J &&) j, n)) { return recounted((I &&) i, (J &&) j, n); } }; } // namespace adl_uncounted_recounted_detail /// \endcond RANGES_INLINE_VARIABLE(adl_uncounted_recounted_detail::uncounted_fn, uncounted) RANGES_INLINE_VARIABLE(adl_uncounted_recounted_detail::recounted_fn, recounted) struct enumerate_fn : iter_enumerate_fn { private: template static std::pair, iterator_t> impl_r(Rng & rng, range_tag, range_tag) { return iter_enumerate(begin(rng), end(rng)); } template static std::pair, iterator_t> impl_r( Rng & rng, common_range_tag, sized_range_tag) { return {static_cast>(size(rng)), end(rng)}; } public: using iter_enumerate_fn::operator(); template auto operator()(Rng && rng) const -> CPP_ret(std::pair, iterator_t>)( // requires range) { // Better not be trying to compute the distance of an infinite range: RANGES_EXPECT(!is_infinite::value); return enumerate_fn::impl_r( rng, common_range_tag_of(), sized_range_tag_of()); } }; /// \sa `enumerate_fn` RANGES_INLINE_VARIABLE(enumerate_fn, enumerate) struct distance_fn : iter_distance_fn { private: template static range_difference_t impl_r(Rng & rng, range_tag) { return enumerate(rng).first; } template constexpr static range_difference_t impl_r(Rng & rng, sized_range_tag) { return static_cast>(size(rng)); } public: using iter_distance_fn::operator(); template constexpr auto operator()(Rng && rng) const -> CPP_ret(range_difference_t)( // requires range) { // Better not be trying to compute the distance of an infinite range: RANGES_EXPECT(!is_infinite::value); return distance_fn::impl_r(rng, sized_range_tag_of()); } }; /// \sa `distance_fn` RANGES_INLINE_VARIABLE(distance_fn, distance) // The interface of distance_compare is taken from Util.listLengthCmp in the GHC API. struct distance_compare_fn : iter_distance_compare_fn { private: template static int impl_r(Rng & rng, range_difference_t n, range_tag) { // Infinite ranges are always compared to be larger than a finite number. return is_infinite::value ? 1 : iter_distance_compare(begin(rng), end(rng), n); } template static int impl_r(Rng & rng, range_difference_t n, sized_range_tag) { auto dist = distance(rng); // O(1) since rng is a sized_range if(dist > n) return 1; else if(dist < n) return -1; else return 0; } public: using iter_distance_compare_fn::operator(); template auto operator()(Rng && rng, range_difference_t n) const -> CPP_ret(int)( // requires range) { return distance_compare_fn::impl_r(rng, n, sized_range_tag_of()); } }; /// \sa `distance_compare_fn` RANGES_INLINE_VARIABLE(distance_compare_fn, distance_compare) namespace cpp20 { using ranges::advance; using ranges::distance; using ranges::next; using ranges::prev; } // namespace cpp20 /// @} } // namespace ranges #endif // RANGES_V3_ITERATOR_OPERATIONS_HPP