/// \file // Range v3 library // // Copyright Eric Niebler 2013-present // // Use, modification and distribution is subject to the // Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // Project home: https://github.com/ericniebler/range-v3 // #ifndef RANGES_V3_VIEW_SPLIT_WHEN_HPP #define RANGES_V3_VIEW_SPLIT_WHEN_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ranges { /// \addtogroup group-views /// @{ template struct split_when_view : view_facade, is_finite::value ? finite : range_cardinality::value> { private: friend range_access; Rng rng_; semiregular_box_t fun_; template struct cursor { private: friend range_access; friend split_when_view; friend struct cursor; bool zero_; using CRng = meta::const_if_c; iterator_t cur_; sentinel_t last_; using fun_ref_t = semiregular_box_ref_or_val_t; fun_ref_t fun_; struct search_pred { bool zero_; iterator_t first_; sentinel_t last_; fun_ref_t fun_; bool operator()(iterator_t cur) const { return (zero_ && cur == first_) || (cur != last_ && !invoke(fun_, cur, last_).first); } }; using reference_ = indirect_view>, search_pred>>; reference_ read() const { return reference_{{views::iota(cur_), {zero_, cur_, last_, fun_}}}; } void next() { RANGES_EXPECT(cur_ != last_); // If the last match consumed zero elements, bump the position. if(zero_) { zero_ = false; ++cur_; } for(; cur_ != last_; ++cur_) { auto p = invoke(fun_, cur_, last_); if(p.first) { zero_ = (cur_ == p.second); cur_ = p.second; return; } } } bool equal(default_sentinel_t) const { return cur_ == last_; } bool equal(cursor const & that) const { return cur_ == that.cur_; } cursor(fun_ref_t fun, iterator_t first, sentinel_t last) : cur_(first) , last_(last) , fun_(fun) { // For skipping an initial zero-length match auto p = invoke(fun, first, last); zero_ = p.first && first == p.second; } public: cursor() = default; template(bool Other)( /// \pre requires IsConst AND CPP_NOT(Other)) // cursor(cursor that) : cursor{std::move(that.cur_), std::move(that.last_), std::move(that.fun_)} {} }; cursor begin_cursor() { return {fun_, ranges::begin(rng_), ranges::end(rng_)}; } template(bool Const = true)( /// \pre requires Const AND range> AND invocable>, sentinel_t>>) cursor begin_cursor() const { return {fun_, ranges::begin(rng_), ranges::end(rng_)}; } public: split_when_view() = default; split_when_view(Rng rng, Fun fun) : rng_(std::move(rng)) , fun_(std::move(fun)) {} }; #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17 template(typename Rng, typename Fun)( /// \pre requires copy_constructible) split_when_view(Rng &&, Fun) -> split_when_view, Fun>; #endif namespace views { struct split_when_base_fn { private: template struct predicate_pred_ { semiregular_box_t pred_; template(typename I, typename S)( /// \pre requires sentinel_for) std::pair operator()(I cur, S last) const { auto where = ranges::find_if_not(cur, last, std::ref(pred_)); return {cur != where, where}; } }; public: template(typename Rng, typename Fun)( /// \pre requires viewable_range AND forward_range AND invocable, sentinel_t> AND invocable, iterator_t> AND copy_constructible AND convertible_to< invoke_result_t, sentinel_t>, std::pair>>) split_when_view, Fun> operator()(Rng && rng, Fun fun) const // { return {all(static_cast(rng)), std::move(fun)}; } template(typename Rng, typename Fun)( /// \pre requires viewable_range AND forward_range AND predicate> AND copy_constructible) split_when_view, predicate_pred_> // operator()(Rng && rng, Fun fun) const { return {all(static_cast(rng)), predicate_pred_{std::move(fun)}}; } }; struct split_when_fn : split_when_base_fn { using split_when_base_fn::operator(); template constexpr auto operator()(T && t) const { return make_view_closure( bind_back(split_when_base_fn{}, static_cast(t))); } }; /// \relates split_when_fn /// \ingroup group-views RANGES_INLINE_VARIABLE(split_when_fn, split_when) } // namespace views /// @} } // namespace ranges #include #include RANGES_SATISFY_BOOST_RANGE(::ranges::split_when_view) #endif