/// \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_HPP #define RANGES_V3_VIEW_SPLIT_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ranges { /// \addtogroup group-views /// @{ /// \cond namespace detail { // clang-format off #if defined(_MSC_VER) && !defined(__clang__) && \ RANGES_CXX_VER <= RANGES_CXX_STD_17 template(R::size())> constexpr bool _is_tiny_range_(R const *) noexcept { return R::size() <= 1u; } constexpr bool _is_tiny_range_(void const*) noexcept { return false; } /// \concept tiny_range /// \brief The \c tiny_range concept template CPP_concept tiny_range = sized_range && detail::_is_tiny_range_(static_cast>(nullptr)); #else // ^^^^ workaround / no workaround vvvv /// \concept tiny_range_ /// \brief The \c tiny_range_ concept template(typename R)( concept (tiny_range_)(R), ranges::type< std::integral_constant> AND (R::size() <= 1) ); /// \concept tiny_range /// \brief The \c tiny_range concept template CPP_concept tiny_range = sized_range && CPP_concept_ref(detail::tiny_range_, std::remove_reference_t); #endif // clang-format on } // namespace detail template #if CPP_CXX_CONCEPTS requires input_range && forward_range && view_ && view_< Pattern> && indirectly_comparable, iterator_t, ranges::equal_to> && (forward_range || detail::tiny_range) #endif struct split_view; namespace detail { struct there { template static decltype(auto) current_(T & t) noexcept { return (t.curr_); } }; template struct here { It curr_ = It(); It & current_(ignore_t) noexcept { return curr_; } It const & current_(ignore_t) const noexcept { return curr_; } }; template struct here_or_there_ { template using invoke = there; }; template<> struct here_or_there_ { template using invoke = here; }; template using split_view_base = meta::invoke>, It>; template struct split_outer_iterator; template struct split_inner_iterator; template struct split_inner_iterator, Const> { private: using Outer = split_outer_iterator, Const>; using Base = meta::const_if_c; using BaseIterCategory = typename std::iterator_traits>::iterator_category; Outer i_ = Outer(); bool incremented_ = false; constexpr decltype(auto) current_() noexcept { return i_.current_(); } constexpr decltype(auto) current_() const noexcept { return i_.current_(); } constexpr bool done_() const { auto cur = current_(); auto last = ranges::end(i_.parent_->base_); if(cur == last) return true; auto pcur = ranges::begin(i_.parent_->pattern_); auto pend = ranges::end(i_.parent_->pattern_); if(pcur == pend) return incremented_; do { if(*cur != *pcur) return false; if(++pcur == pend) return true; } while(++cur != last); return false; } #if RANGES_CXX_IF_CONSTEXPR < RANGES_CXX_IF_CONSTEXPR_17 constexpr void pre_inc(std::true_type) // Forward { ++current_(); } constexpr void pre_inc(std::false_type) // Input { if(Pattern::size() != 0) ++current_(); } constexpr split_inner_iterator post_inc(std::true_type) // Forward { auto tmp = *this; pre_inc(std::true_type{}); return tmp; } constexpr void post_inc(std::false_type) // Input { pre_inc(std::false_type{}); } #endif public: using iterator_concept = typename Outer::iterator_concept; using iterator_category = meta::conditional_t< derived_from, std::forward_iterator_tag, std::input_iterator_tag>; using value_type = range_value_t; using difference_type = range_difference_t; using reference = range_reference_t; // Not to spec using pointer = iter_pointer_t>; // Not to spec split_inner_iterator() = default; constexpr explicit split_inner_iterator(Outer i) : i_(std::move(i)) {} constexpr decltype(auto) operator*() const { return *current_(); } constexpr split_inner_iterator & operator++() { incremented_ = true; #if RANGES_CXX_IF_CONSTEXPR >= RANGES_CXX_IF_CONSTEXPR_17 if constexpr(!forward_range) if constexpr(Pattern::size() == 0) return *this; ++current_(); #else pre_inc(meta::bool_>{}); #endif return *this; } constexpr decltype(auto) operator++(int) { #if RANGES_CXX_IF_CONSTEXPR >= RANGES_CXX_IF_CONSTEXPR_17 if constexpr(forward_range) { auto tmp = *this; ++*this; return tmp; } else ++*this; #else return post_inc(meta::bool_>{}); #endif } CPP_broken_friend_member friend constexpr auto operator==(split_inner_iterator const & x, split_inner_iterator const & y) -> CPP_broken_friend_ret(bool)( requires forward_range) { return x.i_.curr_ == y.i_.curr_; } CPP_broken_friend_member friend constexpr auto operator!=(split_inner_iterator const & x, split_inner_iterator const & y) -> CPP_broken_friend_ret(bool)( requires forward_range) { return x.i_.curr_ != y.i_.curr_; } #ifdef RANGES_WORKAROUND_MSVC_756601 template #endif // RANGES_WORKAROUND_MSVC_756601 friend constexpr bool operator==(split_inner_iterator const & x, default_sentinel_t) { return x.done_(); } #ifdef RANGES_WORKAROUND_MSVC_756601 template #endif // RANGES_WORKAROUND_MSVC_756601 friend constexpr bool operator==(default_sentinel_t, split_inner_iterator const & x) { return x.done_(); } #ifdef RANGES_WORKAROUND_MSVC_756601 template #endif // RANGES_WORKAROUND_MSVC_756601 friend constexpr bool operator!=(split_inner_iterator const & x, default_sentinel_t) { return !x.done_(); } #ifdef RANGES_WORKAROUND_MSVC_756601 template #endif // RANGES_WORKAROUND_MSVC_756601 friend constexpr bool operator!=(default_sentinel_t, split_inner_iterator const & x) { return !x.done_(); } #ifdef RANGES_WORKAROUND_MSVC_756601 template #endif // RANGES_WORKAROUND_MSVC_756601 friend constexpr decltype(auto) iter_move( split_inner_iterator const & i) noexcept(noexcept(ranges::iter_move(i.current_()))) { return ranges::iter_move(i.current_()); } CPP_broken_friend_member friend constexpr auto iter_swap( split_inner_iterator const & x, split_inner_iterator const & y) noexcept(noexcept(ranges::iter_swap(x.current_(), y.current_()))) -> CPP_broken_friend_ret(void)( requires indirectly_swappable>) { ranges::iter_swap(x.current_(), y.current_()); } }; template using split_outer_iterator_base = meta::invoke>, It>; template struct split_outer_iterator; template struct split_outer_iterator, Const> : split_outer_iterator_base>> { private: friend struct split_inner_iterator, Const>; using Parent = meta::const_if_c>; using Base = meta::const_if_c; using Current = split_outer_iterator_base>; Parent * parent_ = nullptr; constexpr decltype(auto) current_() noexcept { return parent_->current_(*this); } constexpr decltype(auto) current_() const noexcept { return parent_->current_(*this); } constexpr decltype(auto) base_() const noexcept { return (parent_->base_); } #if RANGES_CXX_IF_CONSTEXPR < RANGES_CXX_IF_CONSTEXPR_17 constexpr split_outer_iterator post_inc(std::true_type) // Forward { auto tmp = *this; ++*this; return tmp; } constexpr void post_inc(std::false_type) // Input { ++*this; } #endif public: using iterator_concept = meta::conditional_t, std::forward_iterator_tag, std::input_iterator_tag>; using iterator_category = std::input_iterator_tag; struct value_type : view_interface { private: split_outer_iterator i_ = split_outer_iterator(); public: value_type() = default; constexpr explicit value_type(split_outer_iterator i) : i_(std::move(i)) {} constexpr split_inner_iterator, Const> begin() const { return split_inner_iterator, Const>(i_); } constexpr default_sentinel_t end() const { return default_sentinel; } }; using difference_type = range_difference_t; using reference = value_type; // Not to spec using pointer = value_type *; // Not to spec split_outer_iterator() = default; CPP_member constexpr explicit CPP_ctor(split_outer_iterator)(Parent * parent)( requires (!forward_range)) : parent_(parent) {} CPP_member constexpr CPP_ctor(split_outer_iterator)(Parent * parent, iterator_t current)( requires forward_range) : Current{std::move(current)} , parent_(parent) {} template(bool Other)( requires Const AND CPP_NOT(Other) AND convertible_to, iterator_t>) constexpr split_outer_iterator( split_outer_iterator, Other> i) : Current{std::move(i.curr_)} , parent_(i.parent_) {} constexpr value_type operator*() const { return value_type{*this}; } constexpr split_outer_iterator & operator++() { auto & current = current_(); const auto last = ranges::end(base_()); if(current == last) return *this; auto const pbegin = ranges::begin(parent_->pattern_); auto const pend = ranges::end(parent_->pattern_); if(pbegin == pend) ++current; else do { const auto ret = ranges::mismatch(current, last, pbegin, pend); if(ret.in2 == pend) { current = ret.in1; // The pattern matched; skip it break; } } while(++current != last); return *this; } constexpr decltype(auto) operator++(int) { #if RANGES_CXX_IF_CONSTEXPR >= RANGES_CXX_IF_CONSTEXPR_17 if constexpr(forward_range) { auto tmp = *this; ++*this; return tmp; } else ++*this; #else return post_inc(meta::bool_>{}); #endif } CPP_broken_friend_member friend constexpr auto operator==(split_outer_iterator const & x, split_outer_iterator const & y) -> CPP_broken_friend_ret(bool)( requires forward_range) { return x.curr_ == y.curr_; } CPP_broken_friend_member friend constexpr auto operator!=(split_outer_iterator const & x, split_outer_iterator const & y) -> CPP_broken_friend_ret(bool)( requires forward_range) { return x.curr_ != y.curr_; } #ifdef RANGES_WORKAROUND_MSVC_756601 template #endif // RANGES_WORKAROUND_MSVC_756601 friend constexpr bool operator==(split_outer_iterator const & x, default_sentinel_t) { return x.current_() == ranges::end(x.base_()); } #ifdef RANGES_WORKAROUND_MSVC_756601 template #endif // RANGES_WORKAROUND_MSVC_756601 friend constexpr bool operator==(default_sentinel_t, split_outer_iterator const & x) { return x.current_() == ranges::end(x.base_()); } #ifdef RANGES_WORKAROUND_MSVC_756601 template #endif // RANGES_WORKAROUND_MSVC_756601 friend constexpr bool operator!=(split_outer_iterator const & x, default_sentinel_t) { return x.current_() != ranges::end(x.base_()); } #ifdef RANGES_WORKAROUND_MSVC_756601 template #endif // RANGES_WORKAROUND_MSVC_756601 friend constexpr bool operator!=(default_sentinel_t, split_outer_iterator const & x) { return x.current_() != ranges::end(x.base_()); } }; } // namespace detail /// \endcond template #if CPP_CXX_CONCEPTS requires input_range && forward_range && view_ && view_< Pattern> && indirectly_comparable, iterator_t, ranges::equal_to> && (forward_range || detail::tiny_range) #endif struct RANGES_EMPTY_BASES split_view : view_interface, is_finite::value ? finite : unknown> , private detail::split_view_base> { private: template friend struct detail::split_outer_iterator; template friend struct detail::split_inner_iterator; V base_ = V(); Pattern pattern_ = Pattern(); template using outer_iterator = detail::split_outer_iterator; #if RANGES_CXX_IF_CONSTEXPR < RANGES_CXX_IF_CONSTEXPR_17 outer_iterator()> begin_(std::true_type) { return outer_iterator()>{this, ranges::begin(base_)}; } outer_iterator begin_(std::false_type) { this->curr_ = ranges::begin(base_); return outer_iterator{this}; } outer_iterator()> end_(std::true_type) const { return outer_iterator{this, ranges::end(base_)}; } default_sentinel_t end_(std::false_type) const { return default_sentinel; } #endif public: split_view() = default; constexpr split_view(V base, Pattern pattern) : base_((V &&) base) , pattern_((Pattern &&) pattern) {} CPP_member constexpr CPP_ctor(split_view)(V base, range_value_t e)( requires constructible_from>) : base_(std::move(base)) , pattern_(e) {} constexpr V base() const { return base_; } constexpr outer_iterator && simple_view()> begin() { #if RANGES_CXX_IF_CONSTEXPR >= RANGES_CXX_IF_CONSTEXPR_17 if constexpr(forward_range) return outer_iterator()>{this, ranges::begin(base_)}; else { this->curr_ = ranges::begin(base_); return outer_iterator{this}; } #else return begin_(meta::bool_>{}); #endif } CPP_member constexpr auto begin() const // -> CPP_ret(outer_iterator)( requires forward_range && forward_range) { return {this, ranges::begin(base_)}; } CPP_member constexpr auto end() // -> CPP_ret(outer_iterator()>)( requires forward_range && common_range) { return outer_iterator()>{this, ranges::end(base_)}; } constexpr auto end() const { #if RANGES_CXX_IF_CONSTEXPR >= RANGES_CXX_IF_CONSTEXPR_17 if constexpr(forward_range && forward_range && common_range) return outer_iterator{this, ranges::end(base_)}; else return default_sentinel; #else return end_(meta::bool_ < forward_range && forward_range && common_range > {}); #endif } }; #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17 template(typename R, typename P)( requires input_range AND forward_range

AND viewable_range AND viewable_range

AND indirectly_comparable, iterator_t

, ranges::equal_to> AND (forward_range || detail::tiny_range

)) // split_view(R &&, P &&) ->split_view, views::all_t

>; template(typename R)( requires input_range) split_view(R &&, range_value_t) ->split_view, single_view>>; #endif namespace views { struct split_base_fn { template(typename Rng)( requires viewable_range AND input_range AND indirectly_comparable, range_value_t const *, ranges::equal_to>) constexpr split_view, single_view>> // operator()(Rng && rng, range_value_t val) const { return {all(static_cast(rng)), single(std::move(val))}; } template(typename Rng, typename Pattern)( requires viewable_range AND input_range AND viewable_range AND forward_range AND indirectly_comparable< iterator_t, iterator_t, ranges::equal_to> AND (forward_range || detail::tiny_range)) // constexpr split_view, all_t> // operator()(Rng && rng, Pattern && pattern) const { return {all((Rng &&) rng), all((Pattern &&) pattern)}; } }; struct split_fn : split_base_fn { using split_base_fn::operator(); template constexpr auto operator()(T t) const { return make_view_closure(bind_back(split_base_fn{}, std::move(t))); } }; /// \relates split_fn /// \ingroup group-views RANGES_INLINE_VARIABLE(split_fn, split) } // namespace views namespace cpp20 { namespace views { using ranges::views::split; } template(typename Rng, typename Pattern)( requires input_range AND forward_range AND view_ AND view_ AND indirectly_comparable< iterator_t, iterator_t, ranges::equal_to> AND (forward_range || ranges::detail::tiny_range)) // using split_view = ranges::split_view; } // namespace cpp20 /// @} } // namespace ranges #include #include RANGES_SATISFY_BOOST_RANGE(::ranges::split_view) #endif