/// \file cycle.hpp // Range v3 library // // Copyright Eric Niebler 2013-present // Copyright Gonzalo Brito Gadeschi 2015 // Copyright Casey Carter 2015 // // 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_VIEW_CYCLE_HPP #define RANGES_V3_VIEW_CYCLE_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ranges { /// \addtogroup group-views ///@{ template() */> struct RANGES_EMPTY_BASES cycled_view : view_facade, infinite> , private detail::non_propagating_cache, cycled_view, !common_range> { private: CPP_assert(forward_range && !is_infinite::value); friend range_access; Rng rng_; using cache_t = detail::non_propagating_cache, cycled_view, !common_range>; template struct cursor { private: friend struct cursor; template using constify_if = meta::const_if_c; using cycled_view_t = constify_if; using CRng = constify_if; using iterator = iterator_t; cycled_view_t * rng_{}; iterator it_{}; std::intmax_t n_ = 0; iterator get_end_(std::true_type, bool = false) const { return ranges::end(rng_->rng_); } template iterator get_end_(std::false_type, meta::bool_ = {}) const { auto & end_ = static_cast(*rng_); RANGES_EXPECT(CanBeEmpty || end_); if(CanBeEmpty && !end_) end_ = ranges::next(it_, ranges::end(rng_->rng_)); return *end_; } void set_end_(std::true_type) const {} void set_end_(std::false_type) const { auto & end_ = static_cast(*rng_); if(!end_) end_ = it_; } public: cursor() = default; cursor(cycled_view_t * rng) : rng_(rng) , it_(ranges::begin(rng->rng_)) {} CPP_template(bool Other)( // requires IsConst && (!Other)) cursor(cursor that) : rng_(that.rng_) , it_(std::move(that.it_)) {} // clang-format off auto CPP_auto_fun(read)()(const) ( return *it_ ) // clang-format on CPP_member auto equal(cursor const & pos) const -> CPP_ret(bool)( // requires equality_comparable) { RANGES_EXPECT(rng_ == pos.rng_); return n_ == pos.n_ && it_ == pos.it_; } void next() { auto const last = ranges::end(rng_->rng_); RANGES_EXPECT(it_ != last); if(++it_ == last) { ++n_; this->set_end_(meta::bool_<(bool)common_range>{}); it_ = ranges::begin(rng_->rng_); } } CPP_member auto prev() -> CPP_ret(void)( // requires bidirectional_range) { if(it_ == ranges::begin(rng_->rng_)) { RANGES_EXPECT(n_ > 0); // decrementing the begin iterator?! --n_; it_ = this->get_end_(meta::bool_<(bool)common_range>{}); } --it_; } CPP_template(typename Diff)( // requires random_access_range && detail::integer_like_) void advance(Diff n) { auto const first = ranges::begin(rng_->rng_); auto const last = this->get_end_(meta::bool_<(bool)common_range>{}, meta::bool_()); auto const dist = last - first; auto const d = it_ - first; auto const off = (d + n) % dist; n_ += (d + n) / dist; RANGES_EXPECT(n_ >= 0); using D = range_difference_t; it_ = first + static_cast(off < 0 ? off + dist : off); } CPP_member auto CPP_fun(distance_to)(cursor const & that)( const requires sized_sentinel_for) { RANGES_EXPECT(that.rng_ == rng_); auto const first = ranges::begin(rng_->rng_); auto const last = this->get_end_(meta::bool_<(bool)common_range>{}, meta::bool_()); auto const dist = last - first; return (that.n_ - n_) * dist + (that.it_ - it_); } }; CPP_member auto begin_cursor() -> CPP_ret(cursor)( // requires(!simple_view() || !common_range)) { return {this}; } CPP_member auto begin_cursor() const -> CPP_ret(cursor)( // requires common_range) { return {this}; } unreachable_sentinel_t end_cursor() const { return unreachable; } public: cycled_view() = default; /// \pre !empty(rng) explicit cycled_view(Rng rng) : rng_(std::move(rng)) { RANGES_EXPECT(!ranges::empty(rng_)); } }; template struct cycled_view : identity_adaptor { CPP_assert(is_infinite::value); using identity_adaptor::identity_adaptor; }; #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17 template cycled_view(Rng &&)->cycled_view>; #endif namespace views { /// Returns an infinite range that endlessly repeats the source /// range. struct cycle_fn { /// \pre !empty(rng) template auto operator()(Rng && rng) const -> CPP_ret(cycled_view>)( // requires viewable_range && forward_range) { return cycled_view>{all(static_cast(rng))}; } }; /// \relates cycle_fn /// \ingroup group-views RANGES_INLINE_VARIABLE(view, cycle) } // namespace views /// @} } // namespace ranges #include RANGES_SATISFY_BOOST_RANGE(::ranges::cycled_view) #endif