/// \file // Range v3 library // // Copyright Eric Niebler 2013-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_SLICE_HPP #define RANGES_V3_VIEW_SLICE_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ranges { /// \cond namespace detail { template iterator_t pos_at_(Rng && rng, Int i, input_range_tag, std::true_type) { RANGES_EXPECT(0 <= i); return next(ranges::begin(rng), i); } template iterator_t pos_at_(Rng && rng, Int i, bidirectional_range_tag, std::false_type) { if(0 > i) { // If it's not common and we know the size, faster to count from the front if(RANGES_CONSTEXPR_IF(sized_range && !common_range)) return next(ranges::begin(rng), distance(rng) + i); // Otherwise, probably faster to count from the back. return next(ranges::next(ranges::begin(rng), ranges::end(rng)), i); } return next(ranges::begin(rng), i); } template iterator_t pos_at_(Rng && rng, Int i, input_range_tag, std::false_type) { RANGES_EXPECT(i >= 0 || (bool)sized_range || (bool)forward_range); if(0 > i) return next(ranges::begin(rng), distance(rng) + i); return next(ranges::begin(rng), i); } template struct slice_view_ : view_facade, finite> { private: friend range_access; Rng rng_; range_difference_t from_, count_; detail::non_propagating_cache> begin_; iterator_t get_begin_() { if(!begin_) begin_ = detail::pos_at_( rng_, from_, range_tag_of{}, is_infinite{}); return *begin_; } public: slice_view_() = default; constexpr slice_view_(Rng rng, range_difference_t from, range_difference_t count) : rng_(std::move(rng)) , from_(from) , count_(count) {} counted_iterator> begin() { return make_counted_iterator(get_begin_(), count_); } default_sentinel_t end() { return {}; } auto size() const { return static_cast>>(count_); } Rng base() const { return rng_; } }; template struct slice_view_ : view_interface, finite> { private: Rng rng_; range_difference_t from_, count_; public: slice_view_() = default; constexpr slice_view_(Rng rng, range_difference_t from, range_difference_t count) : rng_(std::move(rng)) , from_(from) , count_(count) { RANGES_EXPECT(0 <= count_); } iterator_t begin() { return detail::pos_at_( rng_, from_, range_tag_of{}, is_infinite{}); } iterator_t end() { return detail::pos_at_( rng_, from_, range_tag_of{}, is_infinite{}) + count_; } template auto begin() const -> CPP_ret(iterator_t)( // requires range) { return detail::pos_at_( rng_, from_, range_tag_of{}, is_infinite{}); } template auto end() const -> CPP_ret(iterator_t)( // requires range) { return detail::pos_at_( rng_, from_, range_tag_of{}, is_infinite{}) + count_; } auto size() const { return static_cast>>(count_); } Rng base() const { return rng_; } }; } // namespace detail /// \endcond /// \addtogroup group-views /// @{ template struct slice_view : detail::slice_view_> { using detail::slice_view_>::slice_view_; }; #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17 template slice_view(Rng &&, range_difference_t, range_difference_t) ->slice_view>; #endif namespace views { struct slice_fn { private: friend view_access; template constexpr static slice_view> impl_(Rng && rng, range_difference_t from, range_difference_t count, input_range_tag, range_tag = {}) { return {all(static_cast(rng)), from, count}; } template static auto impl_(Rng && rng, range_difference_t from, range_difference_t count, random_access_range_tag, common_range_tag = {}) -> CPP_ret(subrange>)( // requires forwarding_range_) { auto it = detail::pos_at_(rng, from, range_tag_of{}, is_infinite{}); return {it, it + count}; } // Overloads for the pipe syntax: rng | views::slice(from,to) template static constexpr auto CPP_fun(bind)(slice_fn slice, Int from, Int to)( // requires detail::integer_like_) { return make_pipeable(bind_back(slice, from, to)); } template static constexpr auto CPP_fun(bind)(slice_fn slice, Int from, detail::from_end_ to)( // requires detail::integer_like_) { return make_pipeable(bind_back(slice, from, to)); } template static constexpr auto CPP_fun(bind)(slice_fn slice, detail::from_end_ from, detail::from_end_ to)( // requires detail::integer_like_) { return make_pipeable(bind_back(slice, from, to)); } template static constexpr auto CPP_fun(bind)(slice_fn, Int from, end_fn)( // requires detail::integer_like_) { return make_pipeable(bind_back(ranges::views::drop_exactly, from)); } template static constexpr auto CPP_fun(bind)(slice_fn slice, detail::from_end_ from, end_fn to)( // requires detail::integer_like_) { return make_pipeable(bind_back(slice, from, to)); } public: // slice(rng, 2, 4) template constexpr auto CPP_fun(operator())( // Rng && rng, range_difference_t from, range_difference_t to)( const requires viewable_range && input_range) { RANGES_EXPECT(0 <= from && from <= to); return slice_fn::impl_( static_cast(rng), from, to - from, range_tag_of{}); } // slice(rng, 4, end-2) // TODO Support Forward, non-Sized ranges by returning a range that // doesn't know it's size? template auto CPP_fun(operator())( // Rng && rng, range_difference_t from, detail::from_end_of_t to)(const requires viewable_range && input_range && sized_range) { static_assert(!is_infinite::value, "Can't index from the end of an infinite range!"); RANGES_EXPECT(0 <= from); RANGES_ASSERT(from <= distance(rng) + to.dist_); return slice_fn::impl_(static_cast(rng), from, distance(rng) + to.dist_ - from, range_tag_of{}); } // slice(rng, end-4, end-2) template auto CPP_fun(operator())( // Rng && rng, detail::from_end_of_t from, detail::from_end_of_t to)(const requires viewable_range && (forward_range || (input_range && sized_range))) { static_assert(!is_infinite::value, "Can't index from the end of an infinite range!"); RANGES_EXPECT(from.dist_ <= to.dist_); return slice_fn::impl_(static_cast(rng), from.dist_, to.dist_ - from.dist_, range_tag_of{}, common_range_tag_of{}); } // slice(rng, 4, end) template auto CPP_fun(operator())(Rng && rng, range_difference_t from, end_fn)( const requires viewable_range && input_range) { RANGES_EXPECT(0 <= from); return ranges::views::drop_exactly(static_cast(rng), from); } // slice(rng, end-4, end) template auto CPP_fun(operator())(Rng && rng, detail::from_end_of_t from, end_fn)(const requires viewable_range && (forward_range || (input_range && sized_range))) { static_assert(!is_infinite::value, "Can't index from the end of an infinite range!"); return slice_fn::impl_(static_cast(rng), from.dist_, -from.dist_, range_tag_of{}, common_range_tag_of{}); } }; /// \relates _slice_fn /// \ingroup group-views RANGES_INLINE_VARIABLE(view, slice) } // namespace views /// @} } // namespace ranges #include RANGES_SATISFY_BOOST_RANGE(::ranges::slice_view) #endif