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_HPP
0015 #define RANGES_V3_VIEW_SPLIT_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/mismatch.hpp>
0025 #include <range/v3/functional/bind_back.hpp>
0026 #include <range/v3/iterator/default_sentinel.hpp>
0027 #include <range/v3/range/access.hpp>
0028 #include <range/v3/range/concepts.hpp>
0029 #include <range/v3/range/traits.hpp>
0030 #include <range/v3/utility/static_const.hpp>
0031 #include <range/v3/view/all.hpp>
0032 #include <range/v3/view/interface.hpp>
0033 #include <range/v3/view/single.hpp>
0034 #include <range/v3/view/view.hpp>
0035
0036 #include <range/v3/detail/prologue.hpp>
0037
0038 namespace ranges
0039 {
0040
0041
0042
0043
0044 namespace detail
0045 {
0046
0047 #if defined(_MSC_VER) && !defined(__clang__) && \
0048 RANGES_CXX_VER <= RANGES_CXX_STD_17
0049 template<typename R, std::size_t Sz = static_cast<std::size_t>(R::size())>
0050 constexpr bool _is_tiny_range_(R const *) noexcept
0051 {
0052 return R::size() <= 1u;
0053 }
0054 constexpr bool _is_tiny_range_(void const*) noexcept
0055 {
0056 return false;
0057 }
0058
0059
0060 template<typename R>
0061 CPP_concept tiny_range =
0062 sized_range<R> &&
0063 detail::_is_tiny_range_(static_cast<std::add_pointer_t<R>>(nullptr));
0064 #else
0065
0066
0067 template(typename R)(
0068 concept (tiny_range_)(R),
0069 ranges::type<
0070 std::integral_constant<decltype(R::size()), R::size()>> AND
0071 (R::size() <= 1)
0072 );
0073
0074
0075 template<typename R>
0076 CPP_concept tiny_range =
0077 sized_range<R> &&
0078 CPP_concept_ref(detail::tiny_range_, std::remove_reference_t<R>);
0079 #endif
0080
0081 }
0082
0083 template<typename V, typename Pattern>
0084 #if CPP_CXX_CONCEPTS
0085 requires input_range<V> && forward_range<Pattern> && view_<V> && view_<
0086 Pattern> && indirectly_comparable<iterator_t<V>, iterator_t<Pattern>,
0087 ranges::equal_to> &&
0088 (forward_range<V> || detail::tiny_range<Pattern>)
0089 #endif
0090 struct split_view;
0091
0092 namespace detail
0093 {
0094 struct there
0095 {
0096 template<typename T>
0097 static decltype(auto) current_(T & t) noexcept
0098 {
0099 return (t.curr_);
0100 }
0101 };
0102
0103 template<typename It>
0104 struct here
0105 {
0106 It curr_ = It();
0107 It & current_(ignore_t) noexcept
0108 {
0109 return curr_;
0110 }
0111 It const & current_(ignore_t) const noexcept
0112 {
0113 return curr_;
0114 }
0115 };
0116
0117 template<bool>
0118 struct here_or_there_
0119 {
0120 template<typename>
0121 using invoke = there;
0122 };
0123
0124 template<>
0125 struct here_or_there_<true>
0126 {
0127 template<typename It>
0128 using invoke = here<It>;
0129 };
0130
0131 template<typename It>
0132 using split_view_base = meta::invoke<here_or_there_<!forward_iterator<It>>, It>;
0133
0134 template<typename JoinView, bool Const>
0135 struct split_outer_iterator;
0136
0137 template<typename JoinView, bool Const>
0138 struct split_inner_iterator;
0139
0140 template<typename V, typename Pattern, bool Const>
0141 struct split_inner_iterator<split_view<V, Pattern>, Const>
0142 {
0143 private:
0144 using Outer = split_outer_iterator<split_view<V, Pattern>, Const>;
0145 using Base = meta::const_if_c<Const, V>;
0146 using BaseIterCategory =
0147 typename std::iterator_traits<iterator_t<Base>>::iterator_category;
0148 Outer i_ = Outer();
0149 bool incremented_ = false;
0150 constexpr decltype(auto) current_() noexcept
0151 {
0152 return i_.current_();
0153 }
0154 constexpr decltype(auto) current_() const noexcept
0155 {
0156 return i_.current_();
0157 }
0158 constexpr bool done_() const
0159 {
0160 auto cur = current_();
0161 auto last = ranges::end(i_.parent_->base_);
0162 if(cur == last)
0163 return true;
0164 auto pcur = ranges::begin(i_.parent_->pattern_);
0165 auto pend = ranges::end(i_.parent_->pattern_);
0166 if(pcur == pend)
0167 return incremented_;
0168 do
0169 {
0170 if(*cur != *pcur)
0171 return false;
0172 if(++pcur == pend)
0173 return true;
0174 } while(++cur != last);
0175 return false;
0176 }
0177 #if RANGES_CXX_IF_CONSTEXPR < RANGES_CXX_IF_CONSTEXPR_17
0178 constexpr void pre_inc(std::true_type)
0179 {
0180 ++current_();
0181 }
0182 constexpr void pre_inc(std::false_type)
0183 {
0184 if(Pattern::size() != 0)
0185 ++current_();
0186 }
0187 constexpr split_inner_iterator post_inc(std::true_type)
0188 {
0189 auto tmp = *this;
0190 pre_inc(std::true_type{});
0191 return tmp;
0192 }
0193 constexpr void post_inc(std::false_type)
0194 {
0195 pre_inc(std::false_type{});
0196 }
0197 #endif
0198 public:
0199 using iterator_concept = typename Outer::iterator_concept;
0200 using iterator_category =
0201 meta::conditional_t<
0202 derived_from<BaseIterCategory, std::forward_iterator_tag>,
0203 std::forward_iterator_tag,
0204 std::input_iterator_tag>;
0205 using value_type = range_value_t<Base>;
0206 using difference_type = range_difference_t<Base>;
0207 using reference = range_reference_t<Base>;
0208 using pointer = iter_pointer_t<iterator_t<Base>>;
0209
0210 split_inner_iterator() = default;
0211
0212 constexpr explicit split_inner_iterator(Outer i)
0213 : i_(std::move(i))
0214 {}
0215
0216 constexpr decltype(auto) operator*() const
0217 {
0218 return *current_();
0219 }
0220
0221 constexpr split_inner_iterator & operator++()
0222 {
0223 incremented_ = true;
0224 #if RANGES_CXX_IF_CONSTEXPR >= RANGES_CXX_IF_CONSTEXPR_17
0225 if constexpr(!forward_range<Base>)
0226 if constexpr(Pattern::size() == 0)
0227 return *this;
0228 ++current_();
0229 #else
0230 pre_inc(meta::bool_<forward_range<Base>>{});
0231 #endif
0232 return *this;
0233 }
0234
0235 constexpr decltype(auto) operator++(int)
0236 {
0237 #if RANGES_CXX_IF_CONSTEXPR >= RANGES_CXX_IF_CONSTEXPR_17
0238 if constexpr(forward_range<V>)
0239 {
0240 auto tmp = *this;
0241 ++*this;
0242 return tmp;
0243 }
0244 else
0245 ++*this;
0246 #else
0247 return post_inc(meta::bool_<forward_range<V>>{});
0248 #endif
0249 }
0250
0251 CPP_broken_friend_member
0252 friend constexpr auto operator==(split_inner_iterator const & x,
0253 split_inner_iterator const & y)
0254 -> CPP_broken_friend_ret(bool)(
0255 requires forward_range<Base>)
0256 {
0257 return x.i_.curr_ == y.i_.curr_;
0258 }
0259 CPP_broken_friend_member
0260 friend constexpr auto operator!=(split_inner_iterator const & x,
0261 split_inner_iterator const & y)
0262 -> CPP_broken_friend_ret(bool)(
0263 requires forward_range<Base>)
0264 {
0265 return x.i_.curr_ != y.i_.curr_;
0266 }
0267 #ifdef RANGES_WORKAROUND_MSVC_756601
0268 template<typename = void>
0269 #endif
0270 friend constexpr bool operator==(split_inner_iterator const & x,
0271 default_sentinel_t)
0272 {
0273 return x.done_();
0274 }
0275 #ifdef RANGES_WORKAROUND_MSVC_756601
0276 template<typename = void>
0277 #endif
0278 friend constexpr bool operator==(default_sentinel_t,
0279 split_inner_iterator const & x)
0280 {
0281 return x.done_();
0282 }
0283 #ifdef RANGES_WORKAROUND_MSVC_756601
0284 template<typename = void>
0285 #endif
0286 friend constexpr bool operator!=(split_inner_iterator const & x,
0287 default_sentinel_t)
0288 {
0289 return !x.done_();
0290 }
0291 #ifdef RANGES_WORKAROUND_MSVC_756601
0292 template<typename = void>
0293 #endif
0294 friend constexpr bool operator!=(default_sentinel_t,
0295 split_inner_iterator const & x)
0296 {
0297 return !x.done_();
0298 }
0299 #ifdef RANGES_WORKAROUND_MSVC_756601
0300 template<typename = void>
0301 #endif
0302 friend constexpr decltype(auto) iter_move(
0303 split_inner_iterator const &
0304 i) noexcept(noexcept(ranges::iter_move(i.current_())))
0305 {
0306 return ranges::iter_move(i.current_());
0307 }
0308 CPP_broken_friend_member
0309 friend constexpr auto iter_swap(
0310 split_inner_iterator const & x,
0311 split_inner_iterator const &
0312 y) noexcept(noexcept(ranges::iter_swap(x.current_(), y.current_())))
0313 -> CPP_broken_friend_ret(void)(
0314 requires indirectly_swappable<iterator_t<Base>>)
0315 {
0316 ranges::iter_swap(x.current_(), y.current_());
0317 }
0318 };
0319
0320 template<typename It>
0321 using split_outer_iterator_base =
0322 meta::invoke<here_or_there_<forward_iterator<It>>, It>;
0323
0324 template<typename JoinView, bool Const>
0325 struct split_outer_iterator;
0326
0327 template<typename V, typename Pattern, bool Const>
0328 struct split_outer_iterator<split_view<V, Pattern>, Const>
0329 : split_outer_iterator_base<iterator_t<meta::const_if_c<Const, V>>>
0330 {
0331 private:
0332 friend struct split_inner_iterator<split_view<V, Pattern>, Const>;
0333 using Parent = meta::const_if_c<Const, split_view<V, Pattern>>;
0334 using Base = meta::const_if_c<Const, V>;
0335 using Current = split_outer_iterator_base<iterator_t<Base>>;
0336
0337 Parent * parent_ = nullptr;
0338 constexpr decltype(auto) current_() noexcept
0339 {
0340 return parent_->current_(*this);
0341 }
0342 constexpr decltype(auto) current_() const noexcept
0343 {
0344 return parent_->current_(*this);
0345 }
0346 constexpr decltype(auto) base_() const noexcept
0347 {
0348 return (parent_->base_);
0349 }
0350 #if RANGES_CXX_IF_CONSTEXPR < RANGES_CXX_IF_CONSTEXPR_17
0351 constexpr split_outer_iterator post_inc(std::true_type)
0352 {
0353 auto tmp = *this;
0354 ++*this;
0355 return tmp;
0356 }
0357 constexpr void post_inc(std::false_type)
0358 {
0359 ++*this;
0360 }
0361 #endif
0362
0363 public:
0364 using iterator_concept =
0365 meta::conditional_t<forward_range<Base>, std::forward_iterator_tag,
0366 std::input_iterator_tag>;
0367 using iterator_category = std::input_iterator_tag;
0368 struct value_type : view_interface<value_type>
0369 {
0370 private:
0371 split_outer_iterator i_ = split_outer_iterator();
0372
0373 public:
0374 value_type() = default;
0375 constexpr explicit value_type(split_outer_iterator i)
0376 : i_(std::move(i))
0377 {}
0378 constexpr split_inner_iterator<split_view<V, Pattern>, Const> begin()
0379 const
0380 {
0381 return split_inner_iterator<split_view<V, Pattern>, Const>(i_);
0382 }
0383 constexpr default_sentinel_t end() const
0384 {
0385 return default_sentinel;
0386 }
0387 };
0388 using difference_type = range_difference_t<Base>;
0389 using reference = value_type;
0390 using pointer = value_type *;
0391
0392 split_outer_iterator() = default;
0393
0394 CPP_member
0395 constexpr explicit CPP_ctor(split_outer_iterator)(Parent * parent)(
0396 requires (!forward_range<Base>))
0397 : parent_(parent)
0398 {}
0399
0400 CPP_member
0401 constexpr CPP_ctor(split_outer_iterator)(Parent * parent,
0402 iterator_t<Base> current)(
0403 requires forward_range<Base>)
0404 : Current{std::move(current)}
0405 , parent_(parent)
0406 {}
0407
0408 template(bool Other)(
0409 requires Const AND CPP_NOT(Other) AND
0410 convertible_to<iterator_t<V>, iterator_t<Base>>)
0411 constexpr split_outer_iterator(
0412 split_outer_iterator<split_view<V, Pattern>, Other> i)
0413 : Current{std::move(i.curr_)}
0414 , parent_(i.parent_)
0415 {}
0416
0417 constexpr value_type operator*() const
0418 {
0419 return value_type{*this};
0420 }
0421
0422 constexpr split_outer_iterator & operator++()
0423 {
0424 auto & current = current_();
0425 const auto last = ranges::end(base_());
0426 if(current == last)
0427 return *this;
0428 auto const pbegin = ranges::begin(parent_->pattern_);
0429 auto const pend = ranges::end(parent_->pattern_);
0430 if(pbegin == pend)
0431 ++current;
0432 else
0433 do
0434 {
0435 const auto ret = ranges::mismatch(current, last, pbegin, pend);
0436 if(ret.in2 == pend)
0437 {
0438 current = ret.in1;
0439 break;
0440 }
0441 } while(++current != last);
0442 return *this;
0443 }
0444
0445 constexpr decltype(auto) operator++(int)
0446 {
0447 #if RANGES_CXX_IF_CONSTEXPR >= RANGES_CXX_IF_CONSTEXPR_17
0448 if constexpr(forward_range<Base>)
0449 {
0450 auto tmp = *this;
0451 ++*this;
0452 return tmp;
0453 }
0454 else
0455 ++*this;
0456 #else
0457 return post_inc(meta::bool_<forward_range<Base>>{});
0458 #endif
0459 }
0460
0461 CPP_broken_friend_member
0462 friend constexpr auto operator==(split_outer_iterator const & x,
0463 split_outer_iterator const & y)
0464 -> CPP_broken_friend_ret(bool)(
0465 requires forward_range<Base>)
0466 {
0467 return x.curr_ == y.curr_;
0468 }
0469 CPP_broken_friend_member
0470 friend constexpr auto operator!=(split_outer_iterator const & x,
0471 split_outer_iterator const & y)
0472 -> CPP_broken_friend_ret(bool)(
0473 requires forward_range<Base>)
0474 {
0475 return x.curr_ != y.curr_;
0476 }
0477 #ifdef RANGES_WORKAROUND_MSVC_756601
0478 template<typename = void>
0479 #endif
0480 friend constexpr bool operator==(split_outer_iterator const & x,
0481 default_sentinel_t)
0482 {
0483 return x.current_() == ranges::end(x.base_());
0484 }
0485 #ifdef RANGES_WORKAROUND_MSVC_756601
0486 template<typename = void>
0487 #endif
0488 friend constexpr bool operator==(default_sentinel_t,
0489 split_outer_iterator const & x)
0490 {
0491 return x.current_() == ranges::end(x.base_());
0492 }
0493 #ifdef RANGES_WORKAROUND_MSVC_756601
0494 template<typename = void>
0495 #endif
0496 friend constexpr bool operator!=(split_outer_iterator const & x,
0497 default_sentinel_t)
0498 {
0499 return x.current_() != ranges::end(x.base_());
0500 }
0501 #ifdef RANGES_WORKAROUND_MSVC_756601
0502 template<typename = void>
0503 #endif
0504 friend constexpr bool operator!=(default_sentinel_t,
0505 split_outer_iterator const & x)
0506 {
0507 return x.current_() != ranges::end(x.base_());
0508 }
0509 };
0510 }
0511
0512
0513 template<typename V, typename Pattern>
0514 #if CPP_CXX_CONCEPTS
0515 requires input_range<V> && forward_range<Pattern> && view_<V> && view_<
0516 Pattern> && indirectly_comparable<iterator_t<V>, iterator_t<Pattern>,
0517 ranges::equal_to> &&
0518 (forward_range<V> || detail::tiny_range<Pattern>)
0519 #endif
0520 struct RANGES_EMPTY_BASES split_view
0521 : view_interface<split_view<V, Pattern>, is_finite<V>::value ? finite : unknown>
0522 , private detail::split_view_base<iterator_t<V>>
0523 {
0524 private:
0525 template<typename, bool>
0526 friend struct detail::split_outer_iterator;
0527 template<typename, bool>
0528 friend struct detail::split_inner_iterator;
0529
0530 V base_ = V();
0531 Pattern pattern_ = Pattern();
0532 template<bool Const>
0533 using outer_iterator = detail::split_outer_iterator<split_view, Const>;
0534
0535 #if RANGES_CXX_IF_CONSTEXPR < RANGES_CXX_IF_CONSTEXPR_17
0536 outer_iterator<simple_view<V>()> begin_(std::true_type)
0537 {
0538 return outer_iterator<simple_view<V>()>{this, ranges::begin(base_)};
0539 }
0540 outer_iterator<false> begin_(std::false_type)
0541 {
0542 this->curr_ = ranges::begin(base_);
0543 return outer_iterator<false>{this};
0544 }
0545
0546 outer_iterator<simple_view<V>()> end_(std::true_type) const
0547 {
0548 return outer_iterator<true>{this, ranges::end(base_)};
0549 }
0550 default_sentinel_t end_(std::false_type) const
0551 {
0552 return default_sentinel;
0553 }
0554 #endif
0555
0556 public:
0557 split_view() = default;
0558
0559 constexpr split_view(V base, Pattern pattern)
0560 : base_((V &&) base)
0561 , pattern_((Pattern &&) pattern)
0562 {}
0563
0564 CPP_member
0565 constexpr CPP_ctor(split_view)(V base, range_value_t<V> e)(
0566 requires constructible_from<Pattern, range_value_t<V>>)
0567 : base_(std::move(base))
0568 , pattern_(e)
0569 {}
0570
0571 constexpr V base() const
0572 {
0573 return base_;
0574 }
0575
0576 constexpr outer_iterator<forward_range<V> && simple_view<V>()> begin()
0577 {
0578 #if RANGES_CXX_IF_CONSTEXPR >= RANGES_CXX_IF_CONSTEXPR_17
0579 if constexpr(forward_range<V>)
0580 return outer_iterator<simple_view<V>()>{this, ranges::begin(base_)};
0581 else
0582 {
0583 this->curr_ = ranges::begin(base_);
0584 return outer_iterator<false>{this};
0585 }
0586 #else
0587 return begin_(meta::bool_<forward_range<V>>{});
0588 #endif
0589 }
0590 CPP_member
0591 constexpr auto begin() const
0592 -> CPP_ret(outer_iterator<true>)(
0593 requires forward_range<V> && forward_range<const V>)
0594 {
0595 return {this, ranges::begin(base_)};
0596 }
0597 CPP_member
0598 constexpr auto end()
0599 -> CPP_ret(outer_iterator<simple_view<V>()>)(
0600 requires forward_range<V> && common_range<V>)
0601 {
0602 return outer_iterator<simple_view<V>()>{this, ranges::end(base_)};
0603 }
0604 constexpr auto end() const
0605 {
0606 #if RANGES_CXX_IF_CONSTEXPR >= RANGES_CXX_IF_CONSTEXPR_17
0607 if constexpr(forward_range<V> && forward_range<const V> &&
0608 common_range<const V>)
0609 return outer_iterator<true>{this, ranges::end(base_)};
0610 else
0611 return default_sentinel;
0612 #else
0613 return end_(meta::bool_ < forward_range<V> && forward_range<const V> &&
0614 common_range<const V> > {});
0615 #endif
0616 }
0617 };
0618
0619 #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
0620 template(typename R, typename P)(
0621 requires input_range<R> AND forward_range<P> AND viewable_range<R> AND
0622 viewable_range<P> AND
0623 indirectly_comparable<iterator_t<R>, iterator_t<P>, ranges::equal_to> AND
0624 (forward_range<R> || detail::tiny_range<P>))
0625 split_view(R &&, P &&)
0626 ->split_view<views::all_t<R>, views::all_t<P>>;
0627
0628 template(typename R)(
0629 requires input_range<R>)
0630 split_view(R &&, range_value_t<R>)
0631 ->split_view<views::all_t<R>, single_view<range_value_t<R>>>;
0632 #endif
0633
0634 namespace views
0635 {
0636 struct split_base_fn
0637 {
0638 template(typename Rng)(
0639 requires viewable_range<Rng> AND input_range<Rng> AND
0640 indirectly_comparable<iterator_t<Rng>,
0641 range_value_t<Rng> const *,
0642 ranges::equal_to>)
0643 constexpr split_view<all_t<Rng>, single_view<range_value_t<Rng>>>
0644 operator()(Rng && rng, range_value_t<Rng> val) const
0645 {
0646 return {all(static_cast<Rng &&>(rng)), single(std::move(val))};
0647 }
0648
0649 template(typename Rng, typename Pattern)(
0650 requires viewable_range<Rng> AND input_range<Rng> AND
0651 viewable_range<Pattern> AND forward_range<Pattern> AND
0652 indirectly_comparable<
0653 iterator_t<Rng>,
0654 iterator_t<Pattern>,
0655 ranges::equal_to> AND
0656 (forward_range<Rng> || detail::tiny_range<Pattern>))
0657 constexpr split_view<all_t<Rng>, all_t<Pattern>>
0658 operator()(Rng && rng, Pattern && pattern) const
0659 {
0660 return {all((Rng &&) rng), all((Pattern &&) pattern)};
0661 }
0662 };
0663
0664 struct split_fn : split_base_fn
0665 {
0666 using split_base_fn::operator();
0667
0668 template<typename T>
0669 constexpr auto operator()(T t) const
0670 {
0671 return make_view_closure(bind_back(split_base_fn{}, std::move(t)));
0672 }
0673 };
0674
0675
0676
0677 RANGES_INLINE_VARIABLE(split_fn, split)
0678 }
0679
0680 namespace cpp20
0681 {
0682 namespace views
0683 {
0684 using ranges::views::split;
0685 }
0686 template(typename Rng, typename Pattern)(
0687 requires input_range<Rng> AND forward_range<Pattern> AND view_<Rng> AND
0688 view_<Pattern> AND
0689 indirectly_comparable<
0690 iterator_t<Rng>,
0691 iterator_t<Pattern>,
0692 ranges::equal_to> AND
0693 (forward_range<Rng> || ranges::detail::tiny_range<Pattern>))
0694 using split_view =
0695 ranges::split_view<Rng, Pattern>;
0696 }
0697
0698
0699 }
0700
0701 #include <range/v3/detail/epilogue.hpp>
0702
0703 #include <range/v3/detail/satisfy_boost_range.hpp>
0704 RANGES_SATISFY_BOOST_RANGE(::ranges::split_view)
0705
0706 #endif