25 Ranges library [ranges]

25.7 Range adaptors [range.adaptors]

25.7.15 Join with view [range.join.with]

25.7.15.3 Class template join_with_view​::​iterator [range.join.with.iterator]

namespace std::ranges { template<input_range V, forward_range Pattern> requires view<V> && input_range<range_reference_t<V>> && view<Pattern> && concatable<range_reference_t<V>, Pattern> template<bool Const> class join_with_view<V, Pattern>::iterator { using Parent = maybe-const<Const, join_with_view>; // exposition only using Base = maybe-const<Const, V>; // exposition only using InnerBase = range_reference_t<Base>; // exposition only using PatternBase = maybe-const<Const, Pattern>; // exposition only using OuterIter = iterator_t<Base>; // exposition only using InnerIter = iterator_t<InnerBase>; // exposition only using PatternIter = iterator_t<PatternBase>; // exposition only static constexpr bool ref-is-glvalue = is_reference_v<InnerBase>; // exposition only Parent* parent_ = nullptr; // exposition only OuterIter outer_it_ = OuterIter(); // exposition only, present only // if Base models forward_range variant<PatternIter, InnerIter> inner_it_; // exposition only constexpr iterator(Parent& parent, OuterIter outer) requires forward_range<Base>; // exposition only constexpr explicit iterator(Parent& parent) requires (!forward_range<Base>); // exposition only constexpr OuterIter& outer(); // exposition only constexpr const OuterIter& outer() const; // exposition only constexpr auto& update-inner(); // exposition only constexpr auto& get-inner(); // exposition only constexpr void satisfy(); // exposition only public: using iterator_concept = see below; using iterator_category = see below; // not always present using value_type = see below; using difference_type = see below; iterator() = default; constexpr iterator(iterator<!Const> i) requires Const && convertible_to<iterator_t<V>, OuterIter> && convertible_to<iterator_t<InnerRng>, InnerIter> && convertible_to<iterator_t<Pattern>, PatternIter>; constexpr decltype(auto) operator*() const; constexpr iterator& operator++(); constexpr void operator++(int); constexpr iterator operator++(int) requires ref-is-glvalue && forward_iterator<OuterIter> && forward_iterator<InnerIter>; constexpr iterator& operator--() requires ref-is-glvalue && bidirectional_range<Base> && bidirectional-common<InnerBase> && bidirectional-common<PatternBase>; constexpr iterator operator--(int) requires ref-is-glvalue && bidirectional_range<Base> && bidirectional-common<InnerBase> && bidirectional-common<PatternBase>; friend constexpr bool operator==(const iterator& x, const iterator& y) requires ref-is-glvalue && forward_range<Base> && equality_comparable<InnerIter>; friend constexpr decltype(auto) iter_move(const iterator& x) { using rvalue_reference = common_reference_t< iter_rvalue_reference_t<InnerIter>, iter_rvalue_reference_t<PatternIter>>; return visit<rvalue_reference>(ranges::iter_move, x.inner_it_); } friend constexpr void iter_swap(const iterator& x, const iterator& y) requires indirectly_swappable<InnerIter, PatternIter> { visit(ranges::iter_swap, x.inner_it_, y.inner_it_); } }; }
iterator​::​iterator_concept is defined as follows:
  • If ref-is-glvalue is true, Base models bidirectional_range, and InnerBase and PatternBase each model bidirectional-common, then iterator_concept denotes bidirectional_iterator_tag.
  • Otherwise, if ref-is-glvalue is true and Base and InnerBase each model forward_range, then iterator_concept denotes forward_iterator_tag.
  • Otherwise, iterator_concept denotes input_iterator_tag.
The member typedef-name iterator_category is defined if and only if ref-is-glvalue is true, and Base and InnerBase each model forward_range.
In that case, iterator​::​iterator_category is defined as follows:
  • Let OUTERC denote iterator_traits<OuterIter>​::​iterator_category, let INNERC denote iterator_traits<InnerIter>​::​iterator_category, and let PATTERNC denote iterator_traits<PatternIter>​::​iterator_category.
  • If is_reference_v<common_reference_t<iter_reference_t<InnerIter>, iter_reference_t<PatternIter>>> is false, iterator_category denotes input_iterator_tag.
  • Otherwise, if OUTERC, INNERC, and PATTERNC each model derived_from<bidirectional_iterator_tag> and InnerBase and PatternBase each model common_range, iterator_category denotes bidirectional_iterator_tag.
  • Otherwise, if OUTERC, INNERC, and PATTERNC each model derived_from<forward_iterator_tag>, iterator_category denotes forward_iterator_tag.
  • Otherwise, iterator_category denotes input_iterator_tag.
iterator​::​value_type denotes the type: common_type_t<iter_value_t<InnerIter>, iter_value_t<PatternIter>>
iterator​::​difference_type denotes the type: common_type_t< iter_difference_t<OuterIter>, iter_difference_t<InnerIter>, iter_difference_t<PatternIter>>
constexpr OuterIter& outer(); constexpr const OuterIter& outer() const;
Returns: outer_it_ if Base models forward_range; otherwise, *parent_->outer_it_.
constexpr auto& update-inner();
Effects: Equivalent to: if constexpr (ref-is-glvalue) return as-lvalue(*outer()); else return parent_->inner_.emplace-deref(outer());
constexpr auto& get-inner();
Effects: Equivalent to: if constexpr (ref-is-glvalue) return as-lvalue(*outer()); else return *parent_->inner_;
constexpr void satisfy();
Effects: Equivalent to: while (true) { if (inner_it_.index() == 0) { if (std::get<0>(inner_it_) != ranges::end(parent_->pattern_)) break; inner_it_.template emplace<1>(ranges::begin(update-inner())); } else { if (std::get<1>(inner_it_) != ranges::end(get-inner())) break; if (++outer() == ranges::end(parent_->base_)) { if constexpr (ref-is-glvalue) inner_it_.template emplace<0>(); break; } inner_it_.template emplace<0>(ranges::begin(parent_->pattern_)); } }
[Note 1: 
join_with_view iterators use the satisfy function to skip over empty inner ranges.
— end note]
constexpr iterator(Parent& parent, OuterIter outer) requires forward_range<Base>; constexpr explicit iterator(Parent& parent) requires (!forward_range<Base>);
Effects: Initializes parent_ with addressof(parent).
For the first overload, also initializes outer_it_ with std​::​move(outer).
Then, equivalent to: if (outer() != ranges::end(parent_->base_)) { inner_it_.template emplace<1>(ranges::begin(update-inner())); satisfy(); }
constexpr iterator(iterator<!Const> i) requires Const && convertible_to<iterator_t<V>, OuterIter> && convertible_to<iterator_t<InnerRng>, InnerIter> && convertible_to<iterator_t<Pattern>, PatternIter>;
Effects: Initializes outer_it_ with std​::​move(i.outer_it_) and parent_ with i.parent_.
Then, equivalent to: if (i.inner_it_.index() == 0) inner_it_.template emplace<0>(std::get<0>(std::move(i.inner_it_))); else inner_it_.template emplace<1>(std::get<1>(std::move(i.inner_it_)));
[Note 2: 
Const can only be true when Base models forward_range.
— end note]
constexpr decltype(auto) operator*() const;
Effects: Equivalent to: using reference = common_reference_t<iter_reference_t<InnerIter>, iter_reference_t<PatternIter>>; return visit([](auto& it) -> reference { return *it; }, inner_it_);
constexpr iterator& operator++();
Effects: Equivalent to: visit([](auto& it){ ++it; }, inner_it_); satisfy(); return *this;
constexpr void operator++(int);
Effects: Equivalent to ++*this.
constexpr iterator operator++(int) requires ref-is-glvalue && forward_iterator<OuterIter> && forward_iterator<InnerIter>;
Effects: Equivalent to: iterator tmp = *this; ++*this; return tmp;
constexpr iterator& operator--() requires ref-is-glvalue && bidirectional_range<Base> && bidirectional-common<InnerBase> && bidirectional-common<PatternBase>;
Effects: Equivalent to: if (outer_it_ == ranges::end(parent_->base_)) { auto&& inner = *--outer_it_; inner_it_.template emplace<1>(ranges::end(inner)); } while (true) { if (inner_it_.index() == 0) { auto& it = std::get<0>(inner_it_); if (it == ranges::begin(parent_->pattern_)) { auto&& inner = *--outer_it_; inner_it_.template emplace<1>(ranges::end(inner)); } else { break; } } else { auto& it = std::get<1>(inner_it_); auto&& inner = *outer_it_; if (it == ranges::begin(inner)) { inner_it_.template emplace<0>(ranges::end(parent_->pattern_)); } else { break; } } } visit([](auto& it){ --it; }, inner_it_); return *this;
constexpr iterator operator--(int) requires ref-is-glvalue && bidirectional_range<Base> && bidirectional-common<InnerBase> && bidirectional-common<PatternBase>;
Effects: Equivalent to: iterator tmp = *this; --*this; return tmp;
friend constexpr bool operator==(const iterator& x, const iterator& y) requires ref-is-glvalue && forward_range<Base> && equality_comparable<InnerIter>;
Effects: Equivalent to: return x.outer_it_ == y.outer_it_ && x.inner_it_ == y.inner_it_;