26 Ranges library [ranges]

26.7 Range adaptors [range.adaptors]

26.7.24 Chunk view [range.chunk]

26.7.24.1 Overview [range.chunk.overview]

chunk_­view takes a view and a number N and produces a range of views that are N-sized non-overlapping successive chunks of the elements of the original view, in order.
The last view in the range can have fewer than N elements.
The name views​::​chunk denotes a range adaptor object ([range.adaptor.object]).
Given subexpressions E and N, the expression views​::​chunk(E, N) is expression-equivalent to chunk_­view(E, N).
[Example 1: vector v = {1, 2, 3, 4, 5}; for (auto r : v | views::chunk(2)) { cout << '['; auto sep = ""; for (auto i : r) { cout << sep << i; sep = ", "; } cout << "] "; } // The above prints [1, 2] [3, 4] [5] — end example]

26.7.24.2 chunk_­view for input ranges [range.chunk.view.input]

namespace std::ranges { template<class I> constexpr I div-ceil(I num, I denom) { // exposition only I r = num / denom; if (num % denom) ++r; return r; } template<view V> requires input_­range<V> class chunk_view : public view_interface<chunk_view<V>> { V base_ = V(); // exposition only range_difference_t<V> n_ = 0; // exposition only range_difference_t<V> remainder_ = 0; // exposition only non-propagating-cache<iterator_t<V>> current_; // exposition only // [range.chunk.outer.iter], class chunk_­view​::​outer-iterator class outer-iterator; // exposition only // [range.chunk.inner.iter], class chunk_­view​::​inner-iterator class inner-iterator; // exposition only public: chunk_view() requires default_­initializable<V> = default; constexpr explicit chunk_view(V base, range_difference_t<V> n); constexpr V base() const & requires copy_­constructible<V> { return base_; } constexpr V base() && { return std::move(base_); } constexpr outer-iterator begin(); constexpr default_sentinel_t end() noexcept; constexpr auto size() requires sized_­range<V>; constexpr auto size() const requires sized_­range<const V>; }; template<class R> chunk_view(R&& r, range_difference_t<R>) -> chunk_view<views::all_t<R>>; }
constexpr explicit chunk_view(V base, range_difference_t<V> n);
Preconditions: n > 0 is true.
Effects: Initializes base_­ with std​::​move(base) and n_­ with n.
constexpr outer-iterator begin();
Effects: Equivalent to: current_ = ranges::begin(base_); remainder_ = n_; return outer-iterator(*this);
constexpr default_sentinel_t end() noexcept;
Returns: default_­sentinel.
constexpr auto size() requires sized_­range<V>; constexpr auto size() const requires sized_­range<const V>;
Effects: Equivalent to: return to-unsigned-like(div-ceil(ranges::distance(base_), n_));

26.7.24.3 Class chunk_­view​::​outer-iterator [range.chunk.outer.iter]

namespace std::ranges { template<view V> requires input_­range<V> class chunk_view<V>::outer-iterator { chunk_view* parent_; // exposition only constexpr explicit outer-iterator(chunk_view& parent); // exposition only public: using iterator_concept = input_iterator_tag; using difference_type = range_difference_t<V>; // [range.chunk.outer.value], class chunk_­view​::​outer-iterator​::​value_­type struct value_type; outer-iterator(outer-iterator&&) = default; outer-iterator& operator=(outer-iterator&&) = default; constexpr value_type operator*() const; constexpr outer-iterator& operator++(); constexpr void operator++(int); friend constexpr bool operator==(const outer-iterator& x, default_sentinel_t); friend constexpr difference_type operator-(default_sentinel_t y, const outer-iterator& x) requires sized_­sentinel_­for<sentinel_t<V>, iterator_t<V>>; friend constexpr difference_type operator-(const outer-iterator& x, default_sentinel_t y) requires sized_­sentinel_­for<sentinel_t<V>, iterator_t<V>>; }; }
constexpr explicit outer-iterator(chunk_view& parent);
Effects: Initializes parent_­ with addressof(parent).
constexpr value_type operator*() const;
Preconditions: *this == default_­sentinel is false.
Returns: value_­type(*parent_­).
constexpr outer-iterator& operator++();
Preconditions: *this == default_­sentinel is false.
Effects: Equivalent to: ranges::advance(*parent_->current_, parent_->remainder_, ranges::end(parent_->base_)); parent_->remainder_ = parent_->n_; return *this;
constexpr void operator++(int);
Effects: Equivalent to ++*this.
friend constexpr bool operator==(const outer-iterator& x, default_sentinel_t);
Effects: Equivalent to: return *x.parent_->current_ == ranges::end(x.parent_->base_) && x.parent_->remainder_ != 0;
friend constexpr difference_type operator-(default_sentinel_t y, const outer-iterator& x) requires sized_­sentinel_­for<sentinel_t<V>, iterator_t<V>>;
Effects: Equivalent to: const auto dist = ranges::end(x.parent_->base_) - *x.parent_->current_; if (dist < x.parent_->remainder_) { return dist == 0 ? 0 : 1; } return div-ceil(dist - x.parent_->remainder_, x.parent_->n_) + 1;
friend constexpr difference_type operator-(const outer-iterator& x, default_sentinel_t y) requires sized_­sentinel_­for<sentinel_t<V>, iterator_t<V>>;
Effects: Equivalent to: return -(y - x);

26.7.24.4 Class chunk_­view​::​outer-iterator​::​value_­type [range.chunk.outer.value]

namespace std::ranges { template<view V> requires input_­range<V> struct chunk_view<V>::outer-iterator::value_type : view_interface<value_type> { private: chunk_view* parent_; // exposition only constexpr explicit value_type(chunk_view& parent); // exposition only public: constexpr inner-iterator begin() const noexcept; constexpr default_sentinel_t end() const noexcept; constexpr auto size() const requires sized_­sentinel_­for<sentinel_t<V>, iterator_t<V>>; }; }
constexpr explicit value_type(chunk_view& parent);
Effects: Initializes parent_­ with addressof(parent).
constexpr inner-iterator begin() const noexcept;
Returns: inner-iterator(*parent_­).
constexpr default_sentinel_t end() const noexcept;
Returns: default_­sentinel.
constexpr auto size() const requires sized_­sentinel_­for<sentinel_t<V>, iterator_t<V>>;
Effects: Equivalent to: return ranges::min(parent_->remainder_, ranges::end(parent_->base_) - *parent_->current_);

26.7.24.5 Class chunk_­view​::​inner-iterator [range.chunk.inner.iter]

namespace std::ranges { template<view V> requires input_­range<V> class chunk_view<V>::inner-iterator { chunk_view* parent_; // exposition only constexpr explicit inner-iterator(chunk_view& parent) noexcept; // exposition only public: using iterator_concept = input_iterator_tag; using difference_type = range_difference_t<V>; using value_type = range_value_t<V>; inner-iterator(inner-iterator&&) = default; inner-iterator& operator=(inner-iterator&&) = default; constexpr const iterator_t<V>& base() const &; constexpr range_reference_t<V> operator*() const; constexpr inner-iterator& operator++(); constexpr void operator++(int); friend constexpr bool operator==(const inner-iterator& x, default_sentinel_t); friend constexpr difference_type operator-(default_sentinel_t y, const inner-iterator& x) requires sized_­sentinel_­for<sentinel_t<V>, iterator_t<V>>; friend constexpr difference_type operator-(const inner-iterator& x, default_sentinel_t y) requires sized_­sentinel_­for<sentinel_t<V>, iterator_t<V>>; }; }
constexpr explicit inner-iterator(chunk_view& parent) noexcept;
Effects: Initializes parent_­ with addressof(parent).
constexpr const iterator_t<V>& base() const &;
Effects: Equivalent to: return *parent_­->current_­;
constexpr range_reference_t<V> operator*() const;
Preconditions: *this == default_­sentinel is false.
Effects: Equivalent to: return **parent_­->current_­;
constexpr inner-iterator& operator++();
Preconditions: *this == default_­sentinel is false.
Effects: Equivalent to: ++*parent_->current_; if (*parent_->current_ == ranges::end(parent_->base_)) parent_->remainder_ = 0; else --parent_->remainder_; return *this;
constexpr void operator++(int);
Effects: Equivalent to ++*this.
friend constexpr bool operator==(const inner-iterator& x, default_sentinel_t);
Returns: x.parent_­->remainder_­ == 0.
friend constexpr difference_type operator-(default_sentinel_t y, const inner-iterator& x) requires sized_­sentinel_­for<sentinel_t<V>, iterator_t<V>>;
Effects: Equivalent to: return ranges::min(x.parent_->remainder_, ranges::end(x.parent_->base_) - *x.parent_->current_);
friend constexpr difference_type operator-(const inner-iterator& x, default_sentinel_t y) requires sized_­sentinel_­for<sentinel_t<V>, iterator_t<V>>;
Effects: Equivalent to: return -(y - x);

26.7.24.6 chunk_­view for forward ranges [range.chunk.view.fwd]

namespace std::ranges { template<view V> requires forward_­range<V> class chunk_view<V> : public view_interface<chunk_view<V>> { V base_ = V(); // exposition only range_difference_t<V> n_ = 0; // exposition only // [range.chunk.fwd.iter], class template chunk_­view​::​iterator template<bool> class iterator; // exposition only public: chunk_view() requires default_­initializable<V> = default; constexpr explicit chunk_view(V base, range_difference_t<V> n); constexpr V base() const & requires copy_­constructible<V> { return base_; } constexpr V base() && { return std::move(base_); } constexpr auto begin() requires (!simple-view<V>) { return iterator<false>(this, ranges::begin(base_)); } constexpr auto begin() const requires forward_­range<const V> { return iterator<true>(this, ranges::begin(base_)); } constexpr auto end() requires (!simple-view<V>) { if constexpr (common_­range<V> && sized_­range<V>) { auto missing = (n_ - ranges::distance(base_) % n_) % n_; return iterator<false>(this, ranges::end(base_), missing); } else if constexpr (common_­range<V> && !bidirectional_­range<V>) { return iterator<false>(this, ranges::end(base_)); } else { return default_sentinel; } } constexpr auto end() const requires forward_­range<const V> { if constexpr (common_­range<const V> && sized_­range<const V>) { auto missing = (n_ - ranges::distance(base_) % n_) % n_; return iterator<true>(this, ranges::end(base_), missing); } else if constexpr (common_­range<const V> && !bidirectional_­range<const V>) { return iterator<true>(this, ranges::end(base_)); } else { return default_sentinel; } } constexpr auto size() requires sized_­range<V>; constexpr auto size() const requires sized_­range<const V>; }; }
constexpr explicit chunk_view(V base, range_difference_t<V> n);
Preconditions: n > 0 is true.
Effects: Initializes base_­ with std​::​move(base) and n_­ with n.
constexpr auto size() requires sized_­range<V>; constexpr auto size() const requires sized_­range<const V>;
Effects: Equivalent to: return to-unsigned-like(div-ceil(ranges::distance(base_), n_));

26.7.24.7 Class template chunk_­view<V>​::​iterator for forward ranges [range.chunk.fwd.iter]

namespace std::ranges { template<view V> requires forward_­range<V> template<bool Const> class chunk_view<V>::iterator { using Parent = maybe-const<Const, chunk_view>; // exposition only using Base = maybe-const<Const, V>; // exposition only iterator_t<Base> current_ = iterator_t<Base>(); // exposition only sentinel_t<Base> end_ = sentinel_t<Base>(); // exposition only range_difference_t<Base> n_ = 0; // exposition only range_difference_t<Base> missing_ = 0; // exposition only constexpr iterator(Parent* parent, iterator_t<Base> current, // exposition only range_difference_t<Base> missing = 0); public: using iterator_category = input_iterator_tag; using iterator_concept = see below; using value_type = decltype(views::take(subrange(current_, end_), n_)); using difference_type = range_difference_t<Base>; iterator() = default; constexpr iterator(iterator<!Const> i) requires Const && convertible_­to<iterator_t<V>, iterator_t<Base>> && convertible_­to<sentinel_t<V>, sentinel_t<Base>>; constexpr iterator_t<Base> base() const; constexpr value_type operator*() const; constexpr iterator& operator++(); constexpr iterator operator++(int); constexpr iterator& operator--() requires bidirectional_­range<Base>; constexpr iterator operator--(int) requires bidirectional_­range<Base>; constexpr iterator& operator+=(difference_type x) requires random_­access_­range<Base>; constexpr iterator& operator-=(difference_type x) requires random_­access_­range<Base>; constexpr value_type operator[](difference_type n) const requires random_­access_­range<Base>; friend constexpr bool operator==(const iterator& x, const iterator& y); friend constexpr bool operator==(const iterator& x, default_sentinel_t); friend constexpr bool operator<(const iterator& x, const iterator& y) requires random_­access_­range<Base>; friend constexpr bool operator>(const iterator& x, const iterator& y) requires random_­access_­range<Base>; friend constexpr bool operator<=(const iterator& x, const iterator& y) requires random_­access_­range<Base>; friend constexpr bool operator>=(const iterator& x, const iterator& y) requires random_­access_­range<Base>; friend constexpr auto operator<=>(const iterator& x, const iterator& y) requires random_­access_­range<Base> && three_­way_­comparable<iterator_t<Base>>; friend constexpr iterator operator+(const iterator& i, difference_type n) requires random_­access_­range<Base>; friend constexpr iterator operator+(difference_type n, const iterator& i) requires random_­access_­range<Base>; friend constexpr iterator operator-(const iterator& i, difference_type n) requires random_­access_­range<Base>; friend constexpr difference_type operator-(const iterator& x, const iterator& y) requires sized_­sentinel_­for<iterator_t<Base>, iterator_t<Base>>; friend constexpr difference_type operator-(default_sentinel_t y, const iterator& x) requires sized_­sentinel_­for<sentinel_t<Base>, iterator_t<Base>>; friend constexpr difference_type operator-(const iterator& x, default_sentinel_t y) requires sized_­sentinel_­for<sentinel_t<Base>, iterator_t<Base>>; }; }
iterator​::​iterator_­concept is defined as follows:
constexpr iterator(Parent* parent, iterator_t<Base> current, range_difference_t<Base> missing = 0);
Effects: Initializes current_­ with current, end_­ with ranges​::​end(parent->base_­), n_­ with parent
->n_­
, and missing_­ with missing.
constexpr iterator(iterator<!Const> i) requires Const && convertible_­to<iterator_t<V>, iterator_t<Base>> && convertible_­to<sentinel_t<V>, sentinel_t<Base>>;
Effects: Initializes current_­ with std​::​move(i.current_­), end_­ with std​::​move(i.end_­), n_­ with i.n_­, and missing_­ with i.missing_­.
constexpr iterator_t<Base> base() const;
Returns: current_­.
constexpr value_type operator*() const;
Preconditions: current_­ != end_­ is true.
Returns: views​::​take(subrange(current_­, end_­), n_­).
constexpr iterator& operator++();
Preconditions: current_­ != end_­ is true.
Effects: Equivalent to: missing_ = ranges::advance(current_, n_, end_); return *this;
constexpr iterator operator++(int);
Effects: Equivalent to: auto tmp = *this; ++*this; return tmp;
constexpr iterator& operator--() requires bidirectional_­range<Base>;
Effects: Equivalent to: ranges::advance(current_, missing_ - n_); missing_ = 0; return *this;
constexpr iterator operator--(int) requires bidirectional_­range<Base>;
Effects: Equivalent to: auto tmp = *this; --*this; return tmp;
constexpr iterator& operator+=(difference_type x) requires random_­access_­range<Base>;
Preconditions: If x is positive, ranges​::​distance(current_­, end_­) > n_­ * (x - 1) is true.
[Note 1:
If x is negative, the Effects paragraph implies a precondition.
— end note]
Effects: Equivalent to: if (x > 0) { missing_ = ranges::advance(current_, n_ * x, end_); } else if (x < 0) { ranges::advance(current_, n_ * x + missing_); missing_ = 0; } return *this;
constexpr iterator& operator-=(difference_type x) requires random_­access_­range<Base>;
Effects: Equivalent to: return *this += -x;
constexpr value_type operator[](difference_type n) const requires random_­access_­range<Base>;
Returns: *(*this + n).
friend constexpr bool operator==(const iterator& x, const iterator& y);
Returns: x.current_­ == y.current_­.
friend constexpr bool operator==(const iterator& x, default_sentinel_t);
Returns: x.current_­ == x.end_­.
friend constexpr bool operator<(const iterator& x, const iterator& y) requires random_­access_­range<Base>;
Returns: x.current_­ < y.current_­.
friend constexpr bool operator>(const iterator& x, const iterator& y) requires random_­access_­range<Base>;
Effects: Equivalent to: return y < x;
friend constexpr bool operator<=(const iterator& x, const iterator& y) requires random_­access_­range<Base>;
Effects: Equivalent to: return !(y < x);
friend constexpr bool operator>=(const iterator& x, const iterator& y) requires random_­access_­range<Base>;
Effects: Equivalent to: return !(x < y);
friend constexpr auto operator<=>(const iterator& x, const iterator& y) requires random_­access_­range<Base> && three_­way_­comparable<iterator_t<Base>>;
Returns: x.current_­ <=> y.current_­.
friend constexpr iterator operator+(const iterator& i, difference_type n) requires random_­access_­range<Base>; friend constexpr iterator operator+(difference_type n, const iterator& i) requires random_­access_­range<Base>;
Effects: Equivalent to: auto r = i; r += n; return r;
friend constexpr iterator operator-(const iterator& i, difference_type n) requires random_­access_­range<Base>;
Effects: Equivalent to: auto r = i; r -= n; return r;
friend constexpr difference_type operator-(const iterator& x, const iterator& y) requires sized_­sentinel_­for<iterator_t<Base>, iterator_t<Base>>;
Returns: (x.current_­ - y.current_­ + x.missing_­ - y.missing_­) / x.n_­.
friend constexpr difference_type operator-(default_sentinel_t y, const iterator& x) requires sized_­sentinel_­for<sentinel_t<Base>, iterator_t<Base>>;
Returns: div-ceil(x.end_­ - x.current_­, x.n_­).
friend constexpr difference_type operator-(const iterator& x, default_sentinel_t y) requires sized_­sentinel_­for<sentinel_t<Base>, iterator_t<Base>>;
Effects: Equivalent to: return -(y - x);