Skip to content

[2025-02 LWG Motion 3] P3137R3 views::to_input #7692

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
294 changes: 294 additions & 0 deletions source/ranges.tex
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,17 @@
class cache_latest_view;

namespace views { inline constexpr @\unspec@ cache_latest = @\unspec@; }

// \ref{range.to.input}, to input view
template<@\libconcept{input_range}@ V>
requires @\libconcept{view}@<V>
class to_input_view;

template<class V>
constexpr bool enable_borrowed_range<to_input_view<V>> =
enable_borrowed_range<V>;

namespace views { inline constexpr @\unspec@ to_input = @\unspec@; }
}

namespace std {
Expand Down Expand Up @@ -17088,6 +17099,289 @@
\tcode{x.\exposid{end_} - y.\exposid{current_}}.
\end{itemdescr}

\rSec2[range.to.input]{To input view}

\rSec3[range.to.input.overview]{Overview}

\pnum
\tcode{to_input_view} presents a view of an underlying sequence
as an input-only non-common range.
\begin{note}
This is useful to avoid overhead
that can be necessary to provide support for the operations
needed for greater iterator strength.
\end{note}

\pnum
The name \tcode{views::to_input} denotes
a range adaptor object\iref{range.adaptor.object}.
Let \tcode{E} be an expression and let \tcode{T} be \tcode{decltype((E))}.
The expression \tcode{views::to_input(E)} is expression-equivalent to:
\begin{itemize}
\item
\tcode{views::all(E)}
if \tcode{T} models \libconcept{input_range},
does not satisfy \libconcept{common_range}, and
does not satisfy \libconcept{forward_range}.
\item
Otherwise, \tcode{to_input_view(E)}.
\end{itemize}

\rSec3[range.to.input.view]{Class template \tcode{to_input_view}}

\begin{codeblock}
template<@\libconcept{input_range}@ V>
requires @\libconcept{view}@<V>
class to_input_view : public view_interface<to_input_view<V>> {
V @\exposid{base_}@ = V(); // \expos

template<bool Const> class @\exposid{iterator}@; // \expos

public:
to_input_view() requires @\libconcept{default_initializable}@<V> = default;
constexpr explicit to_input_view(V base);

constexpr V base() const & requires @\libconcept{copy_constructible}@<V> { return @\exposid{base_}@; }
constexpr V base() && { return std::move(@\exposid{base_}@); }

constexpr auto begin() requires (!@\exposconcept{simple-view}@<V>);
constexpr auto begin() const requires @\libconcept{range}@<const V>;

constexpr auto end() requires (!@\exposconcept{simple-view}@<V>);
constexpr auto end() const requires @\libconcept{range}@<const V>;

constexpr auto size() requires @\libconcept{sized_range}@<V>;
constexpr auto size() const requires @\libconcept{sized_range}@<const V>;
};

template<class R>
to_input_view(R&&) -> to_input_view<views::all_t<R>>;
\end{codeblock}

\begin{itemdecl}
constexpr explicit to_input_view(V base);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Initializes \exposid{base_} with \tcode{std::move(base)}.
\end{itemdescr}

\begin{itemdecl}
constexpr auto begin() requires (!@\exposconcept{simple-view}@<V>);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to: \tcode{return \exposid{iterator}<false>(ranges::begin(\exposid{base_}));}
\end{itemdescr}

\begin{itemdecl}
constexpr auto begin() const requires @\libconcept{range}@<const V>;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to: \tcode{return \exposid{iterator}<true>(ranges::begin(\exposid{base_}));}
\end{itemdescr}

\begin{itemdecl}
constexpr auto end() requires (!@\exposconcept{simple-view}@<V>);
constexpr auto end() const requires @\libconcept{range}@<const V>;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to: \tcode{return ranges::end(\exposid{base_});}
\end{itemdescr}

\begin{itemdecl}
constexpr auto size() requires @\libconcept{sized_range}@<V>;
constexpr auto size() const requires @\libconcept{sized_range}@<const V>;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to: \tcode{return ranges::size(\exposid{base_});}
\end{itemdescr}

\rSec3[range.to.input.iterator]{Class template \tcode{to_input_view::\exposid{iterator}}}

\begin{codeblock}
namespace std::ranges {
template<@\libconcept{input_range}@ V>
requires @\libconcept{view}@<V>
template<bool Const>
class to_input_view<V>::@\exposid{iterator}@ {
using @\exposid{Base}@ = @\exposid{maybe-const}@<Const, V>; // \expos

iterator_t<@\exposid{Base}@> @\exposid{current_}@ = iterator_t<@\exposid{Base}@>(); // \expos

constexpr explicit @\exposid{iterator}@(iterator_t<@\exposid{Base}@> current); // \expos

public:
using difference_type = range_difference_t<@\exposid{Base}@>;
using value_type = range_value_t<@\exposid{Base}@>;
using iterator_concept = input_iterator_tag;

@\exposid{iterator}@() requires @\libconcept{default_initializable}@<iterator_t<@\exposid{Base}@>> = default;

@\exposid{iterator}@(@\exposid{iterator}@&&) = default;
@\exposid{iterator}@& operator=(@\exposid{iterator}@&&) = default;

constexpr @\exposid{iterator}@(@\exposid{iterator}@<!Const> i)
requires Const && @\libconcept{convertible_to}@<iterator_t<V>, iterator_t<@\exposid{Base}@>>;

constexpr iterator_t<@\exposid{Base}@> base() &&;
constexpr const iterator_t<@\exposid{Base}@>& base() const & noexcept;

constexpr decltype(auto) operator*() const { return *@\exposid{current_}@; }

constexpr @\exposid{iterator}@& operator++();
constexpr void operator++(int);

friend constexpr bool operator==(const @\exposid{iterator}@& x, const sentinel_t<@\exposid{Base}@>& y);

friend constexpr difference_type operator-(const sentinel_t<@\exposid{Base}@>& y, const @\exposid{iterator}@& x)
requires @\libconcept{sized_sentinel_for}@<sentinel_t<@\exposid{Base}@>, iterator_t<@\exposid{Base}@>>;
friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const sentinel_t<@\exposid{Base}@>& y)
requires @\libconcept{sized_sentinel_for}@<sentinel_t<@\exposid{Base}@>, iterator_t<@\exposid{Base}@>>;

friend constexpr range_rvalue_reference_t<@\exposid{Base}@> iter_move(const @\exposid{iterator}@& i)
noexcept(noexcept(ranges::iter_move(i.@\exposid{current_}@)));

friend constexpr void iter_swap(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y)
noexcept(noexcept(ranges::iter_swap(x.@\exposid{current_}@, y.@\exposid{current_}@)))
requires @\libconcept{indirectly_swappable}@<iterator_t<@\exposid{Base}@>>;
};
}
\end{codeblock}

\begin{itemdecl}
constexpr explicit @\exposid{iterator}@(iterator_t<@\exposid{Base}@> current);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Initializes \exposid{current_} with \tcode{std::move(current)}.
\end{itemdescr}

\begin{itemdecl}
constexpr @\exposid{iterator}@(@\exposid{iterator}@<!Const> i)
requires Const && @\libconcept{convertible_to}@<iterator_t<V>, iterator_t<@\exposid{Base}@>>;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Initializes \exposid{current_} with \tcode{std::move(i.\exposid{current_})}.
\end{itemdescr}

\begin{itemdecl}
constexpr iterator_t<@\exposid{Base}@> base() &&;
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{std::move(\exposid{current_)}}.
\end{itemdescr}

\begin{itemdecl}
constexpr const iterator_t<@\exposid{Base}@>& base() const & noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\exposid{current_}.
\end{itemdescr}

\begin{itemdecl}
constexpr @\exposid{iterator}@& operator++();
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
++@\exposid{current_}@;
return *this;
\end{codeblock}
\end{itemdescr}

\begin{itemdecl}
constexpr void operator++(int);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to: \tcode{++*this;}
\end{itemdescr}

\begin{itemdecl}
friend constexpr bool operator==(const @\exposid{iterator}@& x, const sentinel_t<@\exposid{Base}@>& y);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{x.\exposid{current_} == y}.
\end{itemdescr}

\begin{itemdecl}
friend constexpr difference_type operator-(const sentinel_t<@\exposid{Base}@>& y, const @\exposid{iterator}@& x)
requires @\libconcept{sized_sentinel_for}@<sentinel_t<@\exposid{Base}@>, iterator_t<@\exposid{Base}@>>;
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{y - x.\exposid{current_}}.
\end{itemdescr}

\begin{itemdecl}
friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const sentinel_t<@\exposid{Base}@>& y)
requires @\libconcept{sized_sentinel_for}@<sentinel_t<@\exposid{Base}@>, iterator_t<@\exposid{Base}@>>;
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{x.\exposid{current_} - y}.
\end{itemdescr}

\begin{itemdecl}
friend constexpr range_rvalue_reference_t<@\exposid{Base}@> iter_move(const @\exposid{iterator}@& i)
noexcept(noexcept(ranges::iter_move(i.@\exposid{current_}@)));
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to: \tcode{return ranges::iter_move(i.\exposid{current_});}
\end{itemdescr}

\begin{itemdecl}
friend constexpr void iter_swap(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y)
noexcept(noexcept(ranges::iter_swap(x.@\exposid{current_}@, y.@\exposid{current_)}@))
requires @\libconcept{indirectly_swappable}@<iterator_t<@\exposid{Base}@>>;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to: \tcode{ranges::iter_swap(x.\exposid{current_}, y.\exposid{current_});}
\end{itemdescr}

\rSec1[coro.generator]{Range generators}

\rSec2[coroutine.generator.overview]{Overview}
Expand Down
1 change: 1 addition & 0 deletions source/support.tex
Original file line number Diff line number Diff line change
Expand Up @@ -765,6 +765,7 @@
#define @\defnlibxname{cpp_lib_ranges_starts_ends_with}@ 202106L // also in \libheader{algorithm}
#define @\defnlibxname{cpp_lib_ranges_stride}@ 202207L // freestanding, also in \libheader{ranges}
#define @\defnlibxname{cpp_lib_ranges_to_container}@ 202202L // freestanding, also in \libheader{ranges}
#define @\defnlibxname{cpp_lib_ranges_to_input}@ 202502L // freestanding, also in \libheader{ranges}
#define @\defnlibxname{cpp_lib_ranges_zip}@ 202110L
// freestanding, also in \libheader{ranges}, \libheader{tuple}, \libheader{utility}
#define @\defnlibxname{cpp_lib_ratio}@ 202306L // freestanding, also in \libheader{ratio}
Expand Down