diff --git a/source/ranges.tex b/source/ranges.tex index bc10e2b0af..81900d18c2 100644 --- a/source/ranges.tex +++ b/source/ranges.tex @@ -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}@ + class to_input_view; + + template + constexpr bool enable_borrowed_range> = + enable_borrowed_range; + + namespace views { inline constexpr @\unspec@ to_input = @\unspec@; } } namespace std { @@ -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}@ +class to_input_view : public view_interface> { + V @\exposid{base_}@ = V(); // \expos + + template class @\exposid{iterator}@; // \expos + +public: + to_input_view() requires @\libconcept{default_initializable}@ = default; + constexpr explicit to_input_view(V base); + + constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } + constexpr V base() && { return std::move(@\exposid{base_}@); } + + constexpr auto begin() requires (!@\exposconcept{simple-view}@); + constexpr auto begin() const requires @\libconcept{range}@; + + constexpr auto end() requires (!@\exposconcept{simple-view}@); + constexpr auto end() const requires @\libconcept{range}@; + + constexpr auto size() requires @\libconcept{sized_range}@; + constexpr auto size() const requires @\libconcept{sized_range}@; +}; + +template + to_input_view(R&&) -> to_input_view>; +\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}@); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return \exposid{iterator}(ranges::begin(\exposid{base_}));} +\end{itemdescr} + +\begin{itemdecl} +constexpr auto begin() const requires @\libconcept{range}@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return \exposid{iterator}(ranges::begin(\exposid{base_}));} +\end{itemdescr} + +\begin{itemdecl} +constexpr auto end() requires (!@\exposconcept{simple-view}@); +constexpr auto end() const requires @\libconcept{range}@; +\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}@; +constexpr auto size() const requires @\libconcept{sized_range}@; +\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}@ + template + class to_input_view::@\exposid{iterator}@ { + using @\exposid{Base}@ = @\exposid{maybe-const}@; // \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}@> = default; + + @\exposid{iterator}@(@\exposid{iterator}@&&) = default; + @\exposid{iterator}@& operator=(@\exposid{iterator}@&&) = default; + + constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) + requires Const && @\libconcept{convertible_to}@, 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}@, iterator_t<@\exposid{Base}@>>; + friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const sentinel_t<@\exposid{Base}@>& y) + requires @\libconcept{sized_sentinel_for}@, 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}@>; + }; +} +\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}@ i) + requires Const && @\libconcept{convertible_to}@, 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}@, 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}@, 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}@>; +\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} diff --git a/source/support.tex b/source/support.tex index d1d6ebb6bd..73b9ba467d 100644 --- a/source/support.tex +++ b/source/support.tex @@ -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}