Files
2025-10-25 03:02:53 +03:00

25 KiB
Raw Permalink Blame History

[range.lazy.split]

25 Ranges library [ranges]

25.7 Range adaptors [range.adaptors]

25.7.16 Lazy split view [range.lazy.split]

25.7.16.1 Overview [range.lazy.split.overview]

1

#

lazy_split_view takes a view and a delimiter, and splits the view into subranges on the delimiter.

The delimiter can be a single element or a view of elements.

2

#

The name views::lazy_split denotes a range adaptor object ([range.adaptor.object]).

Given subexpressions E and F, the expression views::lazy_split(E, F) is expression-equivalent tolazy_split_view(E, F).

3

#

[Example 1: string str{"the quick brown fox"};for (auto word : str | views::lazy_split(' ')) {for (char ch : word) cout << ch; cout << '';}// The above prints thequickbrownfox* — end example]

25.7.16.2 Class template lazy_split_view [range.lazy.split.view]

🔗

namespace std::ranges {template struct require-constant; // exposition onlytemplateconcept tiny-range = // exposition onlysized_range &&requires { typename require-constant<remove_reference_t::size()>; } &&(remove_reference_t::size() <= 1); template<input_range V, forward_range Pattern>requires view && view &&indirectly_comparable<iterator_t, iterator_t, ranges::equal_to> &&(forward_range || tiny-range)class lazy_split_view : public view_interface<lazy_split_view<V, Pattern>> {private: V base_ = V(); // exposition only Pattern pattern_ = Pattern(); // exposition only**non-propagating-cache<iterator_t> current_; // exposition only, present only// if forward_range is false// [range.lazy.split.outer], class template lazy_split_view::outer-iteratortemplate struct outer-iterator; // exposition only// [range.lazy.split.inner], class template lazy_split_view::inner-iteratortemplate struct inner-iterator; // exposition onlypublic: lazy_split_view()requires default_initializable && default_initializable = default; constexpr explicit lazy_split_view(V base, Pattern pattern); template<input_range R>requires constructible_from<V, views::all_t> &&constructible_from<Pattern, single_view<range_value_t>>constexpr explicit lazy_split_view(R&& r, range_value_t e); constexpr V base() const & requires copy_constructible { return base_; }constexpr V base() && { return std::move(base_); }constexpr auto begin() {if constexpr (forward_range) {return outer-iterator<simple-view && simple-view>{*this, ranges::begin(base_)}; } else {current_ = ranges::begin(base_); return outer-iterator{*this}; }}constexpr auto begin() const requires forward_range && forward_range {return outer-iterator{*this, ranges::begin(base_)}; }constexpr auto end() requires forward_range && common_range {return outer-iterator<simple-view && simple-view>{*this, ranges::end(base_)}; }constexpr auto end() const {if constexpr (forward_range && forward_range && common_range)return outer-iterator{*this, ranges::end(base_)}; elsereturn default_sentinel; }}; template<class R, class P> lazy_split_view(R&&, P&&) -> lazy_split_view<views::all_t, views::all_t

>; template<input_range R> lazy_split_view(R&&, range_value_t)-> lazy_split_view<views::all_t, single_view<range_value_t>>;}

🔗

constexpr explicit lazy_split_view(V base, Pattern pattern);

1

#

Effects: Initializes base_ with std::move(base), andpattern_ with std::move(pattern).

🔗

template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") R> requires [constructible_from](concept.constructible#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<V, views::all_t<R>> && [constructible_from](concept.constructible#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<Pattern, single_view<range_value_t<R>>> constexpr explicit lazy_split_view(R&& r, range_value_t<R> e);

2

#

Effects: Initializes base_ with views::all(std::forward(r)), andpattern_ with views::single(std::move(e)).

25.7.16.3 Class template lazy_split_view::outer-iterator [range.lazy.split.outer]

🔗

namespace std::ranges {template<input_range V, forward_range Pattern>requires view && view &&indirectly_comparable<iterator_t, iterator_t, ranges::equal_to> &&(forward_range || tiny-range)templatestruct lazy_split_view<V, Pattern>::outer-iterator {private:using Parent = maybe-const<Const, lazy_split_view>; // exposition onlyusing Base = maybe-const<Const, V>; // exposition onlyParent parent_ = nullptr; // exposition only iterator_t<Base> current_ = iterator_t<Base>(); // exposition only, present only// if V models forward_rangebool trailing_empty_ = false; // exposition onlypublic:using iterator_concept = conditional_t<forward_range<Base>, forward_iterator_tag, input_iterator_tag>; using iterator_category = input_iterator_tag; // present only if Base// models forward_range// [range.lazy.split.outer.value], class lazy_split_view::outer-iterator::value_typestruct value_type; using difference_type = range_difference_t<Base>; outer-iterator() = default; constexpr explicit outer-iterator(Parent& parent)requires (forward_range<Base>); constexpr outer-iterator(Parent& parent, iterator_t<Base> current)requires forward_range<Base>; constexpr outer-iterator(outer-iterator i)requires Const && convertible_to<iterator_t, iterator_t<Base>>; constexpr value_type operator() const; constexpr outer-iterator& operator++(); constexpr decltype(auto) operator++(int) {if constexpr (forward_range<Base>) {auto tmp = *this; ++*this; return tmp; } else++*this; }friend constexpr bool operator==(const outer-iterator& x, const outer-iterator& y)requires forward_range<Base>; friend constexpr bool operator==(const outer-iterator& x, default_sentinel_t); };}

1

#

Many of the specifications in [range.lazy.split] refer to the notional membercurrent of outer-iterator.

current is equivalent to current_ if V models forward_range, and **parent_*->current_ otherwise.

🔗

constexpr explicit outer-iterator(Parent& parent) requires (![forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<Base>);

2

#

Effects: Initializes parent_ with addressof(parent).

🔗

constexpr outer-iterator(Parent& parent, iterator_t<Base> current) requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<Base>;

3

#

Effects: Initializes parent_ with addressof(parent) and current_ with std::move(current).

🔗

constexpr outer-iterator(outer-iterator<!Const> i) requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<iterator_t<V>, iterator_t<Base>>;

4

#

Effects: Initializes parent_ with i.parent_,current_ with std::move(i.current_), andtrailing_empty_ with i.trailing_empty_.

🔗

constexpr value_type operator*() const;

5

#

Effects: Equivalent to: return value_type{*this};

🔗

constexpr outer-iterator& operator++();

6

#

Effects: Equivalent to:const auto end = ranges::end(parent_->base_);if (current == end) {trailing_empty_ = false; return *this;}const auto [pbegin, pend] = subrange{parent_->pattern_};if (pbegin == pend) ++current;else if constexpr (tiny-range) {current = ranges::find(std::move(current), end, *pbegin); if (current != end) {++current; if (current == end)trailing_empty_ = true; }}else {do {auto [b, p] = ranges::mismatch(current, end, pbegin, pend); if (p == pend) {current = b; if (current == end)trailing_empty_ = true; break; // The pattern matched; skip it}} while (++current != end);}return *this;

🔗

friend constexpr bool operator==(const outer-iterator& x, const outer-iterator& y) requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<Base>;

7

#

Effects: Equivalent to:return x.current_ == y.current_ && x.trailing_empty_ == y.trailing_empty_;

🔗

friend constexpr bool operator==(const outer-iterator& x, default_sentinel_t);

8

#

Effects: Equivalent to:return x.current == ranges::end(x.parent_->base_) && !x.trailing_empty_;

25.7.16.4 Class lazy_split_view::outer-iterator::value_type [range.lazy.split.outer.value]

🔗

namespace std::ranges {template<input_range V, forward_range Pattern>requires view && view &&indirectly_comparable<iterator_t, iterator_t, ranges::equal_to> &&(forward_range || tiny-range)templatestruct lazy_split_view<V, Pattern>::outer-iterator::value_type : view_interface<value_type> {private:outer-iterator i_ = outer-iterator(); // exposition onlyconstexpr explicit value_type(outer-iterator i); // exposition onlypublic:constexpr inner-iterator begin() const; constexpr default_sentinel_t end() const noexcept; };}

🔗

constexpr explicit value_type(outer-iterator i);

1

#

Effects: Initializes i_ with std::move(i).

🔗

constexpr inner-iterator<Const> begin() const;

2

#

Effects: Equivalent to: return inner-iterator{i_};

🔗

constexpr default_sentinel_t end() const noexcept;

3

#

Effects: Equivalent to: return default_sentinel;

25.7.16.5 Class template lazy_split_view::inner-iterator [range.lazy.split.inner]

🔗

namespace std::ranges {template<input_range V, forward_range Pattern>requires view && view &&indirectly_comparable<iterator_t, iterator_t, ranges::equal_to> &&(forward_range || tiny-range)templatestruct lazy_split_view<V, Pattern>::inner-iterator {private:using Base = maybe-const<Const, V>; // exposition only**outer-iterator i_ = outer-iterator(); // exposition onlybool incremented_ = false; // exposition onlypublic:using iterator_concept = typename outer-iterator::iterator_concept; using iterator_category = see below; // present only if Base// models forward_rangeusing value_type = range_value_t<Base>; using difference_type = range_difference_t<Base>; inner-iterator() = default; constexpr explicit inner-iterator(outer-iterator i); constexpr const iterator_t<Base>& base() const & noexcept; constexpr iterator_t<Base> base() && requires forward_range; constexpr decltype(auto) operator*() const { return **i_*.current; }constexpr inner-iterator& operator++(); constexpr decltype(auto) operator++(int) {if constexpr (forward_range<Base>) {auto tmp = *this; ++*this; return tmp; } else++*this; }friend constexpr bool operator==(const inner-iterator& x, const inner-iterator& y)requires forward_range<Base>; friend constexpr bool operator==(const inner-iterator& x, default_sentinel_t); friend constexpr decltype(auto) iter_move(const inner-iterator& i)noexcept(noexcept(ranges::iter_move(i.i_.current))) {return ranges::iter_move(i.i_.current); }friend constexpr void iter_swap(const inner-iterator& x, const inner-iterator& y)noexcept(noexcept(ranges::iter_swap(x.i_.current, y.i_.current)))requires indirectly_swappable<iterator_t<Base>>; };}

1

#

If Base does not model forward_range there is no member iterator_category.

Otherwise, the typedef-name iterator_category denotes:

forward_iterator_tag ifiterator_traits<iterator_t<Base>>::iterator_category modelsderived_from<forward_iterator_tag>;

otherwise, iterator_traits<iterator_t<Base>>::iterator_category.

🔗

constexpr explicit inner-iterator(outer-iterator<Const> i);

2

#

Effects: Initializes i_ with std::move(i).

🔗

constexpr const iterator_t<Base>& base() const & noexcept;

3

#

Effects: Equivalent to: return i_.current;

🔗

constexpr iterator_t<Base> base() && requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<V>;

4

#

Effects: Equivalent to: return std::move(i_.current);

🔗

constexpr inner-iterator& operator++();

5

#

Effects: Equivalent to:incremented_ = true;if constexpr (forward_range<Base>) {if constexpr (Pattern::size() == 0) {return *this; }}++i_.current;return *this;

🔗

friend constexpr bool operator==(const inner-iterator& x, const inner-iterator& y) requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<Base>;

6

#

Effects: Equivalent to: return x.i_.current == y.i_.current;

🔗

friend constexpr bool operator==(const inner-iterator& x, default_sentinel_t);

7

#

Effects: Equivalent to:auto [pcur, pend] = subrange{x.i_.parent_->pattern_};auto end = ranges::end(x.i_.parent_->base_);if constexpr (tiny-range) {const auto & cur = x.i_.current; if (cur == end) return true; if (pcur == pend) return x.incremented_; return *cur == *pcur;} else {auto cur = x.i_.current; if (cur == end) return true; if (pcur == pend) return x.incremented_; do {if (*cur != *pcur) return false; if (++pcur == pend) return true; } while (++cur != end); return false;}

🔗

friend constexpr void iter_swap(const inner-iterator& x, const inner-iterator& y) noexcept(noexcept(ranges::iter_swap(x.i_.current, y.i_.current))) requires [indirectly_swappable](alg.req.ind.swap#concept:indirectly_swappable "24.3.7.4Concept indirectly_­swappable[alg.req.ind.swap]")<iterator_t<Base>>;

8

#

Effects: Equivalent toranges::iter_swap(x.i_.current, y.i_.current).