Horizon
split_when.hpp
Go to the documentation of this file.
1 // 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 
14 #ifndef RANGES_V3_VIEW_SPLIT_WHEN_HPP
15 #define RANGES_V3_VIEW_SPLIT_WHEN_HPP
16 
17 #include <type_traits>
18 #include <utility>
19 
20 #include <meta/meta.hpp>
21 
22 #include <range/v3/range_fwd.hpp>
23 
32 #include <range/v3/utility/static_const.hpp>
33 #include <range/v3/view/all.hpp>
34 #include <range/v3/view/facade.hpp>
36 #include <range/v3/view/iota.hpp>
38 #include <range/v3/view/view.hpp>
39 
40 #include <range/v3/detail/prologue.hpp>
41 
42 namespace ranges
43 {
46 
47  template<typename Rng, typename Fun>
49  : view_facade<split_when_view<Rng, Fun>,
50  is_finite<Rng>::value ? finite : range_cardinality<Rng>::value>
51  {
52  private:
53  friend range_access;
54  Rng rng_;
55  semiregular_box_t<Fun> fun_;
56 
57  template<bool IsConst>
58  struct cursor
59  {
60  private:
61  friend range_access;
62  friend split_when_view;
63  friend struct cursor<!IsConst>;
64  bool zero_;
65  using CRng = meta::const_if_c<IsConst, Rng>;
66  iterator_t<CRng> cur_;
67  sentinel_t<CRng> last_;
68  using fun_ref_t = semiregular_box_ref_or_val_t<Fun, IsConst>;
69  fun_ref_t fun_;
70 
71  struct search_pred
72  {
73  bool zero_;
74  iterator_t<CRng> first_;
75  sentinel_t<CRng> last_;
76  fun_ref_t fun_;
77  bool operator()(iterator_t<CRng> cur) const
78  {
79  return (zero_ && cur == first_) ||
80  (cur != last_ && !invoke(fun_, cur, last_).first);
81  }
82  };
83  using reference_ =
85  reference_ read() const
86  {
87  return reference_{{views::iota(cur_), {zero_, cur_, last_, fun_}}};
88  }
89  void next()
90  {
91  RANGES_EXPECT(cur_ != last_);
92  // If the last match consumed zero elements, bump the position.
93  if(zero_)
94  {
95  zero_ = false;
96  ++cur_;
97  }
98  for(; cur_ != last_; ++cur_)
99  {
100  auto p = invoke(fun_, cur_, last_);
101  if(p.first)
102  {
103  zero_ = (cur_ == p.second);
104  cur_ = p.second;
105  return;
106  }
107  }
108  }
109  bool equal(default_sentinel_t) const
110  {
111  return cur_ == last_;
112  }
113  bool equal(cursor const & that) const
114  {
115  return cur_ == that.cur_;
116  }
117  cursor(fun_ref_t fun, iterator_t<CRng> first, sentinel_t<CRng> last)
118  : cur_(first)
119  , last_(last)
120  , fun_(fun)
121  {
122  // For skipping an initial zero-length match
123  auto p = invoke(fun, first, last);
124  zero_ = p.first && first == p.second;
125  }
126 
127  public:
128  cursor() = default;
129  template(bool Other)(
130  requires IsConst AND CPP_NOT(Other)) //
131  cursor(cursor<Other> that)
132  : cursor{std::move(that.cur_), std::move(that.last_), std::move(that.fun_)}
133  {}
134  };
135  cursor<false> begin_cursor()
136  {
137  return {fun_, ranges::begin(rng_), ranges::end(rng_)};
138  }
139  template(bool Const = true)(
140  requires Const AND range<meta::const_if_c<Const, Rng>> AND
141  invocable<Fun const &, iterator_t<meta::const_if_c<Const, Rng>>,
142  sentinel_t<meta::const_if_c<Const, Rng>>>)
143  cursor<Const> begin_cursor() const
144  {
145  return {fun_, ranges::begin(rng_), ranges::end(rng_)};
146  }
147 
148  public:
149  split_when_view() = default;
150  split_when_view(Rng rng, Fun fun)
151  : rng_(std::move(rng))
152  , fun_(std::move(fun))
153  {}
154  };
155 
156 #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
157  template(typename Rng, typename Fun)(
158  requires copy_constructible<Fun>)
159  split_when_view(Rng &&, Fun)
161 #endif
162 
163  namespace views
164  {
166  {
167  private:
168  template<typename Pred>
169  struct predicate_pred_
170  {
171  semiregular_box_t<Pred> pred_;
172 
173  template(typename I, typename S)(
174  requires sentinel_for<S, I>)
175  std::pair<bool, I> operator()(I cur, S last) const
176  {
177  auto where = ranges::find_if_not(cur, last, std::ref(pred_));
178  return {cur != where, where};
179  }
180  };
181 
182  public:
183  template(typename Rng, typename Fun)(
184  requires viewable_range<Rng> AND forward_range<Rng> AND
185  invocable<Fun &, iterator_t<Rng>, sentinel_t<Rng>> AND
187  copy_constructible<Fun> AND
188  convertible_to<
189  invoke_result_t<Fun &, iterator_t<Rng>, sentinel_t<Rng>>,
190  std::pair<bool, iterator_t<Rng>>>)
191  split_when_view<all_t<Rng>, Fun> operator()(Rng && rng, Fun fun) const //
192  {
193  return {all(static_cast<Rng &&>(rng)), std::move(fun)};
194  }
195  template(typename Rng, typename Fun)(
196  requires viewable_range<Rng> AND forward_range<Rng> AND
197  predicate<Fun const &, range_reference_t<Rng>> AND
198  copy_constructible<Fun>)
199  split_when_view<all_t<Rng>, predicate_pred_<Fun>> //
200  operator()(Rng && rng, Fun fun) const
201  {
202  return {all(static_cast<Rng &&>(rng)),
203  predicate_pred_<Fun>{std::move(fun)}};
204  }
205  };
206 
208  {
209  using split_when_base_fn::operator();
210 
211  template<typename T>
212  constexpr auto operator()(T && t) const
213  {
214  return make_view_closure(
215  bind_back(split_when_base_fn{}, static_cast<T &&>(t)));
216  }
217  };
218 
222  } // namespace views
224 } // namespace ranges
225 
226 #include <range/v3/detail/epilogue.hpp>
227 #include <range/v3/detail/satisfy_boost_range.hpp>
228 RANGES_SATISFY_BOOST_RANGE(::ranges::split_when_view)
229 
230 #endif
CPP_concept invocable
\concept invocable
Definition: concepts.hpp:48
CPP_concept predicate
\concept predicate
Definition: concepts.hpp:73
CPP_concept range
\concept range
Definition: concepts.hpp:69
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
typename Fn::template invoke< Args... > invoke
Evaluate the invocable Fn with the arguments Args.
Definition: meta.hpp:541
defer< bind_back, Fn, Ts... > bind_back
Definition: meta.hpp:994
front< Pair > first
Retrieve the first element of the pair Pair.
Definition: meta.hpp:2251
list< F, S > pair
A list with exactly two elements.
Definition: meta.hpp:2246
Tiny meta-programming library.
Definition: default_sentinel.hpp:26
Definition: indirect.hpp:40
Definition: split_when.hpp:51
A utility for constructing a view from a (derived) type that implements begin and end cursors.
Definition: facade.hpp:66
Definition: split_when.hpp:166
Definition: split_when.hpp:208