You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

chunk.hpp 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. /// \file
  2. // Range v3 library
  3. //
  4. // Copyright Eric Niebler 2013-present
  5. //
  6. // Use, modification and distribution is subject to the
  7. // Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. //
  11. // Project home: https://github.com/ericniebler/range-v3
  12. //
  13. #ifndef RANGES_V3_VIEW_CHUNK_HPP
  14. #define RANGES_V3_VIEW_CHUNK_HPP
  15. #include <limits>
  16. #include <utility>
  17. #include <meta/meta.hpp>
  18. #include <range/v3/range_fwd.hpp>
  19. #include <range/v3/functional/bind_back.hpp>
  20. #include <range/v3/iterator/default_sentinel.hpp>
  21. #include <range/v3/iterator/operations.hpp>
  22. #include <range/v3/range/access.hpp>
  23. #include <range/v3/range/concepts.hpp>
  24. #include <range/v3/range/traits.hpp>
  25. #include <range/v3/utility/box.hpp>
  26. #include <range/v3/utility/optional.hpp> // for non_propagating_cache
  27. #include <range/v3/utility/static_const.hpp>
  28. #include <range/v3/view/adaptor.hpp>
  29. #include <range/v3/view/all.hpp>
  30. #include <range/v3/view/facade.hpp>
  31. #include <range/v3/view/take.hpp>
  32. #include <range/v3/view/view.hpp>
  33. namespace ranges
  34. {
  35. /// \cond
  36. namespace detail
  37. {
  38. template<typename Rng, bool Const>
  39. constexpr bool can_sized_sentinel_() noexcept
  40. {
  41. using I = iterator_t<meta::const_if_c<Const, Rng>>;
  42. return (bool)sized_sentinel_for<I, I>;
  43. }
  44. template<typename T>
  45. struct zero
  46. {
  47. zero() = default;
  48. constexpr explicit zero(T const &) noexcept
  49. {}
  50. constexpr zero & operator=(T const &) noexcept
  51. {
  52. return *this;
  53. }
  54. constexpr zero const & operator=(T const &) const noexcept
  55. {
  56. return *this;
  57. }
  58. constexpr operator T() const
  59. {
  60. return T(0);
  61. }
  62. constexpr T exchange(T const &) const
  63. {
  64. return T(0);
  65. }
  66. };
  67. } // namespace detail
  68. /// \endcond
  69. /// \addtogroup group-views
  70. /// @{
  71. template<typename Rng, bool IsForwardRange>
  72. struct chunk_view_
  73. : view_adaptor<chunk_view_<Rng, IsForwardRange>, Rng,
  74. is_finite<Rng>::value ? finite : range_cardinality<Rng>::value>
  75. {
  76. private:
  77. friend range_access;
  78. CPP_assert(forward_range<Rng>);
  79. template<bool Const>
  80. using offset_t =
  81. meta::if_c<bidirectional_range<meta::const_if_c<Const, Rng>> ||
  82. detail::can_sized_sentinel_<Rng, Const>(),
  83. range_difference_t<Rng>, detail::zero<range_difference_t<Rng>>>;
  84. range_difference_t<Rng> n_ = 0;
  85. template<bool Const>
  86. struct RANGES_EMPTY_BASES adaptor
  87. : adaptor_base
  88. , private box<offset_t<Const>>
  89. {
  90. private:
  91. friend adaptor<!Const>;
  92. using CRng = meta::const_if_c<Const, Rng>;
  93. range_difference_t<CRng> n_;
  94. sentinel_t<CRng> end_;
  95. constexpr offset_t<Const> const & offset() const
  96. {
  97. offset_t<Const> const & result = this->box<offset_t<Const>>::get();
  98. RANGES_EXPECT(0 <= result && result < n_);
  99. return result;
  100. }
  101. constexpr offset_t<Const> & offset()
  102. {
  103. return const_cast<offset_t<Const> &>(
  104. const_cast<adaptor const &>(*this).offset());
  105. }
  106. public:
  107. adaptor() = default;
  108. constexpr adaptor(meta::const_if_c<Const, chunk_view_> * cv)
  109. : box<offset_t<Const>>{0}
  110. , n_((RANGES_EXPECT(0 < cv->n_), cv->n_))
  111. , end_(ranges::end(cv->base()))
  112. {}
  113. CPP_template(bool Other)( //
  114. requires Const && (!Other)) constexpr adaptor(adaptor<Other> that)
  115. : box<offset_t<Const>>(that.offset())
  116. , n_(that.n_)
  117. , end_(that.end_)
  118. {}
  119. constexpr auto read(iterator_t<CRng> const & it) const
  120. -> decltype(views::take(make_subrange(it, end_), n_))
  121. {
  122. RANGES_EXPECT(it != end_);
  123. RANGES_EXPECT(0 == offset());
  124. return views::take(make_subrange(it, end_), n_);
  125. }
  126. constexpr void next(iterator_t<CRng> & it)
  127. {
  128. RANGES_EXPECT(it != end_);
  129. RANGES_EXPECT(0 == offset());
  130. offset() = ranges::advance(it, n_, end_);
  131. }
  132. CPP_member
  133. constexpr auto prev(iterator_t<CRng> & it) -> CPP_ret(void)( //
  134. requires bidirectional_range<CRng>)
  135. {
  136. ranges::advance(it, -n_ + offset());
  137. offset() = 0;
  138. }
  139. CPP_member
  140. constexpr auto distance_to(iterator_t<CRng> const & here,
  141. iterator_t<CRng> const & there,
  142. adaptor const & that) const
  143. -> CPP_ret(range_difference_t<Rng>)( //
  144. requires(detail::can_sized_sentinel_<Rng, Const>()))
  145. {
  146. auto const delta = (there - here) + (that.offset() - offset());
  147. // This can fail for cyclic base ranges when the chunk size does not
  148. // divide the cycle length. Such iterator pairs are NOT in the domain of
  149. // -.
  150. RANGES_ENSURE(0 == delta % n_);
  151. return delta / n_;
  152. }
  153. CPP_member
  154. constexpr auto advance(iterator_t<CRng> & it,
  155. range_difference_t<Rng> n) -> CPP_ret(void)( //
  156. requires random_access_range<CRng>)
  157. {
  158. using Limits = std::numeric_limits<range_difference_t<CRng>>;
  159. if(0 < n)
  160. {
  161. RANGES_EXPECT(0 == offset());
  162. RANGES_EXPECT(n <= Limits::max() / n_);
  163. auto const remainder = ranges::advance(it, n * n_, end_) % n_;
  164. RANGES_EXPECT(0 <= remainder && remainder < n_);
  165. offset() = remainder;
  166. }
  167. else if(0 > n)
  168. {
  169. RANGES_EXPECT(n >= Limits::min() / n_);
  170. ranges::advance(it, n * n_ + offset());
  171. offset() = 0;
  172. }
  173. }
  174. };
  175. constexpr adaptor<simple_view<Rng>()> begin_adaptor()
  176. {
  177. return adaptor<simple_view<Rng>()>{this};
  178. }
  179. CPP_member
  180. constexpr auto begin_adaptor() const -> CPP_ret(adaptor<true>)( //
  181. requires forward_range<Rng const>)
  182. {
  183. return adaptor<true>{this};
  184. }
  185. template<typename Size>
  186. constexpr Size size_(Size base_size) const
  187. {
  188. auto const n = static_cast<Size>(n_);
  189. return base_size / n + (0 != (base_size % n));
  190. }
  191. public:
  192. chunk_view_() = default;
  193. constexpr chunk_view_(Rng rng, range_difference_t<Rng> n)
  194. : chunk_view_::view_adaptor(detail::move(rng))
  195. , n_((RANGES_EXPECT(0 < n), n))
  196. {}
  197. CPP_member
  198. constexpr auto CPP_fun(size)()(const requires sized_range<Rng const>)
  199. {
  200. return size_(ranges::size(this->base()));
  201. }
  202. CPP_member
  203. constexpr auto CPP_fun(size)()(requires sized_range<Rng>)
  204. {
  205. return size_(ranges::size(this->base()));
  206. }
  207. };
  208. template<typename Rng>
  209. struct chunk_view_<Rng, false>
  210. : view_facade<chunk_view_<Rng, false>,
  211. is_finite<Rng>::value ? finite : range_cardinality<Rng>::value>
  212. {
  213. private:
  214. friend range_access;
  215. CPP_assert(input_range<Rng> && !forward_range<Rng>);
  216. using iter_cache_t = detail::non_propagating_cache<iterator_t<Rng>>;
  217. Rng base_;
  218. range_difference_t<Rng> n_;
  219. range_difference_t<Rng> remainder_;
  220. mutable iter_cache_t it_cache_;
  221. constexpr iterator_t<Rng> & it() noexcept
  222. {
  223. return *it_cache_;
  224. }
  225. constexpr iterator_t<Rng> const & it() const noexcept
  226. {
  227. return *it_cache_;
  228. }
  229. struct outer_cursor
  230. {
  231. private:
  232. struct inner_view : view_facade<inner_view, finite>
  233. {
  234. private:
  235. friend range_access;
  236. using value_type = range_value_t<Rng>;
  237. chunk_view_ * rng_ = nullptr;
  238. constexpr bool done() const noexcept
  239. {
  240. RANGES_EXPECT(rng_);
  241. return rng_->remainder_ == 0;
  242. }
  243. constexpr bool equal(default_sentinel_t) const noexcept
  244. {
  245. return done();
  246. }
  247. constexpr iter_reference_t<iterator_t<Rng>> read() const
  248. {
  249. RANGES_EXPECT(!done());
  250. return *rng_->it();
  251. }
  252. constexpr iter_rvalue_reference_t<iterator_t<Rng>> move() const
  253. {
  254. RANGES_EXPECT(!done());
  255. return ranges::iter_move(rng_->it());
  256. }
  257. constexpr void next()
  258. {
  259. RANGES_EXPECT(!done());
  260. ++rng_->it();
  261. --rng_->remainder_;
  262. if(rng_->remainder_ != 0 && rng_->it() == ranges::end(rng_->base_))
  263. rng_->remainder_ = 0;
  264. }
  265. CPP_member
  266. constexpr auto distance_to(default_sentinel_t) const
  267. -> CPP_ret(range_difference_t<Rng>)( //
  268. requires sized_sentinel_for<sentinel_t<Rng>, iterator_t<Rng>>)
  269. {
  270. RANGES_EXPECT(rng_);
  271. auto const d = ranges::end(rng_->base_) - rng_->it();
  272. return ranges::min(d, rng_->remainder_);
  273. }
  274. public:
  275. inner_view() = default;
  276. constexpr explicit inner_view(chunk_view_ & view) noexcept
  277. : rng_{&view}
  278. {}
  279. CPP_member
  280. constexpr auto CPP_fun(size)()(
  281. requires sized_sentinel_for<sentinel_t<Rng>, iterator_t<Rng>>)
  282. {
  283. using size_type = detail::iter_size_t<iterator_t<Rng>>;
  284. return static_cast<size_type>(distance_to(default_sentinel_t{}));
  285. }
  286. };
  287. chunk_view_ * rng_ = nullptr;
  288. public:
  289. using value_type = inner_view;
  290. outer_cursor() = default;
  291. constexpr explicit outer_cursor(chunk_view_ * view) noexcept
  292. : rng_{view}
  293. {}
  294. constexpr inner_view read() const
  295. {
  296. RANGES_EXPECT(!done());
  297. return inner_view{*rng_};
  298. }
  299. constexpr bool done() const
  300. {
  301. RANGES_EXPECT(rng_);
  302. return rng_->it() == ranges::end(rng_->base_) && rng_->remainder_ != 0;
  303. }
  304. constexpr bool equal(default_sentinel_t) const
  305. {
  306. return done();
  307. }
  308. constexpr void next()
  309. {
  310. RANGES_EXPECT(!done());
  311. ranges::advance(rng_->it(), rng_->remainder_, ranges::end(rng_->base_));
  312. rng_->remainder_ = rng_->n_;
  313. }
  314. CPP_member
  315. constexpr auto distance_to(default_sentinel_t) const
  316. -> CPP_ret(range_difference_t<Rng>)( //
  317. requires sized_sentinel_for<sentinel_t<Rng>, iterator_t<Rng>>)
  318. {
  319. RANGES_EXPECT(rng_);
  320. auto d = ranges::end(rng_->base_) - rng_->it();
  321. if(d < rng_->remainder_)
  322. return 1;
  323. d -= rng_->remainder_;
  324. d = (d + rng_->n_ - 1) / rng_->n_;
  325. d += (rng_->remainder_ != 0);
  326. return d;
  327. }
  328. };
  329. constexpr outer_cursor begin_cursor() noexcept
  330. {
  331. it_cache_ = ranges::begin(base_);
  332. return outer_cursor{this};
  333. }
  334. template<typename Size>
  335. constexpr Size size_(Size base_size) const
  336. {
  337. auto const n = static_cast<Size>(this->n_);
  338. return base_size / n + (0 != base_size % n);
  339. }
  340. public:
  341. chunk_view_() = default;
  342. constexpr chunk_view_(Rng rng, range_difference_t<Rng> n)
  343. : base_(detail::move(rng))
  344. , n_((RANGES_EXPECT(0 < n), n))
  345. , remainder_(n)
  346. , it_cache_{nullopt}
  347. {}
  348. CPP_member
  349. constexpr auto CPP_fun(size)()(const requires sized_range<Rng const>)
  350. {
  351. return size_(ranges::size(base_));
  352. }
  353. CPP_member
  354. constexpr auto CPP_fun(size)()(requires sized_range<Rng>)
  355. {
  356. return size_(ranges::size(base_));
  357. }
  358. Rng base() const
  359. {
  360. return base_;
  361. }
  362. };
  363. template<typename Rng>
  364. struct chunk_view : chunk_view_<Rng, (bool)forward_range<Rng>>
  365. {
  366. using chunk_view::chunk_view_::chunk_view_;
  367. };
  368. #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
  369. template<typename Rng>
  370. chunk_view(Rng &&, range_difference_t<Rng>)->chunk_view<views::all_t<Rng>>;
  371. #endif
  372. namespace views
  373. {
  374. // In: range<T>
  375. // Out: range<range<T>>, where each inner range has $n$ elements.
  376. // The last range may have fewer.
  377. struct chunk_fn
  378. {
  379. private:
  380. friend view_access;
  381. template<typename Int>
  382. static constexpr auto CPP_fun(bind)(chunk_fn chunk, Int n)( //
  383. requires integral<Int>)
  384. {
  385. return make_pipeable(bind_back(chunk, n));
  386. }
  387. public:
  388. template<typename Rng>
  389. constexpr auto operator()(Rng && rng, range_difference_t<Rng> n) const
  390. -> CPP_ret(chunk_view<all_t<Rng>>)( //
  391. requires viewable_range<Rng> && input_range<Rng>)
  392. {
  393. return {all(static_cast<Rng &&>(rng)), n};
  394. }
  395. };
  396. /// \relates chunk_fn
  397. /// \ingroup group-views
  398. RANGES_INLINE_VARIABLE(view<chunk_fn>, chunk)
  399. } // namespace views
  400. /// @}
  401. } // namespace ranges
  402. #include <range/v3/detail/satisfy_boost_range.hpp>
  403. RANGES_SATISFY_BOOST_RANGE(::ranges::chunk_view)
  404. #endif