/// \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_VIEW_CACHE1_HPP #define RANGES_V3_VIEW_CACHE1_HPP #include #include #include #include #include #include #include #include #include #include #include namespace ranges { /// \addtogroup group-views /// @{ template struct cache1_view : view_facade, range_cardinality::value> { private: CPP_assert(view_); CPP_assert(input_range); CPP_assert(constructible_from, range_reference_t>); friend range_access; Rng rng_; bool dirty_ = true; detail::non_propagating_cache> cache_; CPP_member auto update_(range_reference_t && val) // -> CPP_ret(void)( requires assignable_from &, range_reference_t>) { if(!cache_) cache_.emplace(static_cast &&>(val)); else *cache_ = static_cast &&>(val); } CPP_member auto update_(range_reference_t && val) // -> CPP_ret(void)( requires (!assignable_from &, range_reference_t>)) { cache_.emplace(static_cast &&>(val)); } struct cursor; struct sentinel { private: friend cursor; sentinel_t last_; public: sentinel() = default; constexpr explicit sentinel(sentinel_t last) : last_(std::move(last)) {} }; struct cursor { private: cache1_view * parent_; iterator_t current_; public: using value_type = range_value_t; using single_pass = std::true_type; using difference_type = range_difference_t; cursor() = default; constexpr explicit cursor(cache1_view * parent, iterator_t current) : parent_(parent) , current_(std::move(current)) {} range_value_t && read() const { if(parent_->dirty_) { parent_->update_(*current_); parent_->dirty_ = false; } return std::move(*parent_->cache_); } void next() { ++current_; parent_->dirty_ = true; } bool equal(cursor const & that) const { return current_ == that.current_; } bool equal(sentinel const & that) const { return current_ == that.last_; } CPP_member auto distance_to(cursor const & that) const // -> CPP_ret(difference_type)( requires sized_sentinel_for, iterator_t>) { return that.current_ - current_; } CPP_member auto distance_to(sentinel const & that) const // -> CPP_ret(difference_type)( requires sized_sentinel_for, iterator_t>) { return that.last_ - current_; } }; cursor begin_cursor() { dirty_ = true; return cursor{this, ranges::begin(rng_)}; } cursor end_cursor_impl(std::true_type) { return cursor{this, ranges::end(rng_)}; } sentinel end_cursor_impl(std::false_type) { return sentinel{ranges::end(rng_)}; } auto end_cursor() { return end_cursor_impl(meta::bool_<(bool)common_range>{}); } public: cache1_view() = default; constexpr explicit cache1_view(Rng rng) : rng_{std::move(rng)} {} CPP_auto_member constexpr auto CPP_fun(size)()( requires sized_range) { return ranges::size(rng_); } }; #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17 template cache1_view(Rng &&) // -> cache1_view>; #endif namespace views { struct cache1_fn { /// \brief Caches the most recent element within the view so that /// dereferencing the view's iterator multiple times doesn't incur any /// recomputation. This can be useful in adaptor pipelines that include /// combinations of \c view::filter and \c view::transform, for instance. /// \note \c views::cache1 is always single-pass. template(typename Rng)( requires viewable_range AND input_range AND constructible_from, range_reference_t>) constexpr cache1_view> operator()(Rng && rng) const // { return cache1_view>{all(static_cast(rng))}; } }; /// \relates cache1_fn /// \ingroup group-views RANGES_INLINE_VARIABLE(view_closure, cache1) } // namespace views /// @} } // namespace ranges #include #include RANGES_SATISFY_BOOST_RANGE(::ranges::cache1_view) #endif