/// \file // Range v3 library // // Copyright Andrey Diduh 2019 // // 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_DROP_LAST_HPP #define RANGES_V3_VIEW_DROP_LAST_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ranges { /// \cond namespace detail { namespace drop_last_view { template range_size_t get_size(Rng & rng, range_difference_t n_) { RANGES_EXPECT(n_ >= 0); range_size_t const initial_size = ranges::size(rng); range_size_t const n = static_cast>(n_); RANGES_EXPECT(initial_size >= n); return initial_size > n ? initial_size - n : 0; } template auto get_end(Rng & rng, range_difference_t n, int) -> CPP_ret(iterator_t)( // requires random_access_range && sized_range) { return begin(rng) + static_cast>( drop_last_view::get_size(rng, n)); } template auto get_end(Rng & rng, range_difference_t n, long) -> CPP_ret(iterator_t)( // requires bidirectional_range && common_range) { return prev(end(rng), n, begin(rng)); } enum class mode_enum { bidi, forward, sized, invalid }; template using mode_t = std::integral_constant; using mode_bidi = mode_t; using mode_forward = mode_t; using mode_sized = mode_t; using mode_invalid = mode_t; template constexpr mode_enum get_mode() noexcept { // keep range bound // Sized Bidi O(N) return (random_access_range && view_ && sized_range && view_) || (bidirectional_range && view_ && common_range && view_) // ? mode_enum::bidi // : sized_range && view_ // ? mode_enum::sized // : forward_range && view_ // ? mode_enum::forward // : mode_enum::invalid; // // max performance // Sized Bidi O(1) // Sized Bidi use mode::sized instead of mode::bidi - thus become unbound. /*return (random_access_range && view_ && sized_range && view_) || (bidirectional_range && view_ && common_range && view_) ? mode::bidi : sized_range && view_ ? mode::sized : bidirectional_range && view_ && common_range && view_ ? mode::bidi : forward_range && view_ ? mode::forward : mode::invalid;*/ } template using mode_of = mode_t()>; } // namespace drop_last_view } // namespace detail /// \endcond template> struct drop_last_view {}; template struct drop_last_view : view_interface, is_finite::value ? finite : range_cardinality::value> // finite at best { CPP_assert( (random_access_range && view_ && sized_range && view_) || (bidirectional_range && view_ && common_range && view_)); private: friend range_access; using difference_t = range_difference_t; Rng rng_; difference_t n_; detail::non_propagating_cache> end_; public: drop_last_view() = default; constexpr drop_last_view(Rng rng, difference_t n) : rng_(std::move(rng)) , n_(n) { RANGES_EXPECT(n >= 0); } iterator_t begin() { return ranges::begin(rng_); } sentinel_t end() { if(!end_) end_ = detail::drop_last_view::get_end(rng_, n_, 0); return *end_; } template auto begin() const -> CPP_ret(iterator_t)( // requires random_access_range && sized_range) { return ranges::begin(rng_); } template auto end() const -> CPP_ret(iterator_t)( // requires random_access_range && sized_range) { return detail::drop_last_view::get_end(rng_, n_, 0); } auto CPP_fun(size)()( // requires sized_range) { return detail::drop_last_view::get_size(rng_, n_); } CPP_member auto CPP_fun(size)()(const requires sized_range) { return detail::drop_last_view::get_size(rng_, n_); } Rng & base() { return rng_; } Rng const & base() const { return rng_; } }; template struct drop_last_view : view_adaptor, Rng, is_finite::value ? finite : range_cardinality::value> // finite at best (but // unknown is expected) { CPP_assert(forward_range && view_); private: friend range_access; using difference_t = range_difference_t; difference_t n_; detail::non_propagating_cache> probe_begin; struct adaptor : adaptor_base { iterator_t probe_; adaptor() = default; adaptor(iterator_t probe_first) : probe_(std::move(probe_first)) {} void next(iterator_t & it) { ++it; ++probe_; } }; struct sentinel_adaptor : adaptor_base { template bool empty(I const &, adaptor const & ia, S const & s) const { return ia.probe_ == s; } }; adaptor begin_adaptor() { if(!probe_begin) probe_begin = next(begin(this->base()), n_, end(this->base())); return {*probe_begin}; } sentinel_adaptor end_adaptor() { return {}; } public: drop_last_view() = default; constexpr drop_last_view(Rng rng, difference_t n) : drop_last_view::view_adaptor(std::move(rng)) , n_(n) { RANGES_EXPECT(n >= 0); } CPP_member auto CPP_fun(size)()( // requires sized_range) { return detail::drop_last_view::get_size(this->base(), n_); } CPP_member auto CPP_fun(size)()(const requires sized_range) { return detail::drop_last_view::get_size(this->base(), n_); } }; template struct drop_last_view : view_interface, finite> { CPP_assert(sized_range && view_); private: friend range_access; using difference_t = range_difference_t; Rng rng_; difference_t n_; public: drop_last_view() = default; constexpr drop_last_view(Rng rng, difference_t n) : rng_(std::move(rng)) , n_(n) { RANGES_EXPECT(n >= 0); } counted_iterator> begin() { return {ranges::begin(rng_), static_cast(size())}; } template auto begin() const -> CPP_ret(counted_iterator>)( // requires sized_range) { return {ranges::begin(rng_), static_cast(size())}; } default_sentinel_t end() const { return {}; } range_size_t size() { return detail::drop_last_view::get_size(this->base(), n_); } CPP_member auto CPP_fun(size)()(const requires sized_range) { return detail::drop_last_view::get_size(this->base(), n_); } Rng & base() { return rng_; } Rng const & base() const { return rng_; } }; #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17 template drop_last_view(Rng &&, range_difference_t)->drop_last_view>; #endif namespace views { struct drop_last_fn { private: friend view_access; template static constexpr auto CPP_fun(bind)(drop_last_fn drop_last, Int n)( // requires integral) { return make_pipeable(bind_back(drop_last, n)); } public: template constexpr auto operator()(Rng && rng, range_difference_t n) const -> CPP_ret(drop_last_view>)( // requires sized_range || forward_range) { return {all(static_cast(rng)), n}; } }; RANGES_INLINE_VARIABLE(view, drop_last) } // namespace views } // namespace ranges #include RANGES_SATISFY_BOOST_RANGE(::ranges::drop_last_view) #endif