/// \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 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; CPP_template(bool Other)( // requires IsConst && (!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 auto begin_cursor() const -> CPP_ret(cursor)( // requires Const && range> && invocable>, sentinel_t>>) { 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 CPP_template(typename Rng, typename Fun)(requires copy_constructible) split_when_view(Rng &&, Fun) ->split_when_view, Fun>; #endif namespace views { struct split_when_fn { private: friend view_access; template static auto bind(split_when_fn split_when, T && t) { return make_pipeable(bind_back(split_when, static_cast(t))); } template struct predicate_pred { semiregular_box_t pred_; template auto operator()(I cur, S last) const -> CPP_ret(std::pair)( // requires sentinel_for) { auto where = ranges::find_if_not(cur, last, std::ref(pred_)); return {cur != where, where}; } }; public: template auto operator()(Rng && rng, Fun fun) const -> CPP_ret( split_when_view, Fun>)( // requires viewable_range && forward_range && invocable, sentinel_t> && invocable, iterator_t> && copy_constructible && convertible_to< invoke_result_t, sentinel_t>, std::pair>>) { return {all(static_cast(rng)), std::move(fun)}; } template auto operator()(Rng && rng, Fun fun) const -> CPP_ret(split_when_view, predicate_pred>)( // requires viewable_range && forward_range && predicate< Fun const &, range_reference_t> && copy_constructible) { return {all(static_cast(rng)), predicate_pred{std::move(fun)}}; } }; /// \relates split_when_fn /// \ingroup group-views RANGES_INLINE_VARIABLE(view, split_when) } // namespace views /// @} } // namespace ranges #include RANGES_SATISFY_BOOST_RANGE(::ranges::split_when_view) #endif