Horizon
cycle.hpp
Go to the documentation of this file.
1 // 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 
16 #ifndef RANGES_V3_VIEW_CYCLE_HPP
17 #define RANGES_V3_VIEW_CYCLE_HPP
18 
19 #include <type_traits>
20 #include <utility>
21 
22 #include <meta/meta.hpp>
23 
24 #include <range/v3/range_fwd.hpp>
25 
32 #include <range/v3/utility/box.hpp>
33 #include <range/v3/utility/get.hpp>
35 #include <range/v3/utility/static_const.hpp>
36 #include <range/v3/view/all.hpp>
37 #include <range/v3/view/facade.hpp>
38 #include <range/v3/view/view.hpp>
39 
40 #include <range/v3/detail/prologue.hpp>
41 
42 namespace ranges
43 {
46  template<typename Rng, bool /* = (bool) is_infinite<Rng>() */>
47  struct RANGES_EMPTY_BASES cycled_view
48  : view_facade<cycled_view<Rng>, infinite>
49  , private detail::non_propagating_cache<iterator_t<Rng>, cycled_view<Rng>,
50  !common_range<Rng>>
51  {
52  private:
53  CPP_assert(forward_range<Rng> && !is_infinite<Rng>::value);
54  friend range_access;
55  Rng rng_;
56 
57  using cache_t = detail::non_propagating_cache<iterator_t<Rng>, cycled_view<Rng>,
58  !common_range<Rng>>;
59 
60  template<bool IsConst>
61  struct cursor
62  {
63  private:
64  friend struct cursor<!IsConst>;
65  template<typename T>
66  using constify_if = meta::const_if_c<IsConst, T>;
67  using cycled_view_t = constify_if<cycled_view>;
68  using CRng = constify_if<Rng>;
69  using iterator = iterator_t<CRng>;
70 
71  cycled_view_t * rng_{};
72  iterator it_{};
73  std::intmax_t n_ = 0;
74 
75  iterator get_end_(std::true_type, bool = false) const
76  {
77  return ranges::end(rng_->rng_);
78  }
79  template<bool CanBeEmpty = false>
80  iterator get_end_(std::false_type, meta::bool_<CanBeEmpty> = {}) const
81  {
82  auto & end_ = static_cast<cache_t &>(*rng_);
83  RANGES_EXPECT(CanBeEmpty || end_);
84  if(CanBeEmpty && !end_)
85  end_ = ranges::next(it_, ranges::end(rng_->rng_));
86  return *end_;
87  }
88  void set_end_(std::true_type) const
89  {}
90  void set_end_(std::false_type) const
91  {
92  auto & end_ = static_cast<cache_t &>(*rng_);
93  if(!end_)
94  end_ = it_;
95  }
96 
97  public:
98  cursor() = default;
99  cursor(cycled_view_t * rng)
100  : rng_(rng)
101  , it_(ranges::begin(rng->rng_))
102  {}
103  template(bool Other)(
104  requires IsConst AND CPP_NOT(Other)) //
105  cursor(cursor<Other> that)
106  : rng_(that.rng_)
107  , it_(std::move(that.it_))
108  {}
109  // clang-format off
110  auto CPP_auto_fun(read)()(const)
111  (
112  return *it_
113  )
114  // clang-format on
115  CPP_member
116  auto equal(cursor const & pos) const //
117  -> CPP_ret(bool)(
118  requires equality_comparable<iterator>)
119  {
120  RANGES_EXPECT(rng_ == pos.rng_);
121  return n_ == pos.n_ && it_ == pos.it_;
122  }
123  void next()
124  {
125  auto const last = ranges::end(rng_->rng_);
126  RANGES_EXPECT(it_ != last);
127  if(++it_ == last)
128  {
129  ++n_;
130  this->set_end_(meta::bool_<(bool)common_range<CRng>>{});
131  it_ = ranges::begin(rng_->rng_);
132  }
133  }
134  CPP_member
135  auto prev() //
136  -> CPP_ret(void)(
137  requires bidirectional_range<CRng>)
138  {
139  if(it_ == ranges::begin(rng_->rng_))
140  {
141  RANGES_EXPECT(n_ > 0); // decrementing the begin iterator?!
142  --n_;
143  it_ = this->get_end_(meta::bool_<(bool)common_range<CRng>>{});
144  }
145  --it_;
146  }
147  template(typename Diff)(
148  requires random_access_range<CRng> AND
149  detail::integer_like_<Diff>)
150  void advance(Diff n)
151  {
152  auto const first = ranges::begin(rng_->rng_);
153  auto const last = this->get_end_(meta::bool_<(bool)common_range<CRng>>{},
155  auto const dist = last - first;
156  auto const d = it_ - first;
157  auto const off = (d + n) % dist;
158  n_ += (d + n) / dist;
159  RANGES_EXPECT(n_ >= 0);
160  using D = range_difference_t<Rng>;
161  it_ = first + static_cast<D>(off < 0 ? off + dist : off);
162  }
163  CPP_auto_member
164  auto CPP_fun(distance_to)(cursor const & that)(const //
165  requires sized_sentinel_for<iterator, iterator>)
166  {
167  RANGES_EXPECT(that.rng_ == rng_);
168  auto const first = ranges::begin(rng_->rng_);
169  auto const last = this->get_end_(meta::bool_<(bool)common_range<Rng>>{},
171  auto const dist = last - first;
172  return (that.n_ - n_) * dist + (that.it_ - it_);
173  }
174  };
175 
176  CPP_member
177  auto begin_cursor() //
178  -> CPP_ret(cursor<false>)(
179  requires (!simple_view<Rng>() || !common_range<Rng const>))
180  {
181  return {this};
182  }
183  CPP_member
184  auto begin_cursor() const //
185  -> CPP_ret(cursor<true>)(
186  requires common_range<Rng const>)
187  {
188  return {this};
189  }
190  unreachable_sentinel_t end_cursor() const
191  {
192  return unreachable;
193  }
194 
195  public:
196  cycled_view() = default;
198  explicit cycled_view(Rng rng)
199  : rng_(std::move(rng))
200  {
201  RANGES_EXPECT(!ranges::empty(rng_));
202  }
203  };
204 
205  template<typename Rng>
207  {
208  CPP_assert(is_infinite<Rng>::value);
210  };
211 
212 #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
213  template<typename Rng>
214  cycled_view(Rng &&) //
216 #endif
217 
218  namespace views
219  {
222  struct cycle_fn
223  {
225  template(typename Rng)(
226  requires viewable_range<Rng> AND forward_range<Rng>)
227  cycled_view<all_t<Rng>> operator()(Rng && rng) const
228  {
229  return cycled_view<all_t<Rng>>{all(static_cast<Rng &&>(rng))};
230  }
231  };
232 
235  RANGES_INLINE_VARIABLE(view_closure<cycle_fn>, cycle)
236  } // namespace views
238 } // namespace ranges
239 
240 #include <range/v3/detail/epilogue.hpp>
241 
242 #include <range/v3/detail/satisfy_boost_range.hpp>
243 RANGES_SATISFY_BOOST_RANGE(::ranges::cycled_view)
244 
245 #endif
decltype(begin(declval(Rng &))) iterator_t
Definition: access.hpp:698
RANGES_INLINE_VARIABLE(detail::to_container_fn< detail::from_range< std::vector >>, to_vector) template< template< typename... > class ContT > auto to(RANGES_HIDDEN_DETAIL(detail
For initializing a container of the specified type with the elements of an Range.
Definition: conversion.hpp:399
std::integral_constant< bool, B > bool_
An integral constant wrapper for bool.
Definition: meta.hpp:168
front< Pair > first
Retrieve the first element of the pair Pair.
Definition: meta.hpp:2251
bool_< 0==size< L >::type::value > empty
An Boolean integral constant wrapper around true if L is an empty type list; false,...
Definition: meta.hpp:2231
Tiny meta-programming library.
Definition: cycle.hpp:207
Definition: cycle.hpp:51
cycled_view(Rng rng)
Definition: cycle.hpp:198
Definition: all.hpp:96
Definition: unreachable_sentinel.hpp:27
A utility for constructing a view from a (derived) type that implements begin and end cursors.
Definition: facade.hpp:66
Returns an infinite range that endlessly repeats the source range.
Definition: cycle.hpp:223