namespace std::ranges {
template<input_range V>
requires view<V> && input_range<range_reference_t<V>> &&
(is_reference_v<range_reference_t<V>> ||
view<range_value_t<V>>)
template<bool Const>
struct join_view<V>::iterator {
private:
using Parent =
conditional_t<Const, const join_view, join_view>;
using Base = conditional_t<Const, const V, V>;
static constexpr bool ref-is-glvalue =
is_reference_v<range_reference_t<Base>>;
iterator_t<Base> outer_ = iterator_t<Base>();
iterator_t<range_reference_t<Base>> inner_ =
iterator_t<range_reference_t<Base>>();
Parent* parent_ = nullptr;
constexpr void satisfy();
public:
using iterator_concept = see below;
using iterator_category = see below;
using value_type = range_value_t<range_reference_t<Base>>;
using difference_type = see below;
iterator() = default;
constexpr iterator(Parent& parent, iterator_t<Base> outer);
constexpr iterator(iterator<!Const> i)
requires Const &&
convertible_to<iterator_t<V>, iterator_t<Base>> &&
convertible_to<iterator_t<InnerRng>,
iterator_t<range_reference_t<Base>>>;
constexpr decltype(auto) operator*() const { return *inner_; }
constexpr iterator_t<Base> operator->() const
requires has-arrow<iterator_t<Base>> && copyable<iterator_t<Base>>;
constexpr iterator& operator++();
constexpr void operator++(int);
constexpr iterator operator++(int)
requires ref-is-glvalue && forward_range<Base> &&
forward_range<range_reference_t<Base>>;
constexpr iterator& operator--()
requires ref-is-glvalue && bidirectional_range<Base> &&
bidirectional_range<range_reference_t<Base>> &&
common_range<range_reference_t<Base>>;
constexpr iterator operator--(int)
requires ref-is-glvalue && bidirectional_range<Base> &&
bidirectional_range<range_reference_t<Base>> &&
common_range<range_reference_t<Base>>;
friend constexpr bool operator==(const iterator& x, const iterator& y)
requires ref-is-glvalue && equality_comparable<iterator_t<Base>> &&
equality_comparable<iterator_t<range_reference_t<Base>>>;
friend constexpr decltype(auto) iter_move(const iterator& i)
noexcept(noexcept(ranges::iter_move(i.inner_))) {
return ranges::iter_move(i.inner_);
}
friend constexpr void iter_swap(const iterator& x, const iterator& y)
noexcept(noexcept(ranges::iter_swap(x.inner_, y.inner_)));
};
}
iterator::iterator_concept is defined as follows:
- If ref-is-glvalue is true and
Base and range_reference_t<Base> each model
bidirectional_range, then iterator_concept denotes
bidirectional_iterator_tag.
- Otherwise, if ref-is-glvalue is true and
Base and range_reference_t<Base>
each model forward_range, then iterator_concept denotes
forward_iterator_tag.
- Otherwise, iterator_concept denotes input_iterator_tag.
iterator::iterator_category is defined as follows:
- Let OUTERC denote
iterator_traits<iterator_t<Base>>::iterator_category, and
let INNERC denote
iterator_traits<iterator_t<range_reference_t<Base>>>::iterator_category.
- If ref-is-glvalue is true and
OUTERC and INNERC each model
derived_from<bidirectional_iterator_tag>, iterator_category
denotes bidirectional_iterator_tag.
- Otherwise, if ref-is-glvalue is true and
OUTERC and INNERC each model
derived_from<forward_iterator_tag>, iterator_category
denotes forward_iterator_tag.
- Otherwise, if OUTERC and INNERC each model
derived_from<input_iterator_tag>,
iterator_category denotes input_iterator_tag.
- Otherwise, iterator_category denotes output_iterator_tag.
iterator::difference_type denotes the type:
common_type_t<
range_difference_t<Base>,
range_difference_t<range_reference_t<Base>>>
join_view iterators use the
satisfy function to skip over
empty inner ranges
. constexpr void satisfy();
Effects: Equivalent to:
auto update_inner = [this](range_reference_t<Base> x) -> auto& {
if constexpr (ref-is-glvalue)
return x;
else
return (parent_->inner_ = views::all(std::move(x)));
};
for (; outer_ != ranges::end(parent_->base_); ++outer_) {
auto& inner = update_inner(*outer_);
inner_ = ranges::begin(inner);
if (inner_ != ranges::end(inner))
return;
}
if constexpr (ref-is-glvalue)
inner_ = iterator_t<range_reference_t<Base>>();
constexpr iterator(Parent& parent, iterator_t<Base> outer);
Effects: Initializes
outer_ with
std::move(outer) and
parent_ with
addressof(parent); then calls
satisfy(). constexpr iterator(iterator<!Const> i)
requires Const &&
convertible_to<iterator_t<V>, iterator_t<Base>> &&
convertible_to<iterator_t<InnerRng>,
iterator_t<range_reference_t<Base>>>;
Effects: Initializes
outer_ with
std::move(i.outer_),
inner_ with
std::move(i.inner_), and
parent_ with
i.parent_. constexpr iterator_t<Base> operator->() const
requires has-arrow<iterator_t<Base>> && copyable<iterator_t<Base>>;
Effects: Equivalent to return inner_;
constexpr iterator& operator++();
Let
inner-range be:
- If ref-is-glvalue is true, *outer_.
- Otherwise, parent_->inner_.
Effects: Equivalent to:
auto&& inner_rng = inner-range;
if (++inner_ == ranges::end(inner_rng)) {
++outer_;
satisfy();
}
return *this;
constexpr void operator++(int);
Effects: Equivalent to:
++*this. constexpr iterator operator++(int)
requires ref-is-glvalue && forward_range<Base> &&
forward_range<range_reference_t<Base>>;
Effects: Equivalent to:
auto tmp = *this;
++*this;
return tmp;
constexpr iterator& operator--()
requires ref-is-glvalue && bidirectional_range<Base> &&
bidirectional_range<range_reference_t<Base>> &&
common_range<range_reference_t<Base>>;
Effects: Equivalent to:
if (outer_ == ranges::end(parent_->base_))
inner_ = ranges::end(*--outer_);
while (inner_ == ranges::begin(*outer_))
inner_ = ranges::end(*--outer_);
--inner_;
return *this;
constexpr iterator operator--(int)
requires ref-is-glvalue && bidirectional_range<Base> &&
bidirectional_range<range_reference_t<Base>> &&
common_range<range_reference_t<Base>>;
Effects: Equivalent to:
auto tmp = *this;
--*this;
return tmp;
friend constexpr bool operator==(const iterator& x, const iterator& y)
requires ref-is-glvalue && equality_comparable<iterator_t<Base>> &&
equality_comparable<iterator_t<range_reference_t<Base>>>;
Effects: Equivalent to:
return x.outer_ == y.outer_ && x.inner_ == y.inner_;
friend constexpr void iter_swap(const iterator& x, const iterator& y)
noexcept(noexcept(ranges::iter_swap(x.inner_, y.inner_)));
Effects: Equivalent to: return ranges::iter_swap(x.inner_, y.inner_);