Files
allhaileris afb81b8278
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled
init
2026-02-16 15:50:16 +03:00

707 lines
24 KiB
C++

/// \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 <type_traits>
#include <utility>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/algorithm/mismatch.hpp>
#include <range/v3/functional/bind_back.hpp>
#include <range/v3/iterator/default_sentinel.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/interface.hpp>
#include <range/v3/view/single.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
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<typename R, std::size_t Sz = static_cast<std::size_t>(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<typename R>
CPP_concept tiny_range =
sized_range<R> &&
detail::_is_tiny_range_(static_cast<std::add_pointer_t<R>>(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<decltype(R::size()), R::size()>> AND
(R::size() <= 1)
);
/// \concept tiny_range
/// \brief The \c tiny_range concept
template<typename R>
CPP_concept tiny_range =
sized_range<R> &&
CPP_concept_ref(detail::tiny_range_, std::remove_reference_t<R>);
#endif
// clang-format on
} // namespace detail
template<typename V, typename Pattern>
#if CPP_CXX_CONCEPTS
requires input_range<V> && forward_range<Pattern> && view_<V> && view_<
Pattern> && indirectly_comparable<iterator_t<V>, iterator_t<Pattern>,
ranges::equal_to> &&
(forward_range<V> || detail::tiny_range<Pattern>)
#endif
struct split_view;
namespace detail
{
struct there
{
template<typename T>
static decltype(auto) current_(T & t) noexcept
{
return (t.curr_);
}
};
template<typename It>
struct here
{
It curr_ = It();
It & current_(ignore_t) noexcept
{
return curr_;
}
It const & current_(ignore_t) const noexcept
{
return curr_;
}
};
template<bool>
struct here_or_there_
{
template<typename>
using invoke = there;
};
template<>
struct here_or_there_<true>
{
template<typename It>
using invoke = here<It>;
};
template<typename It>
using split_view_base = meta::invoke<here_or_there_<!forward_iterator<It>>, It>;
template<typename JoinView, bool Const>
struct split_outer_iterator;
template<typename JoinView, bool Const>
struct split_inner_iterator;
template<typename V, typename Pattern, bool Const>
struct split_inner_iterator<split_view<V, Pattern>, Const>
{
private:
using Outer = split_outer_iterator<split_view<V, Pattern>, Const>;
using Base = meta::const_if_c<Const, V>;
using BaseIterCategory =
typename std::iterator_traits<iterator_t<Base>>::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<BaseIterCategory, std::forward_iterator_tag>,
std::forward_iterator_tag,
std::input_iterator_tag>;
using value_type = range_value_t<Base>;
using difference_type = range_difference_t<Base>;
using reference = range_reference_t<Base>; // Not to spec
using pointer = iter_pointer_t<iterator_t<Base>>; // 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<Base>)
if constexpr(Pattern::size() == 0)
return *this;
++current_();
#else
pre_inc(meta::bool_<forward_range<Base>>{});
#endif
return *this;
}
constexpr decltype(auto) operator++(int)
{
#if RANGES_CXX_IF_CONSTEXPR >= RANGES_CXX_IF_CONSTEXPR_17
if constexpr(forward_range<V>)
{
auto tmp = *this;
++*this;
return tmp;
}
else
++*this;
#else
return post_inc(meta::bool_<forward_range<V>>{});
#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<Base>)
{
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<Base>)
{
return x.i_.curr_ != y.i_.curr_;
}
#ifdef RANGES_WORKAROUND_MSVC_756601
template<typename = void>
#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<typename = void>
#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<typename = void>
#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<typename = void>
#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<typename = void>
#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<iterator_t<Base>>)
{
ranges::iter_swap(x.current_(), y.current_());
}
};
template<typename It>
using split_outer_iterator_base =
meta::invoke<here_or_there_<forward_iterator<It>>, It>;
template<typename JoinView, bool Const>
struct split_outer_iterator;
template<typename V, typename Pattern, bool Const>
struct split_outer_iterator<split_view<V, Pattern>, Const>
: split_outer_iterator_base<iterator_t<meta::const_if_c<Const, V>>>
{
private:
friend struct split_inner_iterator<split_view<V, Pattern>, Const>;
using Parent = meta::const_if_c<Const, split_view<V, Pattern>>;
using Base = meta::const_if_c<Const, V>;
using Current = split_outer_iterator_base<iterator_t<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<forward_range<Base>, std::forward_iterator_tag,
std::input_iterator_tag>;
using iterator_category = std::input_iterator_tag;
struct value_type : view_interface<value_type>
{
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<split_view<V, Pattern>, Const> begin()
const
{
return split_inner_iterator<split_view<V, Pattern>, Const>(i_);
}
constexpr default_sentinel_t end() const
{
return default_sentinel;
}
};
using difference_type = range_difference_t<Base>;
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<Base>))
: parent_(parent)
{}
CPP_member
constexpr CPP_ctor(split_outer_iterator)(Parent * parent,
iterator_t<Base> current)(
requires forward_range<Base>)
: Current{std::move(current)}
, parent_(parent)
{}
template(bool Other)(
requires Const AND CPP_NOT(Other) AND
convertible_to<iterator_t<V>, iterator_t<Base>>)
constexpr split_outer_iterator(
split_outer_iterator<split_view<V, Pattern>, 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<Base>)
{
auto tmp = *this;
++*this;
return tmp;
}
else
++*this;
#else
return post_inc(meta::bool_<forward_range<Base>>{});
#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<Base>)
{
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<Base>)
{
return x.curr_ != y.curr_;
}
#ifdef RANGES_WORKAROUND_MSVC_756601
template<typename = void>
#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<typename = void>
#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<typename = void>
#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<typename = void>
#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<typename V, typename Pattern>
#if CPP_CXX_CONCEPTS
requires input_range<V> && forward_range<Pattern> && view_<V> && view_<
Pattern> && indirectly_comparable<iterator_t<V>, iterator_t<Pattern>,
ranges::equal_to> &&
(forward_range<V> || detail::tiny_range<Pattern>)
#endif
struct RANGES_EMPTY_BASES split_view
: view_interface<split_view<V, Pattern>, is_finite<V>::value ? finite : unknown>
, private detail::split_view_base<iterator_t<V>>
{
private:
template<typename, bool>
friend struct detail::split_outer_iterator;
template<typename, bool>
friend struct detail::split_inner_iterator;
V base_ = V();
Pattern pattern_ = Pattern();
template<bool Const>
using outer_iterator = detail::split_outer_iterator<split_view, Const>;
#if RANGES_CXX_IF_CONSTEXPR < RANGES_CXX_IF_CONSTEXPR_17
outer_iterator<simple_view<V>()> begin_(std::true_type)
{
return outer_iterator<simple_view<V>()>{this, ranges::begin(base_)};
}
outer_iterator<false> begin_(std::false_type)
{
this->curr_ = ranges::begin(base_);
return outer_iterator<false>{this};
}
outer_iterator<simple_view<V>()> end_(std::true_type) const
{
return outer_iterator<true>{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<V> e)(
requires constructible_from<Pattern, range_value_t<V>>)
: base_(std::move(base))
, pattern_(e)
{}
constexpr V base() const
{
return base_;
}
constexpr outer_iterator<forward_range<V> && simple_view<V>()> begin()
{
#if RANGES_CXX_IF_CONSTEXPR >= RANGES_CXX_IF_CONSTEXPR_17
if constexpr(forward_range<V>)
return outer_iterator<simple_view<V>()>{this, ranges::begin(base_)};
else
{
this->curr_ = ranges::begin(base_);
return outer_iterator<false>{this};
}
#else
return begin_(meta::bool_<forward_range<V>>{});
#endif
}
CPP_member
constexpr auto begin() const //
-> CPP_ret(outer_iterator<true>)(
requires forward_range<V> && forward_range<const V>)
{
return {this, ranges::begin(base_)};
}
CPP_member
constexpr auto end() //
-> CPP_ret(outer_iterator<simple_view<V>()>)(
requires forward_range<V> && common_range<V>)
{
return outer_iterator<simple_view<V>()>{this, ranges::end(base_)};
}
constexpr auto end() const
{
#if RANGES_CXX_IF_CONSTEXPR >= RANGES_CXX_IF_CONSTEXPR_17
if constexpr(forward_range<V> && forward_range<const V> &&
common_range<const V>)
return outer_iterator<true>{this, ranges::end(base_)};
else
return default_sentinel;
#else
return end_(meta::bool_ < forward_range<V> && forward_range<const V> &&
common_range<const V> > {});
#endif
}
};
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template(typename R, typename P)(
requires input_range<R> AND forward_range<P> AND viewable_range<R> AND
viewable_range<P> AND
indirectly_comparable<iterator_t<R>, iterator_t<P>, ranges::equal_to> AND
(forward_range<R> || detail::tiny_range<P>)) //
split_view(R &&, P &&)
->split_view<views::all_t<R>, views::all_t<P>>;
template(typename R)(
requires input_range<R>)
split_view(R &&, range_value_t<R>)
->split_view<views::all_t<R>, single_view<range_value_t<R>>>;
#endif
namespace views
{
struct split_base_fn
{
template(typename Rng)(
requires viewable_range<Rng> AND input_range<Rng> AND
indirectly_comparable<iterator_t<Rng>,
range_value_t<Rng> const *,
ranges::equal_to>)
constexpr split_view<all_t<Rng>, single_view<range_value_t<Rng>>> //
operator()(Rng && rng, range_value_t<Rng> val) const
{
return {all(static_cast<Rng &&>(rng)), single(std::move(val))};
}
template(typename Rng, typename Pattern)(
requires viewable_range<Rng> AND input_range<Rng> AND
viewable_range<Pattern> AND forward_range<Pattern> AND
indirectly_comparable<
iterator_t<Rng>,
iterator_t<Pattern>,
ranges::equal_to> AND
(forward_range<Rng> || detail::tiny_range<Pattern>)) //
constexpr split_view<all_t<Rng>, all_t<Pattern>> //
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<typename T>
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<Rng> AND forward_range<Pattern> AND view_<Rng> AND
view_<Pattern> AND
indirectly_comparable<
iterator_t<Rng>,
iterator_t<Pattern>,
ranges::equal_to> AND
(forward_range<Rng> || ranges::detail::tiny_range<Pattern>)) //
using split_view =
ranges::split_view<Rng, Pattern>;
} // namespace cpp20
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::split_view)
#endif