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.

cycle.hpp 7.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. /// \file cycle.hpp
  2. // Range v3 library
  3. //
  4. // Copyright Eric Niebler 2013-present
  5. // Copyright Gonzalo Brito Gadeschi 2015
  6. // Copyright Casey Carter 2015
  7. //
  8. // Use, modification and distribution is subject to the
  9. // Boost Software License, Version 1.0. (See accompanying
  10. // file LICENSE_1_0.txt or copy at
  11. // http://www.boost.org/LICENSE_1_0.txt)
  12. //
  13. // Project home: https://github.com/ericniebler/range-v3
  14. //
  15. #ifndef RANGES_V3_VIEW_CYCLE_HPP
  16. #define RANGES_V3_VIEW_CYCLE_HPP
  17. #include <type_traits>
  18. #include <utility>
  19. #include <meta/meta.hpp>
  20. #include <range/v3/range_fwd.hpp>
  21. #include <range/v3/iterator/operations.hpp>
  22. #include <range/v3/iterator/unreachable_sentinel.hpp>
  23. #include <range/v3/range/access.hpp>
  24. #include <range/v3/range/concepts.hpp>
  25. #include <range/v3/range/primitives.hpp>
  26. #include <range/v3/range/traits.hpp>
  27. #include <range/v3/utility/box.hpp>
  28. #include <range/v3/utility/get.hpp>
  29. #include <range/v3/utility/optional.hpp>
  30. #include <range/v3/utility/static_const.hpp>
  31. #include <range/v3/view/all.hpp>
  32. #include <range/v3/view/facade.hpp>
  33. #include <range/v3/view/view.hpp>
  34. namespace ranges
  35. {
  36. /// \addtogroup group-views
  37. ///@{
  38. template<typename Rng, bool /* = (bool) is_infinite<Rng>() */>
  39. struct RANGES_EMPTY_BASES cycled_view
  40. : view_facade<cycled_view<Rng>, infinite>
  41. , private detail::non_propagating_cache<iterator_t<Rng>, cycled_view<Rng>,
  42. !common_range<Rng>>
  43. {
  44. private:
  45. CPP_assert(forward_range<Rng> && !is_infinite<Rng>::value);
  46. friend range_access;
  47. Rng rng_;
  48. using cache_t = detail::non_propagating_cache<iterator_t<Rng>, cycled_view<Rng>,
  49. !common_range<Rng>>;
  50. template<bool IsConst>
  51. struct cursor
  52. {
  53. private:
  54. friend struct cursor<!IsConst>;
  55. template<typename T>
  56. using constify_if = meta::const_if_c<IsConst, T>;
  57. using cycled_view_t = constify_if<cycled_view>;
  58. using CRng = constify_if<Rng>;
  59. using iterator = iterator_t<CRng>;
  60. cycled_view_t * rng_{};
  61. iterator it_{};
  62. std::intmax_t n_ = 0;
  63. iterator get_end_(std::true_type, bool = false) const
  64. {
  65. return ranges::end(rng_->rng_);
  66. }
  67. template<bool CanBeEmpty = false>
  68. iterator get_end_(std::false_type, meta::bool_<CanBeEmpty> = {}) const
  69. {
  70. auto & end_ = static_cast<cache_t &>(*rng_);
  71. RANGES_EXPECT(CanBeEmpty || end_);
  72. if(CanBeEmpty && !end_)
  73. end_ = ranges::next(it_, ranges::end(rng_->rng_));
  74. return *end_;
  75. }
  76. void set_end_(std::true_type) const
  77. {}
  78. void set_end_(std::false_type) const
  79. {
  80. auto & end_ = static_cast<cache_t &>(*rng_);
  81. if(!end_)
  82. end_ = it_;
  83. }
  84. public:
  85. cursor() = default;
  86. cursor(cycled_view_t * rng)
  87. : rng_(rng)
  88. , it_(ranges::begin(rng->rng_))
  89. {}
  90. CPP_template(bool Other)( //
  91. requires IsConst && (!Other)) cursor(cursor<Other> that)
  92. : rng_(that.rng_)
  93. , it_(std::move(that.it_))
  94. {}
  95. // clang-format off
  96. auto CPP_auto_fun(read)()(const)
  97. (
  98. return *it_
  99. )
  100. // clang-format on
  101. CPP_member
  102. auto equal(cursor const & pos) const -> CPP_ret(bool)( //
  103. requires equality_comparable<iterator>)
  104. {
  105. RANGES_EXPECT(rng_ == pos.rng_);
  106. return n_ == pos.n_ && it_ == pos.it_;
  107. }
  108. void next()
  109. {
  110. auto const last = ranges::end(rng_->rng_);
  111. RANGES_EXPECT(it_ != last);
  112. if(++it_ == last)
  113. {
  114. ++n_;
  115. this->set_end_(meta::bool_<(bool)common_range<CRng>>{});
  116. it_ = ranges::begin(rng_->rng_);
  117. }
  118. }
  119. CPP_member
  120. auto prev() -> CPP_ret(void)( //
  121. requires bidirectional_range<CRng>)
  122. {
  123. if(it_ == ranges::begin(rng_->rng_))
  124. {
  125. RANGES_EXPECT(n_ > 0); // decrementing the begin iterator?!
  126. --n_;
  127. it_ = this->get_end_(meta::bool_<(bool)common_range<CRng>>{});
  128. }
  129. --it_;
  130. }
  131. CPP_template(typename Diff)( //
  132. requires random_access_range<CRng> &&
  133. detail::integer_like_<Diff>) void advance(Diff n)
  134. {
  135. auto const first = ranges::begin(rng_->rng_);
  136. auto const last = this->get_end_(meta::bool_<(bool)common_range<CRng>>{},
  137. meta::bool_<true>());
  138. auto const dist = last - first;
  139. auto const d = it_ - first;
  140. auto const off = (d + n) % dist;
  141. n_ += (d + n) / dist;
  142. RANGES_EXPECT(n_ >= 0);
  143. using D = range_difference_t<Rng>;
  144. it_ = first + static_cast<D>(off < 0 ? off + dist : off);
  145. }
  146. CPP_member
  147. auto CPP_fun(distance_to)(cursor const & that)(
  148. const requires sized_sentinel_for<iterator, iterator>)
  149. {
  150. RANGES_EXPECT(that.rng_ == rng_);
  151. auto const first = ranges::begin(rng_->rng_);
  152. auto const last = this->get_end_(meta::bool_<(bool)common_range<Rng>>{},
  153. meta::bool_<true>());
  154. auto const dist = last - first;
  155. return (that.n_ - n_) * dist + (that.it_ - it_);
  156. }
  157. };
  158. CPP_member
  159. auto begin_cursor() -> CPP_ret(cursor<false>)( //
  160. requires(!simple_view<Rng>() || !common_range<Rng const>))
  161. {
  162. return {this};
  163. }
  164. CPP_member
  165. auto begin_cursor() const -> CPP_ret(cursor<true>)( //
  166. requires common_range<Rng const>)
  167. {
  168. return {this};
  169. }
  170. unreachable_sentinel_t end_cursor() const
  171. {
  172. return unreachable;
  173. }
  174. public:
  175. cycled_view() = default;
  176. /// \pre <tt>!empty(rng)</tt>
  177. explicit cycled_view(Rng rng)
  178. : rng_(std::move(rng))
  179. {
  180. RANGES_EXPECT(!ranges::empty(rng_));
  181. }
  182. };
  183. template<typename Rng>
  184. struct cycled_view<Rng, true> : identity_adaptor<Rng>
  185. {
  186. CPP_assert(is_infinite<Rng>::value);
  187. using identity_adaptor<Rng>::identity_adaptor;
  188. };
  189. #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
  190. template<typename Rng>
  191. cycled_view(Rng &&)->cycled_view<views::all_t<Rng>>;
  192. #endif
  193. namespace views
  194. {
  195. /// Returns an infinite range that endlessly repeats the source
  196. /// range.
  197. struct cycle_fn
  198. {
  199. /// \pre <tt>!empty(rng)</tt>
  200. template<typename Rng>
  201. auto operator()(Rng && rng) const -> CPP_ret(cycled_view<all_t<Rng>>)( //
  202. requires viewable_range<Rng> && forward_range<Rng>)
  203. {
  204. return cycled_view<all_t<Rng>>{all(static_cast<Rng &&>(rng))};
  205. }
  206. };
  207. /// \relates cycle_fn
  208. /// \ingroup group-views
  209. RANGES_INLINE_VARIABLE(view<cycle_fn>, cycle)
  210. } // namespace views
  211. /// @}
  212. } // namespace ranges
  213. #include <range/v3/detail/satisfy_boost_range.hpp>
  214. RANGES_SATISFY_BOOST_RANGE(::ranges::cycled_view)
  215. #endif