File indexing completed on 2025-01-18 10:09:54
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef RANGES_V3_VIEW_CHUNK_HPP
0015 #define RANGES_V3_VIEW_CHUNK_HPP
0016
0017 #include <limits>
0018 #include <utility>
0019
0020 #include <meta/meta.hpp>
0021
0022 #include <range/v3/range_fwd.hpp>
0023
0024 #include <range/v3/functional/bind_back.hpp>
0025 #include <range/v3/iterator/default_sentinel.hpp>
0026 #include <range/v3/iterator/operations.hpp>
0027 #include <range/v3/range/access.hpp>
0028 #include <range/v3/range/concepts.hpp>
0029 #include <range/v3/range/traits.hpp>
0030 #include <range/v3/utility/box.hpp>
0031 #include <range/v3/utility/optional.hpp> // for non_propagating_cache
0032 #include <range/v3/utility/static_const.hpp>
0033 #include <range/v3/view/adaptor.hpp>
0034 #include <range/v3/view/all.hpp>
0035 #include <range/v3/view/facade.hpp>
0036 #include <range/v3/view/take.hpp>
0037 #include <range/v3/view/view.hpp>
0038
0039 #include <range/v3/detail/prologue.hpp>
0040
0041 namespace ranges
0042 {
0043
0044 namespace detail
0045 {
0046 template<typename Rng, bool Const>
0047 constexpr bool can_sized_sentinel_() noexcept
0048 {
0049 using I = iterator_t<meta::const_if_c<Const, Rng>>;
0050 return (bool)sized_sentinel_for<I, I>;
0051 }
0052
0053 template<typename T>
0054 struct zero
0055 {
0056 zero() = default;
0057 constexpr explicit zero(T const &) noexcept
0058 {}
0059 constexpr zero & operator=(T const &) noexcept
0060 {
0061 return *this;
0062 }
0063 constexpr zero const & operator=(T const &) const noexcept
0064 {
0065 return *this;
0066 }
0067 constexpr operator T() const
0068 {
0069 return T(0);
0070 }
0071 constexpr T exchange(T const &) const
0072 {
0073 return T(0);
0074 }
0075 };
0076 }
0077
0078
0079
0080
0081 template<typename Rng, bool IsForwardRange>
0082 struct chunk_view_
0083 : view_adaptor<chunk_view_<Rng, IsForwardRange>, Rng,
0084 is_finite<Rng>::value ? finite : range_cardinality<Rng>::value>
0085 {
0086 private:
0087 friend range_access;
0088 CPP_assert(forward_range<Rng>);
0089
0090 template<bool Const>
0091 using offset_t =
0092 meta::if_c<bidirectional_range<meta::const_if_c<Const, Rng>> ||
0093 detail::can_sized_sentinel_<Rng, Const>(),
0094 range_difference_t<Rng>, detail::zero<range_difference_t<Rng>>>;
0095
0096 range_difference_t<Rng> n_ = 0;
0097
0098 template<bool Const>
0099 struct RANGES_EMPTY_BASES adaptor
0100 : adaptor_base
0101 , private box<offset_t<Const>>
0102 {
0103 private:
0104 friend adaptor<!Const>;
0105 using CRng = meta::const_if_c<Const, Rng>;
0106
0107 range_difference_t<CRng> n_;
0108 sentinel_t<CRng> end_;
0109
0110 constexpr offset_t<Const> const & offset() const
0111 {
0112 offset_t<Const> const & result = this->box<offset_t<Const>>::get();
0113 RANGES_EXPECT(0 <= result && result < n_);
0114 return result;
0115 }
0116 constexpr offset_t<Const> & offset()
0117 {
0118 return const_cast<offset_t<Const> &>(
0119 const_cast<adaptor const &>(*this).offset());
0120 }
0121
0122 public:
0123 adaptor() = default;
0124 constexpr adaptor(meta::const_if_c<Const, chunk_view_> * cv)
0125 : box<offset_t<Const>>{0}
0126 , n_((RANGES_EXPECT(0 < cv->n_), cv->n_))
0127 , end_(ranges::end(cv->base()))
0128 {}
0129 template(bool Other)(
0130 requires Const AND CPP_NOT(Other))
0131 constexpr adaptor(adaptor<Other> that)
0132 : box<offset_t<Const>>(that.offset())
0133 , n_(that.n_)
0134 , end_(that.end_)
0135 {}
0136 constexpr auto read(iterator_t<CRng> const & it) const
0137 -> decltype(views::take(make_subrange(it, end_), n_))
0138 {
0139 RANGES_EXPECT(it != end_);
0140 RANGES_EXPECT(0 == offset());
0141 return views::take(make_subrange(it, end_), n_);
0142 }
0143 constexpr void next(iterator_t<CRng> & it)
0144 {
0145 RANGES_EXPECT(it != end_);
0146 RANGES_EXPECT(0 == offset());
0147 offset() = ranges::advance(it, n_, end_);
0148 }
0149 CPP_member
0150 constexpr auto prev(iterator_t<CRng> & it)
0151 -> CPP_ret(void)(
0152 requires bidirectional_range<CRng>)
0153 {
0154 ranges::advance(it, -n_ + offset());
0155 offset() = 0;
0156 }
0157 CPP_member
0158 constexpr auto distance_to(iterator_t<CRng> const & here,
0159 iterator_t<CRng> const & there,
0160 adaptor const & that) const
0161 -> CPP_ret(range_difference_t<Rng>)(
0162 requires (detail::can_sized_sentinel_<Rng, Const>()))
0163 {
0164 auto const delta = (there - here) + (that.offset() - offset());
0165
0166
0167
0168 RANGES_ENSURE(0 == delta % n_);
0169 return delta / n_;
0170 }
0171 CPP_member
0172 constexpr auto advance(iterator_t<CRng> & it, range_difference_t<Rng> n)
0173 -> CPP_ret(void)(
0174 requires random_access_range<CRng>)
0175 {
0176 using Limits = std::numeric_limits<range_difference_t<CRng>>;
0177 if(0 < n)
0178 {
0179 RANGES_EXPECT(0 == offset());
0180 RANGES_EXPECT(n <= Limits::max() / n_);
0181 auto const remainder = ranges::advance(it, n * n_, end_) % n_;
0182 RANGES_EXPECT(0 <= remainder && remainder < n_);
0183 offset() = remainder;
0184 }
0185 else if(0 > n)
0186 {
0187 RANGES_EXPECT(n >= Limits::min() / n_);
0188 ranges::advance(it, n * n_ + offset());
0189 offset() = 0;
0190 }
0191 }
0192 };
0193
0194 constexpr adaptor<simple_view<Rng>()> begin_adaptor()
0195 {
0196 return adaptor<simple_view<Rng>()>{this};
0197 }
0198 CPP_member
0199 constexpr auto begin_adaptor() const
0200 -> CPP_ret(adaptor<true>)(
0201 requires forward_range<Rng const>)
0202 {
0203 return adaptor<true>{this};
0204 }
0205 template<typename Size>
0206 constexpr Size size_(Size base_size) const
0207 {
0208 auto const n = static_cast<Size>(n_);
0209 return base_size / n + (0 != (base_size % n));
0210 }
0211
0212 public:
0213 chunk_view_() = default;
0214 constexpr chunk_view_(Rng rng, range_difference_t<Rng> n)
0215 : chunk_view_::view_adaptor(detail::move(rng))
0216 , n_((RANGES_EXPECT(0 < n), n))
0217 {}
0218 CPP_auto_member
0219 constexpr auto CPP_fun(size)()(const
0220 requires sized_range<Rng const>)
0221 {
0222 return size_(ranges::size(this->base()));
0223 }
0224 CPP_auto_member
0225 constexpr auto CPP_fun(size)()(
0226 requires sized_range<Rng>)
0227 {
0228 return size_(ranges::size(this->base()));
0229 }
0230 };
0231
0232 template<typename Rng>
0233 struct chunk_view_<Rng, false>
0234 : view_facade<chunk_view_<Rng, false>,
0235 is_finite<Rng>::value ? finite : range_cardinality<Rng>::value>
0236 {
0237 private:
0238 friend range_access;
0239 CPP_assert(input_range<Rng> && !forward_range<Rng>);
0240
0241 using iter_cache_t = detail::non_propagating_cache<iterator_t<Rng>>;
0242
0243 Rng base_;
0244 range_difference_t<Rng> n_;
0245 range_difference_t<Rng> remainder_;
0246 mutable iter_cache_t it_cache_;
0247
0248 constexpr iterator_t<Rng> & it() noexcept
0249 {
0250 return *it_cache_;
0251 }
0252 constexpr iterator_t<Rng> const & it() const noexcept
0253 {
0254 return *it_cache_;
0255 }
0256
0257 struct outer_cursor
0258 {
0259 private:
0260 struct inner_view : view_facade<inner_view, finite>
0261 {
0262 private:
0263 friend range_access;
0264
0265 using value_type = range_value_t<Rng>;
0266
0267 chunk_view_ * rng_ = nullptr;
0268
0269 constexpr bool done() const noexcept
0270 {
0271 RANGES_EXPECT(rng_);
0272 return rng_->remainder_ == 0;
0273 }
0274 constexpr bool equal(default_sentinel_t) const noexcept
0275 {
0276 return done();
0277 }
0278 constexpr iter_reference_t<iterator_t<Rng>> read() const
0279 {
0280 RANGES_EXPECT(!done());
0281 return *rng_->it();
0282 }
0283 constexpr iter_rvalue_reference_t<iterator_t<Rng>> move() const
0284 {
0285 RANGES_EXPECT(!done());
0286 return ranges::iter_move(rng_->it());
0287 }
0288 constexpr void next()
0289 {
0290 RANGES_EXPECT(!done());
0291 ++rng_->it();
0292 --rng_->remainder_;
0293 if(rng_->remainder_ != 0 && rng_->it() == ranges::end(rng_->base_))
0294 rng_->remainder_ = 0;
0295 }
0296 CPP_member
0297 constexpr auto distance_to(default_sentinel_t) const
0298 -> CPP_ret(range_difference_t<Rng>)(
0299 requires sized_sentinel_for<sentinel_t<Rng>, iterator_t<Rng>>)
0300 {
0301 RANGES_EXPECT(rng_);
0302 auto const d = ranges::end(rng_->base_) - rng_->it();
0303 return ranges::min(d, rng_->remainder_);
0304 }
0305
0306 public:
0307 inner_view() = default;
0308 constexpr explicit inner_view(chunk_view_ * view) noexcept
0309 : rng_{view}
0310 {}
0311 CPP_auto_member
0312 constexpr auto CPP_fun(size)()(
0313 requires sized_sentinel_for<sentinel_t<Rng>, iterator_t<Rng>>)
0314 {
0315 using size_type = detail::iter_size_t<iterator_t<Rng>>;
0316 return static_cast<size_type>(distance_to(default_sentinel_t{}));
0317 }
0318 };
0319
0320 chunk_view_ * rng_ = nullptr;
0321
0322 public:
0323 using value_type = inner_view;
0324
0325 outer_cursor() = default;
0326 constexpr explicit outer_cursor(chunk_view_ * view) noexcept
0327 : rng_{view}
0328 {}
0329 constexpr inner_view read() const
0330 {
0331 RANGES_EXPECT(!done());
0332 return inner_view{rng_};
0333 }
0334 constexpr bool done() const
0335 {
0336 RANGES_EXPECT(rng_);
0337 return rng_->it() == ranges::end(rng_->base_) && rng_->remainder_ != 0;
0338 }
0339 constexpr bool equal(default_sentinel_t) const
0340 {
0341 return done();
0342 }
0343 constexpr void next()
0344 {
0345 RANGES_EXPECT(!done());
0346 ranges::advance(rng_->it(), rng_->remainder_, ranges::end(rng_->base_));
0347 rng_->remainder_ = rng_->n_;
0348 }
0349 CPP_member
0350 constexpr auto distance_to(default_sentinel_t) const
0351 -> CPP_ret(range_difference_t<Rng>)(
0352 requires sized_sentinel_for<sentinel_t<Rng>, iterator_t<Rng>>)
0353 {
0354 RANGES_EXPECT(rng_);
0355 auto d = ranges::end(rng_->base_) - rng_->it();
0356 if(d < rng_->remainder_)
0357 return 1;
0358
0359 d -= rng_->remainder_;
0360 d = (d + rng_->n_ - 1) / rng_->n_;
0361 d += (rng_->remainder_ != 0);
0362 return d;
0363 }
0364 };
0365
0366 constexpr outer_cursor begin_cursor() noexcept
0367 {
0368 it_cache_ = ranges::begin(base_);
0369 return outer_cursor{this};
0370 }
0371 template<typename Size>
0372 constexpr Size size_(Size base_size) const
0373 {
0374 auto const n = static_cast<Size>(this->n_);
0375 return base_size / n + (0 != base_size % n);
0376 }
0377
0378 public:
0379 chunk_view_() = default;
0380 constexpr chunk_view_(Rng rng, range_difference_t<Rng> n)
0381 : base_(detail::move(rng))
0382 , n_((RANGES_EXPECT(0 < n), n))
0383 , remainder_(n)
0384 , it_cache_{nullopt}
0385 {}
0386 CPP_auto_member
0387 constexpr auto CPP_fun(size)()(const
0388 requires sized_range<Rng const>)
0389 {
0390 return size_(ranges::size(base_));
0391 }
0392 CPP_auto_member
0393 constexpr auto CPP_fun(size)()(
0394 requires sized_range<Rng>)
0395 {
0396 return size_(ranges::size(base_));
0397 }
0398 Rng base() const
0399 {
0400 return base_;
0401 }
0402 };
0403
0404 template<typename Rng>
0405 struct chunk_view : chunk_view_<Rng, (bool)forward_range<Rng>>
0406 {
0407 chunk_view() = default;
0408 constexpr chunk_view(Rng rng, range_difference_t<Rng> n)
0409 : chunk_view_<Rng, (bool)forward_range<Rng>>(static_cast<Rng &&>(rng), n)
0410 {}
0411 };
0412
0413
0414 template<typename Rng>
0415 RANGES_INLINE_VAR constexpr bool enable_borrowed_range<chunk_view<Rng>> =
0416 enable_borrowed_range<Rng> && forward_range<Rng>;
0417
0418 #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
0419 template<typename Rng>
0420 chunk_view(Rng &&, range_difference_t<Rng>)
0421 -> chunk_view<views::all_t<Rng>>;
0422 #endif
0423
0424 namespace views
0425 {
0426
0427
0428
0429 struct chunk_base_fn
0430 {
0431 template(typename Rng)(
0432 requires viewable_range<Rng> AND input_range<Rng>)
0433 constexpr chunk_view<all_t<Rng>>
0434 operator()(Rng && rng, range_difference_t<Rng> n) const
0435 {
0436 return {all(static_cast<Rng &&>(rng)), n};
0437 }
0438 };
0439
0440 struct chunk_fn : chunk_base_fn
0441 {
0442 using chunk_base_fn::operator();
0443
0444 template(typename Int)(
0445 requires detail::integer_like_<Int>)
0446 constexpr auto operator()(Int n) const
0447 {
0448 return make_view_closure(bind_back(chunk_base_fn{}, n));
0449 }
0450 };
0451
0452
0453
0454 RANGES_INLINE_VARIABLE(chunk_fn, chunk)
0455 }
0456
0457 }
0458
0459 #include <range/v3/detail/epilogue.hpp>
0460 #include <range/v3/detail/satisfy_boost_range.hpp>
0461 RANGES_SATISFY_BOOST_RANGE(::ranges::chunk_view)
0462
0463 #endif