/// \file // Range v3 library // // Copyright Eric Niebler 2013-present // Copyright Tobias Mayer 2016 // Copyright Casey Carter 2016 // // 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_SLIDING_HPP #define RANGES_V3_VIEW_SLIDING_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ranges { /// \cond namespace sliding_view_detail { enum class cache { none, first, last }; template using caching = std::integral_constant< cache, random_access_range && sized_range ? cache::none : bidirectional_range && common_range ? cache::last : cache::first>; } // namespace sliding_view_detail /// \endcond template::value> struct sliding_view; /// \cond namespace sliding_view_detail { template using uncounted_t = decltype(ranges::uncounted(std::declval &>())); template> struct trailing { trailing() = default; constexpr trailing(Rng & rng) : it_{uncounted(ranges::begin(rng))} {} constexpr uncounted_t get(iterator_t const &, range_difference_t) const { return it_; } void next() { ++it_; } CPP_member auto prev() -> CPP_ret(void)(requires bidirectional_range) { --it_; } private: uncounted_t it_; }; template struct trailing { trailing() = default; constexpr trailing(Rng &) noexcept {} constexpr uncounted_t get(iterator_t const & it, range_difference_t n) const { return uncounted(it - (n - 1)); } void next() {} void prev() {} }; template struct RANGES_EMPTY_BASES sv_base : view_adaptor, Rng, is_finite::value ? finite : range_cardinality::value> , private detail::non_propagating_cache, sv_base, caching::value != cache::none> { CPP_assert(forward_range); sv_base() = default; sv_base(Rng rng, range_difference_t n) : sv_base::view_adaptor(std::move(rng)) , n_(n) { RANGES_ASSERT(0 < n_); } CPP_member auto CPP_fun(size)()(const requires sized_range) { auto const count = ranges::size(this->base()); auto const n = static_cast>(n_); return count < n ? 0 : count - n + 1; } CPP_member auto CPP_fun(size)()(requires sized_range) { auto const count = ranges::size(this->base()); auto const n = static_cast>(n_); return count < n ? 0 : count - n + 1; } protected: range_difference_t n_; optional> & cache() & { return static_cast(*this); } optional> const & cache() const & { return static_cast(*this); } private: using cache_t = detail::non_propagating_cache, sv_base>; }; } // namespace sliding_view_detail /// \endcond /// \addtogroup group-views /// @{ template struct sliding_view : sliding_view_detail::sv_base { private: friend range_access; iterator_t get_first() { auto & first = this->cache(); if(!first) { first = ranges::next( ranges::begin(this->base()), this->n_ - 1, ranges::end(this->base())); } return *first; } struct RANGES_EMPTY_BASES adaptor : adaptor_base , sliding_view_detail::trailing { private: using base_t = sliding_view_detail::trailing; range_difference_t n_ = {}; public: adaptor() = default; adaptor(sliding_view * v) : base_t{v->base()} , n_{v->n_} {} iterator_t begin(sliding_view & v) { return v.get_first(); } auto read(iterator_t const & it) const -> decltype(views::counted(uncounted(it), n_)) { return views::counted(base_t::get(it, n_), n_); } void next(iterator_t & it) { ++it; base_t::next(); } CPP_member auto prev(iterator_t & it) -> CPP_ret(void)( // requires bidirectional_range) { base_t::prev(); --it; } CPP_member auto advance(iterator_t & it, range_difference_t n) -> CPP_ret(void)( // requires random_access_range) { it += n; } }; adaptor begin_adaptor() { return {this}; } meta::if_c, adaptor, adaptor_base> end_adaptor() { return {this}; } public: using sliding_view::sv_base::sv_base; }; template struct sliding_view : sliding_view_detail::sv_base { private: friend range_access; iterator_t get_last() { auto & last = this->cache(); if(!last) { last = ranges::prev( ranges::end(this->base()), this->n_ - 1, ranges::begin(this->base())); } return *last; } struct adaptor : adaptor_base { private: range_difference_t n_ = {}; public: adaptor() = default; adaptor(sliding_view * v) : n_{v->n_} {} iterator_t end(sliding_view & v) { return v.get_last(); } auto read(iterator_t const & it) const -> decltype(views::counted(uncounted(it), n_)) { return views::counted(uncounted(it), n_); } }; adaptor begin_adaptor() { return {this}; } adaptor end_adaptor() { return {this}; } public: using sliding_view::sv_base::sv_base; }; template struct sliding_view : sliding_view_detail::sv_base { private: friend range_access; template struct adaptor : adaptor_base { private: friend adaptor; using CRng = meta::const_if_c; range_difference_t n_ = 0; public: adaptor() = default; adaptor(range_difference_t n) : n_(n) {} template CPP_ctor(adaptor)(adaptor that)( // requires Const && (!Other)) : n_(that.n_) {} iterator_t end(meta::const_if_c & v) const { auto const sz = ranges::distance(v.base()); auto const offset = n_ - 1 < sz ? n_ - 1 : sz; return ranges::begin(v.base()) + (sz - offset); } auto read(iterator_t const & it) const -> decltype(views::counted(uncounted(it), n_)) { return views::counted(uncounted(it), n_); } }; adaptor()> begin_adaptor() { return {this->n_}; } CPP_member auto begin_adaptor() const -> CPP_ret(adaptor)( // requires range) { return {this->n_}; } adaptor()> end_adaptor() { return {this->n_}; } CPP_member auto end_adaptor() const -> CPP_ret(adaptor)( // requires range) { return {this->n_}; } public: using sliding_view::sv_base::sv_base; }; #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17 template sliding_view(Rng &&, range_difference_t)->sliding_view>; #endif namespace views { // In: range // Out: range>, where each inner range has $n$ elements. struct sliding_fn { private: friend view_access; template static constexpr auto CPP_fun(bind)(sliding_fn sliding, Int n)( // requires integral) { return make_pipeable(bind_back(sliding, n)); } public: template constexpr auto operator()(Rng && rng, range_difference_t n) const -> CPP_ret(sliding_view>)( // requires viewable_range && forward_range) { return {all(static_cast(rng)), n}; } }; /// \relates sliding_fn /// \ingroup group-views RANGES_INLINE_VARIABLE(view, sliding) } // namespace views /// @} } // namespace ranges #endif