Horizon
Loading...
Searching...
No Matches
split_when.hpp
Go to the documentation of this file.
1
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
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
23
32#include <range/v3/utility/static_const.hpp>
33#include <range/v3/view/all.hpp>
39
40#include <range/v3/detail/prologue.hpp>
41
42namespace 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>;
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)(
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)(
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
221 RANGES_INLINE_VARIABLE(split_when_fn, split_when)
222 } // namespace views
224} // namespace ranges
225
226#include <range/v3/detail/epilogue.hpp>
227#include <range/v3/detail/satisfy_boost_range.hpp>
228RANGES_SATISFY_BOOST_RANGE(::ranges::split_when_view)
229
230#endif
The forward_range concept.
The invocable concept.
The predicate concept.
The range concept.
The sentinel_for concept.
The viewable_range concept.
decltype(begin(declval(Rng &))) iterator_t
Definition access.hpp:698
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