| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463 |
- /// \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_CHUNK_HPP
- #define RANGES_V3_VIEW_CHUNK_HPP
- #include <limits>
- #include <utility>
- #include <meta/meta.hpp>
- #include <range/v3/range_fwd.hpp>
- #include <range/v3/functional/bind_back.hpp>
- #include <range/v3/iterator/default_sentinel.hpp>
- #include <range/v3/iterator/operations.hpp>
- #include <range/v3/range/access.hpp>
- #include <range/v3/range/concepts.hpp>
- #include <range/v3/range/traits.hpp>
- #include <range/v3/utility/box.hpp>
- #include <range/v3/utility/optional.hpp> // for non_propagating_cache
- #include <range/v3/utility/static_const.hpp>
- #include <range/v3/view/adaptor.hpp>
- #include <range/v3/view/all.hpp>
- #include <range/v3/view/facade.hpp>
- #include <range/v3/view/take.hpp>
- #include <range/v3/view/view.hpp>
- #include <range/v3/detail/prologue.hpp>
- namespace ranges
- {
- /// \cond
- namespace detail
- {
- template<typename Rng, bool Const>
- constexpr bool can_sized_sentinel_() noexcept
- {
- using I = iterator_t<meta::const_if_c<Const, Rng>>;
- return (bool)sized_sentinel_for<I, I>;
- }
- template<typename T>
- struct zero
- {
- zero() = default;
- constexpr explicit zero(T const &) noexcept
- {}
- constexpr zero & operator=(T const &) noexcept
- {
- return *this;
- }
- constexpr zero const & operator=(T const &) const noexcept
- {
- return *this;
- }
- constexpr operator T() const
- {
- return T(0);
- }
- constexpr T exchange(T const &) const
- {
- return T(0);
- }
- };
- } // namespace detail
- /// \endcond
- /// \addtogroup group-views
- /// @{
- template<typename Rng, bool IsForwardRange>
- struct chunk_view_
- : view_adaptor<chunk_view_<Rng, IsForwardRange>, Rng,
- is_finite<Rng>::value ? finite : range_cardinality<Rng>::value>
- {
- private:
- friend range_access;
- CPP_assert(forward_range<Rng>);
- template<bool Const>
- using offset_t =
- meta::if_c<bidirectional_range<meta::const_if_c<Const, Rng>> ||
- detail::can_sized_sentinel_<Rng, Const>(),
- range_difference_t<Rng>, detail::zero<range_difference_t<Rng>>>;
- range_difference_t<Rng> n_ = 0;
- template<bool Const>
- struct RANGES_EMPTY_BASES adaptor
- : adaptor_base
- , private box<offset_t<Const>>
- {
- private:
- friend adaptor<!Const>;
- using CRng = meta::const_if_c<Const, Rng>;
- range_difference_t<CRng> n_;
- sentinel_t<CRng> end_;
- constexpr offset_t<Const> const & offset() const
- {
- offset_t<Const> const & result = this->box<offset_t<Const>>::get();
- RANGES_EXPECT(0 <= result && result < n_);
- return result;
- }
- constexpr offset_t<Const> & offset()
- {
- return const_cast<offset_t<Const> &>(
- const_cast<adaptor const &>(*this).offset());
- }
- public:
- adaptor() = default;
- constexpr adaptor(meta::const_if_c<Const, chunk_view_> * cv)
- : box<offset_t<Const>>{0}
- , n_((RANGES_EXPECT(0 < cv->n_), cv->n_))
- , end_(ranges::end(cv->base()))
- {}
- template(bool Other)(
- requires Const AND CPP_NOT(Other)) //
- constexpr adaptor(adaptor<Other> that)
- : box<offset_t<Const>>(that.offset())
- , n_(that.n_)
- , end_(that.end_)
- {}
- constexpr auto read(iterator_t<CRng> const & it) const
- -> decltype(views::take(make_subrange(it, end_), n_))
- {
- RANGES_EXPECT(it != end_);
- RANGES_EXPECT(0 == offset());
- return views::take(make_subrange(it, end_), n_);
- }
- constexpr void next(iterator_t<CRng> & it)
- {
- RANGES_EXPECT(it != end_);
- RANGES_EXPECT(0 == offset());
- offset() = ranges::advance(it, n_, end_);
- }
- CPP_member
- constexpr auto prev(iterator_t<CRng> & it) //
- -> CPP_ret(void)(
- requires bidirectional_range<CRng>)
- {
- ranges::advance(it, -n_ + offset());
- offset() = 0;
- }
- CPP_member
- constexpr auto distance_to(iterator_t<CRng> const & here,
- iterator_t<CRng> const & there,
- adaptor const & that) const
- -> CPP_ret(range_difference_t<Rng>)(
- requires (detail::can_sized_sentinel_<Rng, Const>()))
- {
- auto const delta = (there - here) + (that.offset() - offset());
- // This can fail for cyclic base ranges when the chunk size does not
- // divide the cycle length. Such iterator pairs are NOT in the domain of
- // -.
- RANGES_ENSURE(0 == delta % n_);
- return delta / n_;
- }
- CPP_member
- constexpr auto advance(iterator_t<CRng> & it, range_difference_t<Rng> n) //
- -> CPP_ret(void)(
- requires random_access_range<CRng>)
- {
- using Limits = std::numeric_limits<range_difference_t<CRng>>;
- if(0 < n)
- {
- RANGES_EXPECT(0 == offset());
- RANGES_EXPECT(n <= Limits::max() / n_);
- auto const remainder = ranges::advance(it, n * n_, end_) % n_;
- RANGES_EXPECT(0 <= remainder && remainder < n_);
- offset() = remainder;
- }
- else if(0 > n)
- {
- RANGES_EXPECT(n >= Limits::min() / n_);
- ranges::advance(it, n * n_ + offset());
- offset() = 0;
- }
- }
- };
- constexpr adaptor<simple_view<Rng>()> begin_adaptor()
- {
- return adaptor<simple_view<Rng>()>{this};
- }
- CPP_member
- constexpr auto begin_adaptor() const //
- -> CPP_ret(adaptor<true>)(
- requires forward_range<Rng const>)
- {
- return adaptor<true>{this};
- }
- template<typename Size>
- constexpr Size size_(Size base_size) const
- {
- auto const n = static_cast<Size>(n_);
- return base_size / n + (0 != (base_size % n));
- }
- public:
- chunk_view_() = default;
- constexpr chunk_view_(Rng rng, range_difference_t<Rng> n)
- : chunk_view_::view_adaptor(detail::move(rng))
- , n_((RANGES_EXPECT(0 < n), n))
- {}
- CPP_auto_member
- constexpr auto CPP_fun(size)()(const
- requires sized_range<Rng const>)
- {
- return size_(ranges::size(this->base()));
- }
- CPP_auto_member
- constexpr auto CPP_fun(size)()(
- requires sized_range<Rng>)
- {
- return size_(ranges::size(this->base()));
- }
- };
- template<typename Rng>
- struct chunk_view_<Rng, false>
- : view_facade<chunk_view_<Rng, false>,
- is_finite<Rng>::value ? finite : range_cardinality<Rng>::value>
- {
- private:
- friend range_access;
- CPP_assert(input_range<Rng> && !forward_range<Rng>);
- using iter_cache_t = detail::non_propagating_cache<iterator_t<Rng>>;
- Rng base_;
- range_difference_t<Rng> n_;
- range_difference_t<Rng> remainder_;
- mutable iter_cache_t it_cache_;
- constexpr iterator_t<Rng> & it() noexcept
- {
- return *it_cache_;
- }
- constexpr iterator_t<Rng> const & it() const noexcept
- {
- return *it_cache_;
- }
- struct outer_cursor
- {
- private:
- struct inner_view : view_facade<inner_view, finite>
- {
- private:
- friend range_access;
- using value_type = range_value_t<Rng>;
- chunk_view_ * rng_ = nullptr;
- constexpr bool done() const noexcept
- {
- RANGES_EXPECT(rng_);
- return rng_->remainder_ == 0;
- }
- constexpr bool equal(default_sentinel_t) const noexcept
- {
- return done();
- }
- constexpr iter_reference_t<iterator_t<Rng>> read() const
- {
- RANGES_EXPECT(!done());
- return *rng_->it();
- }
- constexpr iter_rvalue_reference_t<iterator_t<Rng>> move() const
- {
- RANGES_EXPECT(!done());
- return ranges::iter_move(rng_->it());
- }
- constexpr void next()
- {
- RANGES_EXPECT(!done());
- ++rng_->it();
- --rng_->remainder_;
- if(rng_->remainder_ != 0 && rng_->it() == ranges::end(rng_->base_))
- rng_->remainder_ = 0;
- }
- CPP_member
- constexpr auto distance_to(default_sentinel_t) const
- -> CPP_ret(range_difference_t<Rng>)(
- requires sized_sentinel_for<sentinel_t<Rng>, iterator_t<Rng>>)
- {
- RANGES_EXPECT(rng_);
- auto const d = ranges::end(rng_->base_) - rng_->it();
- return ranges::min(d, rng_->remainder_);
- }
- public:
- inner_view() = default;
- constexpr explicit inner_view(chunk_view_ * view) noexcept
- : rng_{view}
- {}
- CPP_auto_member
- constexpr auto CPP_fun(size)()(
- requires sized_sentinel_for<sentinel_t<Rng>, iterator_t<Rng>>)
- {
- using size_type = detail::iter_size_t<iterator_t<Rng>>;
- return static_cast<size_type>(distance_to(default_sentinel_t{}));
- }
- };
- chunk_view_ * rng_ = nullptr;
- public:
- using value_type = inner_view;
- outer_cursor() = default;
- constexpr explicit outer_cursor(chunk_view_ * view) noexcept
- : rng_{view}
- {}
- constexpr inner_view read() const
- {
- RANGES_EXPECT(!done());
- return inner_view{rng_};
- }
- constexpr bool done() const
- {
- RANGES_EXPECT(rng_);
- return rng_->it() == ranges::end(rng_->base_) && rng_->remainder_ != 0;
- }
- constexpr bool equal(default_sentinel_t) const
- {
- return done();
- }
- constexpr void next()
- {
- RANGES_EXPECT(!done());
- ranges::advance(rng_->it(), rng_->remainder_, ranges::end(rng_->base_));
- rng_->remainder_ = rng_->n_;
- }
- CPP_member
- constexpr auto distance_to(default_sentinel_t) const
- -> CPP_ret(range_difference_t<Rng>)(
- requires sized_sentinel_for<sentinel_t<Rng>, iterator_t<Rng>>)
- {
- RANGES_EXPECT(rng_);
- auto d = ranges::end(rng_->base_) - rng_->it();
- if(d < rng_->remainder_)
- return 1;
- d -= rng_->remainder_;
- d = (d + rng_->n_ - 1) / rng_->n_;
- d += (rng_->remainder_ != 0);
- return d;
- }
- };
- constexpr outer_cursor begin_cursor() noexcept
- {
- it_cache_ = ranges::begin(base_);
- return outer_cursor{this};
- }
- template<typename Size>
- constexpr Size size_(Size base_size) const
- {
- auto const n = static_cast<Size>(this->n_);
- return base_size / n + (0 != base_size % n);
- }
- public:
- chunk_view_() = default;
- constexpr chunk_view_(Rng rng, range_difference_t<Rng> n)
- : base_(detail::move(rng))
- , n_((RANGES_EXPECT(0 < n), n))
- , remainder_(n)
- , it_cache_{nullopt}
- {}
- CPP_auto_member
- constexpr auto CPP_fun(size)()(const
- requires sized_range<Rng const>)
- {
- return size_(ranges::size(base_));
- }
- CPP_auto_member
- constexpr auto CPP_fun(size)()(
- requires sized_range<Rng>)
- {
- return size_(ranges::size(base_));
- }
- Rng base() const
- {
- return base_;
- }
- };
- template<typename Rng>
- struct chunk_view : chunk_view_<Rng, (bool)forward_range<Rng>>
- {
- chunk_view() = default;
- constexpr chunk_view(Rng rng, range_difference_t<Rng> n)
- : chunk_view_<Rng, (bool)forward_range<Rng>>(static_cast<Rng &&>(rng), n)
- {}
- };
- // Need to keep extra state for input_range, but forward_range is transparent
- template<typename Rng>
- RANGES_INLINE_VAR constexpr bool enable_borrowed_range<chunk_view<Rng>> =
- enable_borrowed_range<Rng> && forward_range<Rng>;
- #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
- template<typename Rng>
- chunk_view(Rng &&, range_difference_t<Rng>)
- -> chunk_view<views::all_t<Rng>>;
- #endif
- namespace views
- {
- // In: range<T>
- // Out: range<range<T>>, where each inner range has $n$ elements.
- // The last range may have fewer.
- struct chunk_base_fn
- {
- template(typename Rng)(
- requires viewable_range<Rng> AND input_range<Rng>)
- constexpr chunk_view<all_t<Rng>> //
- operator()(Rng && rng, range_difference_t<Rng> n) const
- {
- return {all(static_cast<Rng &&>(rng)), n};
- }
- };
- struct chunk_fn : chunk_base_fn
- {
- using chunk_base_fn::operator();
- template(typename Int)(
- requires detail::integer_like_<Int>)
- constexpr auto operator()(Int n) const
- {
- return make_view_closure(bind_back(chunk_base_fn{}, n));
- }
- };
- /// \relates chunk_fn
- /// \ingroup group-views
- RANGES_INLINE_VARIABLE(chunk_fn, chunk)
- } // namespace views
- /// @}
- } // namespace ranges
- #include <range/v3/detail/epilogue.hpp>
- #include <range/v3/detail/satisfy_boost_range.hpp>
- RANGES_SATISFY_BOOST_RANGE(::ranges::chunk_view)
- #endif
|