stride.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. /// \file
  2. // Range v3 library
  3. //
  4. // Copyright Eric Niebler 2013-present
  5. // Copyright Casey Carter 2017
  6. //
  7. // Use, modification and distribution is subject to the
  8. // Boost Software License, Version 1.0. (See accompanying
  9. // file LICENSE_1_0.txt or copy at
  10. // http://www.boost.org/LICENSE_1_0.txt)
  11. //
  12. // Project home: https://github.com/ericniebler/range-v3
  13. //
  14. #ifndef RANGES_V3_VIEW_STRIDE_HPP
  15. #define RANGES_V3_VIEW_STRIDE_HPP
  16. #include <type_traits>
  17. #include <utility>
  18. #include <meta/meta.hpp>
  19. #include <range/v3/range_fwd.hpp>
  20. #include <range/v3/functional/bind_back.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/primitives.hpp>
  25. #include <range/v3/range/traits.hpp>
  26. #include <range/v3/utility/static_const.hpp>
  27. #include <range/v3/view/adaptor.hpp>
  28. #include <range/v3/view/all.hpp>
  29. #include <range/v3/view/view.hpp>
  30. #include <range/v3/detail/prologue.hpp>
  31. namespace ranges
  32. {
  33. /// \cond
  34. template<typename Rng>
  35. struct stride_view;
  36. namespace detail
  37. {
  38. template<typename Rng>
  39. using stride_view_adaptor =
  40. view_adaptor<stride_view<Rng>, Rng,
  41. is_finite<Rng>::value ? finite : range_cardinality<Rng>::value>;
  42. // Bidirectional stride views need to remember the distance between
  43. // the penultimate iterator and the last iterator - which may be less
  44. // than the stride - so that decrementing an last iterator properly
  45. // produces the penultimate iterator. stride_view_base specializes on
  46. // that distinction so that only Bidirectional stride views have the
  47. // data member "offset_".
  48. template<typename Rng, bool BidiRange>
  49. struct stride_view_base_;
  50. template<typename Rng>
  51. using stride_view_base = stride_view_base_<Rng, (bool)bidirectional_range<Rng>>;
  52. template<typename Rng, bool /*= bidirectional_range<Rng>*/>
  53. struct stride_view_base_ : stride_view_adaptor<Rng>
  54. {
  55. stride_view_base_() = default;
  56. constexpr stride_view_base_(Rng && rng, range_difference_t<Rng> const stride)
  57. : stride_view_adaptor<Rng>{std::move(rng)}
  58. , stride_{(RANGES_EXPECT(0 < stride), stride)}
  59. , offset_{calc_offset(meta::bool_<sized_range<Rng>>{})}
  60. {}
  61. protected:
  62. constexpr void set_offset(range_difference_t<Rng> const delta) noexcept
  63. {
  64. RANGES_EXPECT(0 <= delta && delta < stride_);
  65. if(0 > offset_)
  66. offset_ = delta;
  67. else
  68. RANGES_EXPECT(offset_ == delta);
  69. }
  70. constexpr void set_offset(range_difference_t<Rng> const) const noexcept
  71. {}
  72. constexpr range_difference_t<Rng> get_offset(bool check = true) const noexcept
  73. {
  74. RANGES_EXPECT(!check || 0 <= offset_);
  75. return offset_;
  76. }
  77. range_difference_t<Rng> stride_;
  78. range_difference_t<Rng> offset_ = -1;
  79. private:
  80. constexpr range_difference_t<Rng> calc_offset(std::true_type)
  81. {
  82. if(auto const rem = ranges::distance(this->base()) % stride_)
  83. return stride_ - rem;
  84. else
  85. return 0;
  86. }
  87. constexpr range_difference_t<Rng> calc_offset(std::false_type) const noexcept
  88. {
  89. return -1;
  90. }
  91. };
  92. template<typename Rng>
  93. struct stride_view_base_<Rng, false> : stride_view_adaptor<Rng>
  94. {
  95. stride_view_base_() = default;
  96. constexpr stride_view_base_(Rng && rng, range_difference_t<Rng> const stride)
  97. : stride_view_adaptor<Rng>{std::move(rng)}
  98. , stride_{(RANGES_EXPECT(0 < stride), stride)}
  99. {}
  100. protected:
  101. constexpr void set_offset(range_difference_t<Rng> const) const noexcept
  102. {}
  103. constexpr range_difference_t<Rng> get_offset(bool = true) const noexcept
  104. {
  105. return 0;
  106. }
  107. range_difference_t<Rng> stride_;
  108. };
  109. } // namespace detail
  110. /// \endcond
  111. /// \addtogroup group-views
  112. /// @{
  113. template<typename Rng>
  114. struct stride_view : detail::stride_view_base<Rng>
  115. {
  116. private:
  117. friend range_access;
  118. // stride_view const models Range if Rng const models Range, and
  119. // either (1) Rng is sized, so we can pre-calculate offset_, or (2)
  120. // Rng is !Bidirectional, so it does not need offset_.
  121. static constexpr bool const_iterable() noexcept
  122. {
  123. return range<Rng const> &&
  124. (sized_range<Rng const> || !bidirectional_range<Rng const>);
  125. }
  126. // If the underlying range doesn't model common_range, then we can't
  127. // decrement the last and there's no reason to adapt the sentinel. Strictly
  128. // speaking, we don't have to adapt the last iterator of input and forward
  129. // ranges, but in the interests of making the resulting stride view model
  130. // common_range, adapt it anyway.
  131. template<bool Const>
  132. static constexpr bool can_bound() noexcept
  133. {
  134. using CRng = meta::const_if_c<Const, Rng>;
  135. return common_range<CRng> &&
  136. (sized_range<CRng> || !bidirectional_range<CRng>);
  137. }
  138. template<bool Const>
  139. struct adaptor : adaptor_base
  140. {
  141. private:
  142. friend struct adaptor<!Const>;
  143. using CRng = meta::const_if_c<Const, Rng>;
  144. using stride_view_t = meta::const_if_c<Const, stride_view>;
  145. stride_view_t * rng_;
  146. public:
  147. adaptor() = default;
  148. constexpr adaptor(stride_view_t * rng) noexcept
  149. : rng_(rng)
  150. {}
  151. template(bool Other)(
  152. requires Const AND CPP_NOT(Other)) //
  153. adaptor(adaptor<Other> that)
  154. : rng_(that.rng_)
  155. {}
  156. constexpr void next(iterator_t<CRng> & it)
  157. {
  158. auto const last = ranges::end(rng_->base());
  159. RANGES_EXPECT(it != last);
  160. auto const delta = ranges::advance(it, rng_->stride_, last);
  161. if(it == last)
  162. {
  163. rng_->set_offset(delta);
  164. }
  165. }
  166. CPP_member
  167. constexpr auto prev(iterator_t<CRng> & it) //
  168. -> CPP_ret(void)(
  169. requires bidirectional_range<CRng>)
  170. {
  171. RANGES_EXPECT(it != ranges::begin(rng_->base()));
  172. auto delta = -rng_->stride_;
  173. if(it == ranges::end(rng_->base()))
  174. {
  175. RANGES_EXPECT(rng_->get_offset() >= 0);
  176. delta += rng_->get_offset();
  177. }
  178. ranges::advance(it, delta);
  179. }
  180. template(typename Other)(
  181. requires sized_sentinel_for<Other, iterator_t<CRng>>)
  182. constexpr range_difference_t<Rng> distance_to(iterator_t<CRng> const & here,
  183. Other const & there) const
  184. {
  185. range_difference_t<Rng> delta = there - here;
  186. if(delta < 0)
  187. delta -= rng_->stride_ - 1;
  188. else
  189. delta += rng_->stride_ - 1;
  190. return delta / rng_->stride_;
  191. }
  192. CPP_member
  193. constexpr auto advance(iterator_t<CRng> & it, range_difference_t<Rng> n) //
  194. -> CPP_ret(void)(
  195. requires random_access_range<CRng>)
  196. {
  197. if(0 == n)
  198. return;
  199. n *= rng_->stride_;
  200. auto const last = ranges::end(rng_->base());
  201. if(it == last)
  202. {
  203. RANGES_EXPECT(n < 0);
  204. RANGES_EXPECT(rng_->get_offset() >= 0);
  205. n += rng_->get_offset();
  206. }
  207. if(0 < n)
  208. {
  209. auto delta = ranges::advance(it, n, last);
  210. if(it == last)
  211. {
  212. // advance hit the last of the base range.
  213. rng_->set_offset(delta % rng_->stride_);
  214. }
  215. }
  216. else if(0 > n)
  217. {
  218. #ifdef NDEBUG
  219. ranges::advance(it, n);
  220. #else
  221. auto const first = ranges::begin(rng_->base());
  222. auto const delta = ranges::advance(it, n, first);
  223. RANGES_EXPECT(delta == 0);
  224. #endif
  225. }
  226. }
  227. };
  228. constexpr adaptor<false> begin_adaptor() noexcept
  229. {
  230. return adaptor<false>{this};
  231. }
  232. CPP_member
  233. constexpr auto begin_adaptor() const noexcept
  234. -> CPP_ret(adaptor<true>)(
  235. requires(const_iterable()))
  236. {
  237. return adaptor<true>{this};
  238. }
  239. constexpr meta::if_c<can_bound<false>(), adaptor<false>, adaptor_base> //
  240. end_adaptor() noexcept
  241. {
  242. return {this};
  243. }
  244. CPP_member
  245. constexpr auto end_adaptor() const noexcept //
  246. -> CPP_ret(meta::if_c<can_bound<true>(), adaptor<true>, adaptor_base>)(
  247. requires (const_iterable()))
  248. {
  249. return {this};
  250. }
  251. public:
  252. stride_view() = default;
  253. constexpr stride_view(Rng rng, range_difference_t<Rng> const stride)
  254. : detail::stride_view_base<Rng>{std::move(rng), stride}
  255. {}
  256. CPP_auto_member
  257. constexpr auto CPP_fun(size)()(
  258. requires sized_range<Rng>)
  259. {
  260. using size_type = range_size_t<Rng>;
  261. auto const n = ranges::size(this->base());
  262. return (n + static_cast<size_type>(this->stride_) - 1) /
  263. static_cast<size_type>(this->stride_);
  264. }
  265. CPP_auto_member
  266. constexpr auto CPP_fun(size)()(const //
  267. requires sized_range<Rng const>)
  268. {
  269. using size_type = range_size_t<Rng const>;
  270. auto const n = ranges::size(this->base());
  271. return (n + static_cast<size_type>(this->stride_) - 1) /
  272. static_cast<size_type>(this->stride_);
  273. }
  274. };
  275. #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
  276. template<typename Rng>
  277. stride_view(Rng &&, range_difference_t<Rng>)
  278. -> stride_view<views::all_t<Rng>>;
  279. #endif
  280. namespace views
  281. {
  282. struct stride_base_fn
  283. {
  284. template(typename Rng)(
  285. requires viewable_range<Rng> AND input_range<Rng>)
  286. constexpr stride_view<all_t<Rng>> //
  287. operator()(Rng && rng, range_difference_t<Rng> step) const
  288. {
  289. return stride_view<all_t<Rng>>{all(static_cast<Rng &&>(rng)), step};
  290. }
  291. };
  292. struct stride_fn : stride_base_fn
  293. {
  294. using stride_base_fn::operator();
  295. template(typename Difference)(
  296. requires detail::integer_like_<Difference>)
  297. constexpr auto operator()(Difference step) const
  298. {
  299. return make_view_closure(bind_back(stride_base_fn{}, step));
  300. }
  301. };
  302. /// \relates stride_fn
  303. /// \ingroup group-views
  304. RANGES_INLINE_VARIABLE(stride_fn, stride)
  305. } // namespace views
  306. /// @}
  307. } // namespace ranges
  308. #include <range/v3/detail/epilogue.hpp>
  309. #include <range/v3/detail/satisfy_boost_range.hpp>
  310. RANGES_SATISFY_BOOST_RANGE(::ranges::stride_view)
  311. #endif