From fc9fc9dbe7ae7abfbb30de01125f671a7a04c18f Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Wed, 27 Nov 2024 20:24:33 +0100 Subject: [PATCH 1/5] P3138R5 views::cache_latest --- source/ranges.tex | 329 ++++++++++++++++++++++++++++++++++++++++++++- source/support.tex | 1 + 2 files changed, 329 insertions(+), 1 deletion(-) diff --git a/source/ranges.tex b/source/ranges.tex index 18fd5561d3..02b8936913 100644 --- a/source/ranges.tex +++ b/source/ranges.tex @@ -541,6 +541,13 @@ class cartesian_product_view; // freestanding namespace views { inline constexpr @\unspecnc@ cartesian_product = @\unspecnc@; } // freestanding + + // \ref{range.cache.latest}, cache latest view + template + requires view + class cache_latest_view; + + namepspace views { inline constexpr @\unspec@ cache_latest = @\unspec@; } } namespace std { @@ -15684,7 +15691,7 @@ \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{++*this;} +Equivalent to \tcode{++*this;} \end{itemdescr} \indexlibrarymember{operator++}{stride_view::\exposid{iterator}}% @@ -16737,6 +16744,326 @@ \end{itemize} \end{itemdescr} +\rSec2[range.cache.latest]{Cache latest view} + +\rSec3[range.cache.latest.overview]{Overview} + +\pnum +\tcode{cache_latest_view} caches the last-accessed element of +its underlying sequence +so that the element does not have to be recomputed on repeated access. +\begin{note} +This is useful if computation of the element to produce is expensive. +\end{note} + +\pnum +The name \tcode{views::cache_latest} denotes +a range adaptor object\iref{range.adaptor.object}. +Let \tcode{E} be an expression. +The expression \tcode{views::cache_latest(E)} is expression-equivalent to +\tcode{cache_latest_view(E)}. + +\rSec3[range.cache.latest.view]{Class template \tcode{cache_latest_view}} + +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{input_range}@ V> + requires @\libconcept{view}@ + class cache_latest_view : public view_interface> { + V @\exposid{base_}@ = V(); // \expos + using @\exposid{cache_t}@ = conditional_t>, // \expos + add_pointer_t>, + range_reference_t>; + + @\exposid{non-propagating-cache}@ @\exposid{cache_}@; // \expos + + class @\exposid{iterator}@; // \expos + class @\exposid{sentinel}@; // \expos + + public: + cache_latest_view() requires @\libconcept{default_initializable}@ = default; + constexpr explicit cache_latest_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(); + constexpr auto end(); + + constexpr auto size() requires @\libconcept{sized_range}@; + constexpr auto size() const requires @\libconcept{sized_range}@; + }; + + template + cache_latest_view(R&&) -> cache_latest_view>; +} +\end{codeblock} + +\begin{itemdecl} +constexpr explicit cache_latest_view(V base); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{base_} with \tcode{std::move(base)}. +\end{itemdescr} + +\begin{itemdecl} +constexpr auto begin(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return \exposid{iterator}(*this);} +\end{itemdescr} + +\begin{itemdecl} +constexpr auto end(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return \exposid{sentinel}(*this);} +\end{itemdescr} + +\begin{itemdecl} +constexpr auto size() requires sized_range; +constexpr auto size() const requires sized_range; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return ranges::size(\exposid{base_});} +\end{itemdescr} + +\rSec3[range.cache.latest.iterator]{Class \tcode{cache_latest_view::\exposid{iterator}}} + +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{input_range}@ V> + requires @\libconcept{view}@ + class cache_latest_view::@\exposid{iterator}@ { + cache_latest_view* @\exposid{parent_}@; // \expos + iterator_t @\exposid{current_}@; // \expos + + constexpr explicit @\exposid{iterator}@(cache_latest_view& parent); // \expos + + public: + using difference_type = range_difference_t; + using value_type = range_value_t; + using iterator_concept = input_iterator_tag; + + @\exposid{iterator}@(@\exposid{iterator}@&&) = default; + @\exposid{iterator}@& operator=(@\exposid{iterator}@&&) = default; + + constexpr iterator_t base() &&; + constexpr const iterator_t& base() const & noexcept; + + constexpr range_reference_t& operator*() const; + + constexpr @\exposid{iterator}@& operator++(); + constexpr void operator++(int); + + friend constexpr range_rvalue_reference_t 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}@(cache_latest_view& parent); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{current_} with +\tcode{ranges::begin(parent.\exposid{base_})} +and \exposid{parent_} with \tcode{addressof(parent)}. +\end{itemdescr} + +\begin{itemdecl} +constexpr iterator_t base() &&; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{std::move(\exposid{current_})}. +\end{itemdescr} + +\begin{itemdecl} +constexpr const iterator_t& base() const & noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\exposid{current_}. +\end{itemdescr} + +\begin{itemdecl} +constexpr iterator& operator++(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +@\exposid{parent_}@->@\exposid{cache_}@.reset(); +++@\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} +constexpr range_reference_t& operator*() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +if constexpr (is_reference_v>) { + if (!@\exposid{parent_}@->@\exposid{cache_}@) { + @\exposid{parent_}@->@\exposid{cache_}@ = addressof(@\exposid{as-lvalue}@(*@\exposid{current_}@)); + } + return **@\exposid{parent_}@->@\exposid{cache_}@; +} else { + if (!@\exposid{parent_}@->c@\exposid{ache_}@) { + @\exposid{parent_}@->@\exposid{cache_}@.@\exposid{emplace-deref}@(@\exposid{current_}@); + } + return *@\exposid{parent_}@->@\exposid{cache_}@; +} +\end{codeblock} +\begin{note} +Evaluations of \tcode{operator*} on the same iterator object +can conflict\iref{intro.races}. +\end{note} +\end{itemdescr} + +\begin{itemdecl} +friend constexpr range_rvalue_reference_t 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} + +\rSec3[range.cache.latest.sentinel]{Class \tcode{cache_latest_view::\exposid{sentinel}}} + +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{input_range}@ V> + requires @\libconcept{view}@ + class cache_latest_view::@\exposid{sentinel}@ { + sentinel_t @\exposid{end_}@ = sentinel_t(); // \expos + + constexpr explicit @\exposid{sentinel}@(cache_latest_view& parent); // \expos + + public: + @\exposid{sentinel}@() = default; + + constexpr sentinel_t base() const; + + friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); + + friend constexpr range_difference_t operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y) + requires sized_sentinel_for, iterator_t>; + friend constexpr range_difference_t operator-(const @\exposid{sentinel}@& x, const @\exposid{iterator}@& y) + requires sized_sentinel_for, iterator_t>; + }; +} +\end{codeblock} + +\begin{itemdecl} +constexpr explicit @\exposid{sentinel}@(cache_latest_view& parent); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{end_} with \tcode{ranges::end(parent.\exposid{base_})}. +\end{itemdescr} + +\begin{itemdecl} +constexpr sentinel_t base() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\exposid{end_}. +\end{itemdescr} + +\begin{itemdecl} +friend constexpr bool operator==(const iterator& x, const sentinel& y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{x.\exposid{current_} == y.\exposid{end_}}. +\end{itemdescr} + +\begin{itemdecl} +friend constexpr range_difference_t operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y) + requires sized_sentinel_for, iterator_t>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{x.\exposid{current_} - y.\exposid{end_}}. +\end{itemdescr} + +\begin{itemdecl} +friend constexpr range_difference_t operator-(const @\exposid{sentinel}@& x, const @\exposid{iterator}@& y) + requires sized_sentinel_for, iterator_t>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{x.\exposid{end_} - 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 28c15ac913..b72181ab30 100644 --- a/source/support.tex +++ b/source/support.tex @@ -739,6 +739,7 @@ // also in \libheader{algorithm}, \libheader{functional}, \libheader{iterator}, \libheader{memory}, \libheader{ranges} #define @\defnlibxname{cpp_lib_ranges_as_const}@ 202311L // freestanding, also in \libheader{ranges} #define @\defnlibxname{cpp_lib_ranges_as_rvalue}@ 202207L // freestanding, also in \libheader{ranges} +#define @\defnlibxname{cpp_lib_ranges_cache_latest}@ 202411L // also in \libheader{ranges} #define @\defnlibxname{cpp_lib_ranges_cartesian_product}@ 202207L // freestanding, also in \libheader{ranges} #define @\defnlibxname{cpp_lib_ranges_chunk}@ 202202L // freestanding, also in \libheader{ranges} #define @\defnlibxname{cpp_lib_ranges_chunk_by}@ 202202L // freestanding, also in \libheader{ranges} From 1010cfa0b0eeccdb47b8610d4258c204d9aa24e7 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Wed, 27 Nov 2024 23:39:26 +0100 Subject: [PATCH 2/5] fixup: overfull \hbox --- source/ranges.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/ranges.tex b/source/ranges.tex index 02b8936913..678a999b82 100644 --- a/source/ranges.tex +++ b/source/ranges.tex @@ -16887,7 +16887,7 @@ \effects Initializes \exposid{current_} with \tcode{ranges::begin(parent.\exposid{base_})} -and \exposid{parent_} with \tcode{addressof(parent)}. +and \exposid{parent_} with \tcode{addressof(par\-ent)}. \end{itemdescr} \begin{itemdecl} From 04c6c30a8ec238cced727eb814f6d43019e8deb7 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Fri, 6 Dec 2024 13:53:21 +0100 Subject: [PATCH 3/5] fixup: markup for concepts --- source/ranges.tex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/ranges.tex b/source/ranges.tex index 678a999b82..fcc1e9f03b 100644 --- a/source/ranges.tex +++ b/source/ranges.tex @@ -543,8 +543,8 @@ namespace views { inline constexpr @\unspecnc@ cartesian_product = @\unspecnc@; } // freestanding // \ref{range.cache.latest}, cache latest view - template - requires view + template<@\libconcept{input_range}@ V> + requires @\libconcept{view}@ class cache_latest_view; namepspace views { inline constexpr @\unspec@ cache_latest = @\unspec@; } From b9109da0e67fd1d3a01d675adab092856bf6c3de Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Fri, 6 Dec 2024 13:54:56 +0100 Subject: [PATCH 4/5] fixup: typo --- source/ranges.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/ranges.tex b/source/ranges.tex index fcc1e9f03b..f0d1f365f0 100644 --- a/source/ranges.tex +++ b/source/ranges.tex @@ -547,7 +547,7 @@ requires @\libconcept{view}@ class cache_latest_view; - namepspace views { inline constexpr @\unspec@ cache_latest = @\unspec@; } + namespace views { inline constexpr @\unspec@ cache_latest = @\unspec@; } } namespace std { From a01fc2191dfd59639fcaec37a114ec9b41c33b21 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Fri, 6 Dec 2024 14:01:40 +0100 Subject: [PATCH 5/5] fixup: add indexing --- source/ranges.tex | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/source/ranges.tex b/source/ranges.tex index f0d1f365f0..412f6d9edf 100644 --- a/source/ranges.tex +++ b/source/ranges.tex @@ -16769,7 +16769,7 @@ namespace std::ranges { template<@\libconcept{input_range}@ V> requires @\libconcept{view}@ - class cache_latest_view : public view_interface> { + class @\libglobal{cache_latest_view}@ : public view_interface> { V @\exposid{base_}@ = V(); // \expos using @\exposid{cache_t}@ = conditional_t>, // \expos add_pointer_t>, @@ -16799,6 +16799,7 @@ } \end{codeblock} +\indexlibraryctor{cache_latest_view}% \begin{itemdecl} constexpr explicit cache_latest_view(V base); \end{itemdecl} @@ -16809,6 +16810,7 @@ Initializes \exposid{base_} with \tcode{std::move(base)}. \end{itemdescr} +\indexlibrarymember{begin}{cache_latest_view}% \begin{itemdecl} constexpr auto begin(); \end{itemdecl} @@ -16819,6 +16821,7 @@ Equivalent to: \tcode{return \exposid{iterator}(*this);} \end{itemdescr} +\indexlibrarymember{end}{cache_latest_view}% \begin{itemdecl} constexpr auto end(); \end{itemdecl} @@ -16829,6 +16832,7 @@ Equivalent to: \tcode{return \exposid{sentinel}(*this);} \end{itemdescr} +\indexlibrarymember{size}{cache_latest_view}% \begin{itemdecl} constexpr auto size() requires sized_range; constexpr auto size() const requires sized_range; @@ -16878,6 +16882,7 @@ } \end{codeblock} +\indexlibraryctor{cache_latest_view::\exposid{iterator}}% \begin{itemdecl} constexpr explicit @\exposid{iterator}@(cache_latest_view& parent); \end{itemdecl} @@ -16890,6 +16895,7 @@ and \exposid{parent_} with \tcode{addressof(par\-ent)}. \end{itemdescr} +\indexlibrarymember{base}{cache_latest_view::\exposid{iterator}}% \begin{itemdecl} constexpr iterator_t base() &&; \end{itemdecl} @@ -16900,6 +16906,7 @@ \tcode{std::move(\exposid{current_})}. \end{itemdescr} +\indexlibrarymember{base}{cache_latest_view::\exposid{iterator}}% \begin{itemdecl} constexpr const iterator_t& base() const & noexcept; \end{itemdecl} @@ -16910,6 +16917,7 @@ \exposid{current_}. \end{itemdescr} +\indexlibrarymember{operator++}{cache_latest_view::\exposid{iterator}}% \begin{itemdecl} constexpr iterator& operator++(); \end{itemdecl} @@ -16925,6 +16933,7 @@ \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator++}{cache_latest_view::\exposid{iterator}}% \begin{itemdecl} constexpr void operator++(int); \end{itemdecl} @@ -16935,6 +16944,7 @@ Equivalent to: \tcode{++*this}. \end{itemdescr} +\indexlibrarymember{operator*}{cache_latest_view::\exposid{iterator}}% \begin{itemdecl} constexpr range_reference_t& operator*() const; \end{itemdecl} @@ -16962,6 +16972,7 @@ \end{note} \end{itemdescr} +\indexlibrarymember{iter_move}{cache_latest_view::\exposid{iterator}}% \begin{itemdecl} friend constexpr range_rvalue_reference_t iter_move(const @\exposid{iterator}@& i) noexcept(noexcept(ranges::iter_move(i.@\exposid{current_}@))); @@ -16973,6 +16984,7 @@ Equivalent to: \tcode{return ranges::iter_move(i.\exposid{current_});} \end{itemdescr} +\indexlibrarymember{iter_swap}{cache_latest_view::\exposid{iterator}}% \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_}@))) @@ -17012,6 +17024,7 @@ } \end{codeblock} +\indexlibraryctor{cache_latest_view::\exposid{sentinel}}% \begin{itemdecl} constexpr explicit @\exposid{sentinel}@(cache_latest_view& parent); \end{itemdecl} @@ -17022,6 +17035,7 @@ Initializes \exposid{end_} with \tcode{ranges::end(parent.\exposid{base_})}. \end{itemdescr} +\indexlibrarymember{base}{cache_latest_view::\exposid{sentinel}}% \begin{itemdecl} constexpr sentinel_t base() const; \end{itemdecl} @@ -17032,6 +17046,8 @@ \exposid{end_}. \end{itemdescr} +\indexlibrarymember{operator==}{cache_latest_view::\exposid{iterator}}% +\indexlibrarymember{operator==}{cache_latest_view::\exposid{sentinel}}% \begin{itemdecl} friend constexpr bool operator==(const iterator& x, const sentinel& y); \end{itemdecl} @@ -17042,6 +17058,8 @@ \tcode{x.\exposid{current_} == y.\exposid{end_}}. \end{itemdescr} +\indexlibrarymember{operator-}{cache_latest_view::\exposid{iterator}}% +\indexlibrarymember{operator-}{cache_latest_view::\exposid{sentinel}}% \begin{itemdecl} friend constexpr range_difference_t operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y) requires sized_sentinel_for, iterator_t>; @@ -17053,6 +17071,8 @@ \tcode{x.\exposid{current_} - y.\exposid{end_}}. \end{itemdescr} +\indexlibrarymember{operator-}{cache_latest_view::\exposid{iterator}}% +\indexlibrarymember{operator-}{cache_latest_view::\exposid{sentinel}}% \begin{itemdecl} friend constexpr range_difference_t operator-(const @\exposid{sentinel}@& x, const @\exposid{iterator}@& y) requires sized_sentinel_for, iterator_t>;