/// \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_COUNTED_ITERATOR_HPP #define RANGES_V3_ITERATOR_COUNTED_ITERATOR_HPP #include #include #include #include #include #include #include #include namespace ranges { /// \addtogroup group-iterator /// @{ /// \cond namespace _counted_iterator_ { struct access { template static constexpr iter_difference_t> & count( counted_iterator & ci) noexcept { return ci.cnt_; } template static constexpr I & current(counted_iterator & ci) noexcept { return ci.current_; } template static constexpr I const & current(counted_iterator const & ci) noexcept { return ci.current_; } }; template struct contiguous_iterator_concept_base {}; template<> struct contiguous_iterator_concept_base { using iterator_concept = ranges::contiguous_iterator_tag; }; } // namespace _counted_iterator_ /// \endcond template // requires input_or_output_iterator struct counted_iterator : _counted_iterator_::contiguous_iterator_concept_base<(bool)contiguous_iterator> { private: friend advance_fn; CPP_assert(input_or_output_iterator); friend _counted_iterator_::access; I current_{}; iter_difference_t cnt_{0}; constexpr void post_increment_(std::true_type) { CPP_assert(std::is_void()); ++current_; } constexpr auto post_increment_(std::false_type) -> decltype(current_++) { CPP_assert(!std::is_void()); auto && tmp = current_++; --cnt_; return static_cast(tmp); } public: using iterator_type = I; using difference_type = iter_difference_t; counted_iterator() = default; constexpr counted_iterator(I x, iter_difference_t n) : current_(std::move(x)) , cnt_(n) { RANGES_EXPECT(n >= 0); } template(typename I2)( /// \pre requires convertible_to) constexpr counted_iterator(counted_iterator const & i) : current_(_counted_iterator_::access::current(i)) , cnt_(i.count()) {} template(typename I2)( /// \pre requires convertible_to) constexpr counted_iterator & operator=(counted_iterator const & i) { current_ = _counted_iterator_::access::current(i); cnt_ = i.count(); } constexpr I base() const { return current_; } constexpr iter_difference_t count() const { return cnt_; } constexpr iter_reference_t operator*() noexcept( noexcept(iter_reference_t(*current_))) { RANGES_EXPECT(cnt_ > 0); return *current_; } template(typename I2 = I)( /// \pre requires indirectly_readable) constexpr iter_reference_t operator*() const // noexcept(noexcept(iter_reference_t(*current_))) { RANGES_EXPECT(cnt_ > 0); return *current_; } constexpr counted_iterator & operator++() { RANGES_EXPECT(cnt_ > 0); ++current_; --cnt_; return *this; } #ifdef RANGES_WORKAROUND_MSVC_677925 template(typename I2 = I)( /// \pre requires (!forward_iterator)) // constexpr auto operator++(int) -> decltype(std::declval()++) #else // ^^^ workaround ^^^ / vvv no workaround vvv CPP_member constexpr auto operator++(int) // -> CPP_ret(decltype(std::declval()++))( /// \pre requires (!forward_iterator)) #endif // RANGES_WORKAROUND_MSVC_677925 { RANGES_EXPECT(cnt_ > 0); return post_increment_(std::is_void()); } CPP_member constexpr auto operator++(int) // -> CPP_ret(counted_iterator)( /// \pre requires forward_iterator) { auto tmp(*this); ++*this; return tmp; } CPP_member constexpr auto operator--() // -> CPP_ret(counted_iterator &)( /// \pre requires bidirectional_iterator) { --current_; ++cnt_; return *this; } CPP_member constexpr auto operator--(int) // -> CPP_ret(counted_iterator)( /// \pre requires bidirectional_iterator) { auto tmp(*this); --*this; return tmp; } CPP_member constexpr auto operator+=(difference_type n) // -> CPP_ret(counted_iterator &)( /// \pre requires random_access_iterator) { RANGES_EXPECT(cnt_ >= n); current_ += n; cnt_ -= n; return *this; } CPP_member constexpr auto operator+(difference_type n) const // -> CPP_ret(counted_iterator)( /// \pre requires random_access_iterator) { auto tmp(*this); tmp += n; return tmp; } CPP_member constexpr auto operator-=(difference_type n) // -> CPP_ret(counted_iterator &)( /// \pre requires random_access_iterator) { RANGES_EXPECT(cnt_ >= -n); current_ -= n; cnt_ += n; return *this; } CPP_member constexpr auto operator-(difference_type n) const // -> CPP_ret(counted_iterator)( /// \pre requires random_access_iterator) { auto tmp(*this); tmp -= n; return tmp; } CPP_member constexpr auto operator[](difference_type n) const // -> CPP_ret(iter_reference_t)( /// \pre requires random_access_iterator) { RANGES_EXPECT(cnt_ >= n); return current_[n]; } #if !RANGES_BROKEN_CPO_LOOKUP CPP_broken_friend_member friend constexpr auto iter_move(counted_iterator const & i) // noexcept(detail::has_nothrow_iter_move_v) -> CPP_broken_friend_ret(iter_rvalue_reference_t)( /// \pre requires input_iterator) { return ranges::iter_move(i.current_); } template friend constexpr auto iter_swap(counted_iterator const & x, counted_iterator const & y) // noexcept(is_nothrow_indirectly_swappable::value) -> CPP_broken_friend_ret(void)( /// \pre requires indirectly_swappable) { return ranges::iter_swap(x.current_, _counted_iterator_::access::current(y)); } #endif }; /// \cond #if RANGES_BROKEN_CPO_LOOKUP namespace _counted_iterator_ { template constexpr auto iter_move(counted_iterator const & i) noexcept( detail::has_nothrow_iter_move_v) -> CPP_broken_friend_ret(iter_rvalue_reference_t)( /// \pre requires input_iterator) { return ranges::iter_move(_counted_iterator_::access::current(i)); } template constexpr auto iter_swap( counted_iterator const & x, counted_iterator const & y) noexcept(is_nothrow_indirectly_swappable::value) -> CPP_broken_friend_ret(void)( /// \pre requires indirectly_swappable) { return ranges::iter_swap(_counted_iterator_::access::current(x), _counted_iterator_::access::current(y)); } } // namespace _counted_iterator_ #endif /// endcond template(typename I1, typename I2)( /// \pre requires common_with) constexpr bool operator==(counted_iterator const & x, counted_iterator const & y) { return x.count() == y.count(); } template constexpr bool operator==(counted_iterator const & x, default_sentinel_t) { return x.count() == 0; } template constexpr bool operator==(default_sentinel_t, counted_iterator const & x) { return x.count() == 0; } template(typename I1, typename I2)( /// \pre requires common_with) constexpr bool operator!=(counted_iterator const & x, counted_iterator const & y) { return !(x == y); } template constexpr bool operator!=(counted_iterator const & x, default_sentinel_t y) { return !(x == y); } template constexpr bool operator!=(default_sentinel_t x, counted_iterator const & y) { return !(x == y); } template(typename I1, typename I2)( /// \pre requires common_with) constexpr bool operator<(counted_iterator const & x, counted_iterator const & y) { return y.count() < x.count(); } template(typename I1, typename I2)( /// \pre requires common_with) constexpr bool operator<=(counted_iterator const & x, counted_iterator const & y) { return !(y < x); } template(typename I1, typename I2)( /// \pre requires common_with) constexpr bool operator>(counted_iterator const & x, counted_iterator const & y) { return y < x; } template(typename I1, typename I2)( /// \pre requires common_with) constexpr bool operator>=(counted_iterator const & x, counted_iterator const & y) { return !(x < y); } template(typename I1, typename I2)( /// \pre requires common_with) constexpr iter_difference_t operator-(counted_iterator const & x, counted_iterator const & y) { return y.count() - x.count(); } template constexpr iter_difference_t operator-(counted_iterator const & x, default_sentinel_t) { return -x.count(); } template constexpr iter_difference_t operator-(default_sentinel_t, counted_iterator const & y) { return y.count(); } template(typename I)( /// \pre requires random_access_iterator) constexpr counted_iterator operator+(iter_difference_t n, counted_iterator const & x) { return x + n; } template(typename I)( /// \pre requires input_or_output_iterator) constexpr counted_iterator make_counted_iterator(I i, iter_difference_t n) { return {std::move(i), n}; } template struct indirectly_readable_traits> : meta::conditional_t< (bool)indirectly_readable, indirectly_readable_traits, meta::nil_> {}; CPP_template_def(typename I)( /// \pre requires input_or_output_iterator) constexpr void advance_fn::operator()(counted_iterator & i, iter_difference_t n) const { RANGES_EXPECT(n <= i.cnt_); advance(i.current_, n); i.cnt_ -= n; } namespace cpp20 { using ranges::counted_iterator; } /// @} } // namespace ranges /// \cond namespace ranges { namespace _counted_iterator_ { template struct iterator_traits_ { using difference_type = iter_difference_t; using value_type = void; using reference = void; using pointer = void; using iterator_category = std::output_iterator_tag; }; template struct iterator_traits_>> : std::iterator_traits { using pointer = void; }; } // namespace _counted_iterator_ } // namespace ranges namespace std { template struct iterator_traits<::ranges::counted_iterator> : ::ranges::_counted_iterator_::iterator_traits_ {}; } // namespace std /// \endcond #include #endif