File indexing completed on 2025-01-18 10:09:58
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef RANGES_V3_VIEW_SPLIT_WHEN_HPP
0015 #define RANGES_V3_VIEW_SPLIT_WHEN_HPP
0016
0017 #include <type_traits>
0018 #include <utility>
0019
0020 #include <meta/meta.hpp>
0021
0022 #include <range/v3/range_fwd.hpp>
0023
0024 #include <range/v3/algorithm/find_if_not.hpp>
0025 #include <range/v3/functional/bind_back.hpp>
0026 #include <range/v3/functional/invoke.hpp>
0027 #include <range/v3/iterator/default_sentinel.hpp>
0028 #include <range/v3/iterator/operations.hpp>
0029 #include <range/v3/range/access.hpp>
0030 #include <range/v3/range/concepts.hpp>
0031 #include <range/v3/range/traits.hpp>
0032 #include <range/v3/utility/static_const.hpp>
0033 #include <range/v3/view/all.hpp>
0034 #include <range/v3/view/facade.hpp>
0035 #include <range/v3/view/indirect.hpp>
0036 #include <range/v3/view/iota.hpp>
0037 #include <range/v3/view/take_while.hpp>
0038 #include <range/v3/view/view.hpp>
0039
0040 #include <range/v3/detail/prologue.hpp>
0041
0042 namespace ranges
0043 {
0044
0045
0046
0047 template<typename Rng, typename Fun>
0048 struct split_when_view
0049 : view_facade<split_when_view<Rng, Fun>,
0050 is_finite<Rng>::value ? finite : range_cardinality<Rng>::value>
0051 {
0052 private:
0053 friend range_access;
0054 Rng rng_;
0055 semiregular_box_t<Fun> fun_;
0056
0057 template<bool IsConst>
0058 struct cursor
0059 {
0060 private:
0061 friend range_access;
0062 friend split_when_view;
0063 friend struct cursor<!IsConst>;
0064 bool zero_;
0065 using CRng = meta::const_if_c<IsConst, Rng>;
0066 iterator_t<CRng> cur_;
0067 sentinel_t<CRng> last_;
0068 using fun_ref_t = semiregular_box_ref_or_val_t<Fun, IsConst>;
0069 fun_ref_t fun_;
0070
0071 struct search_pred
0072 {
0073 bool zero_;
0074 iterator_t<CRng> first_;
0075 sentinel_t<CRng> last_;
0076 fun_ref_t fun_;
0077 bool operator()(iterator_t<CRng> cur) const
0078 {
0079 return (zero_ && cur == first_) ||
0080 (cur != last_ && !invoke(fun_, cur, last_).first);
0081 }
0082 };
0083 using reference_ =
0084 indirect_view<take_while_view<iota_view<iterator_t<CRng>>, search_pred>>;
0085 reference_ read() const
0086 {
0087 return reference_{{views::iota(cur_), {zero_, cur_, last_, fun_}}};
0088 }
0089 void next()
0090 {
0091 RANGES_EXPECT(cur_ != last_);
0092
0093 if(zero_)
0094 {
0095 zero_ = false;
0096 ++cur_;
0097 }
0098 for(; cur_ != last_; ++cur_)
0099 {
0100 auto p = invoke(fun_, cur_, last_);
0101 if(p.first)
0102 {
0103 zero_ = (cur_ == p.second);
0104 cur_ = p.second;
0105 return;
0106 }
0107 }
0108 }
0109 bool equal(default_sentinel_t) const
0110 {
0111 return cur_ == last_;
0112 }
0113 bool equal(cursor const & that) const
0114 {
0115 return cur_ == that.cur_;
0116 }
0117 cursor(fun_ref_t fun, iterator_t<CRng> first, sentinel_t<CRng> last)
0118 : cur_(first)
0119 , last_(last)
0120 , fun_(fun)
0121 {
0122
0123 auto p = invoke(fun, first, last);
0124 zero_ = p.first && first == p.second;
0125 }
0126
0127 public:
0128 cursor() = default;
0129 template(bool Other)(
0130 requires IsConst AND CPP_NOT(Other))
0131 cursor(cursor<Other> that)
0132 : cursor{std::move(that.cur_), std::move(that.last_), std::move(that.fun_)}
0133 {}
0134 };
0135 cursor<false> begin_cursor()
0136 {
0137 return {fun_, ranges::begin(rng_), ranges::end(rng_)};
0138 }
0139 template(bool Const = true)(
0140 requires Const AND range<meta::const_if_c<Const, Rng>> AND
0141 invocable<Fun const &, iterator_t<meta::const_if_c<Const, Rng>>,
0142 sentinel_t<meta::const_if_c<Const, Rng>>>)
0143 cursor<Const> begin_cursor() const
0144 {
0145 return {fun_, ranges::begin(rng_), ranges::end(rng_)};
0146 }
0147
0148 public:
0149 split_when_view() = default;
0150 split_when_view(Rng rng, Fun fun)
0151 : rng_(std::move(rng))
0152 , fun_(std::move(fun))
0153 {}
0154 };
0155
0156 #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
0157 template(typename Rng, typename Fun)(
0158 requires copy_constructible<Fun>)
0159 split_when_view(Rng &&, Fun)
0160 -> split_when_view<views::all_t<Rng>, Fun>;
0161 #endif
0162
0163 namespace views
0164 {
0165 struct split_when_base_fn
0166 {
0167 private:
0168 template<typename Pred>
0169 struct predicate_pred_
0170 {
0171 semiregular_box_t<Pred> pred_;
0172
0173 template(typename I, typename S)(
0174 requires sentinel_for<S, I>)
0175 std::pair<bool, I> operator()(I cur, S last) const
0176 {
0177 auto where = ranges::find_if_not(cur, last, std::ref(pred_));
0178 return {cur != where, where};
0179 }
0180 };
0181
0182 public:
0183 template(typename Rng, typename Fun)(
0184 requires viewable_range<Rng> AND forward_range<Rng> AND
0185 invocable<Fun &, iterator_t<Rng>, sentinel_t<Rng>> AND
0186 invocable<Fun &, iterator_t<Rng>, iterator_t<Rng>> AND
0187 copy_constructible<Fun> AND
0188 convertible_to<
0189 invoke_result_t<Fun &, iterator_t<Rng>, sentinel_t<Rng>>,
0190 std::pair<bool, iterator_t<Rng>>>)
0191 split_when_view<all_t<Rng>, Fun> operator()(Rng && rng, Fun fun) const
0192 {
0193 return {all(static_cast<Rng &&>(rng)), std::move(fun)};
0194 }
0195 template(typename Rng, typename Fun)(
0196 requires viewable_range<Rng> AND forward_range<Rng> AND
0197 predicate<Fun const &, range_reference_t<Rng>> AND
0198 copy_constructible<Fun>)
0199 split_when_view<all_t<Rng>, predicate_pred_<Fun>>
0200 operator()(Rng && rng, Fun fun) const
0201 {
0202 return {all(static_cast<Rng &&>(rng)),
0203 predicate_pred_<Fun>{std::move(fun)}};
0204 }
0205 };
0206
0207 struct split_when_fn : split_when_base_fn
0208 {
0209 using split_when_base_fn::operator();
0210
0211 template<typename T>
0212 constexpr auto operator()(T && t) const
0213 {
0214 return make_view_closure(
0215 bind_back(split_when_base_fn{}, static_cast<T &&>(t)));
0216 }
0217 };
0218
0219
0220
0221 RANGES_INLINE_VARIABLE(split_when_fn, split_when)
0222 }
0223
0224 }
0225
0226 #include <range/v3/detail/epilogue.hpp>
0227 #include <range/v3/detail/satisfy_boost_range.hpp>
0228 RANGES_SATISFY_BOOST_RANGE(::ranges::split_when_view)
0229
0230 #endif