Skip to content

Commit fc9fc9d

Browse files
committed
P3138R5 views::cache_latest
1 parent 861071a commit fc9fc9d

File tree

2 files changed

+329
-1
lines changed

2 files changed

+329
-1
lines changed

source/ranges.tex

Lines changed: 328 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,13 @@
541541
class cartesian_product_view; // freestanding
542542

543543
namespace views { inline constexpr @\unspecnc@ cartesian_product = @\unspecnc@; } // freestanding
544+
545+
// \ref{range.cache.latest}, cache latest view
546+
template<input_range V>
547+
requires view<V>
548+
class cache_latest_view;
549+
550+
namepspace views { inline constexpr @\unspec@ cache_latest = @\unspec@; }
544551
}
545552

546553
namespace std {
@@ -15684,7 +15691,7 @@
1568415691
\begin{itemdescr}
1568515692
\pnum
1568615693
\effects
15687-
Equivalent to: \tcode{++*this;}
15694+
Equivalent to \tcode{++*this;}
1568815695
\end{itemdescr}
1568915696

1569015697
\indexlibrarymember{operator++}{stride_view::\exposid{iterator}}%
@@ -16737,6 +16744,326 @@
1673716744
\end{itemize}
1673816745
\end{itemdescr}
1673916746

16747+
\rSec2[range.cache.latest]{Cache latest view}
16748+
16749+
\rSec3[range.cache.latest.overview]{Overview}
16750+
16751+
\pnum
16752+
\tcode{cache_latest_view} caches the last-accessed element of
16753+
its underlying sequence
16754+
so that the element does not have to be recomputed on repeated access.
16755+
\begin{note}
16756+
This is useful if computation of the element to produce is expensive.
16757+
\end{note}
16758+
16759+
\pnum
16760+
The name \tcode{views::cache_latest} denotes
16761+
a range adaptor object\iref{range.adaptor.object}.
16762+
Let \tcode{E} be an expression.
16763+
The expression \tcode{views::cache_latest(E)} is expression-equivalent to
16764+
\tcode{cache_latest_view(E)}.
16765+
16766+
\rSec3[range.cache.latest.view]{Class template \tcode{cache_latest_view}}
16767+
16768+
\begin{codeblock}
16769+
namespace std::ranges {
16770+
template<@\libconcept{input_range}@ V>
16771+
requires @\libconcept{view}@<V>
16772+
class cache_latest_view : public view_interface<cache_latest_view<V>> {
16773+
V @\exposid{base_}@ = V(); // \expos
16774+
using @\exposid{cache_t}@ = conditional_t<is_reference_v<range_reference_t<V>>, // \expos
16775+
add_pointer_t<range_reference_t<V>>,
16776+
range_reference_t<V>>;
16777+
16778+
@\exposid{non-propagating-cache}@<cache_t> @\exposid{cache_}@; // \expos
16779+
16780+
class @\exposid{iterator}@; // \expos
16781+
class @\exposid{sentinel}@; // \expos
16782+
16783+
public:
16784+
cache_latest_view() requires @\libconcept{default_initializable}@<V> = default;
16785+
constexpr explicit cache_latest_view(V base);
16786+
16787+
constexpr V base() const & requires @\libconcept{copy_constructible}@<V> { return @\exposid{base_}@; }
16788+
constexpr V base() && { return std::move(@\exposid{base_}@); }
16789+
16790+
constexpr auto begin();
16791+
constexpr auto end();
16792+
16793+
constexpr auto size() requires @\libconcept{sized_range}@<V>;
16794+
constexpr auto size() const requires @\libconcept{sized_range}@<const V>;
16795+
};
16796+
16797+
template<class R>
16798+
cache_latest_view(R&&) -> cache_latest_view<views::all_t<R>>;
16799+
}
16800+
\end{codeblock}
16801+
16802+
\begin{itemdecl}
16803+
constexpr explicit cache_latest_view(V base);
16804+
\end{itemdecl}
16805+
16806+
\begin{itemdescr}
16807+
\pnum
16808+
\effects
16809+
Initializes \exposid{base_} with \tcode{std::move(base)}.
16810+
\end{itemdescr}
16811+
16812+
\begin{itemdecl}
16813+
constexpr auto begin();
16814+
\end{itemdecl}
16815+
16816+
\begin{itemdescr}
16817+
\pnum
16818+
\effects
16819+
Equivalent to: \tcode{return \exposid{iterator}(*this);}
16820+
\end{itemdescr}
16821+
16822+
\begin{itemdecl}
16823+
constexpr auto end();
16824+
\end{itemdecl}
16825+
16826+
\begin{itemdescr}
16827+
\pnum
16828+
\effects
16829+
Equivalent to: \tcode{return \exposid{sentinel}(*this);}
16830+
\end{itemdescr}
16831+
16832+
\begin{itemdecl}
16833+
constexpr auto size() requires sized_range<V>;
16834+
constexpr auto size() const requires sized_range<const V>;
16835+
\end{itemdecl}
16836+
16837+
\begin{itemdescr}
16838+
\pnum
16839+
\effects
16840+
Equivalent to: \tcode{return ranges::size(\exposid{base_});}
16841+
\end{itemdescr}
16842+
16843+
\rSec3[range.cache.latest.iterator]{Class \tcode{cache_latest_view::\exposid{iterator}}}
16844+
16845+
\begin{codeblock}
16846+
namespace std::ranges {
16847+
template<@\libconcept{input_range}@ V>
16848+
requires @\libconcept{view}@<V>
16849+
class cache_latest_view<V>::@\exposid{iterator}@ {
16850+
cache_latest_view* @\exposid{parent_}@; // \expos
16851+
iterator_t<V> @\exposid{current_}@; // \expos
16852+
16853+
constexpr explicit @\exposid{iterator}@(cache_latest_view& parent); // \expos
16854+
16855+
public:
16856+
using difference_type = range_difference_t<V>;
16857+
using value_type = range_value_t<V>;
16858+
using iterator_concept = input_iterator_tag;
16859+
16860+
@\exposid{iterator}@(@\exposid{iterator}@&&) = default;
16861+
@\exposid{iterator}@& operator=(@\exposid{iterator}@&&) = default;
16862+
16863+
constexpr iterator_t<V> base() &&;
16864+
constexpr const iterator_t<V>& base() const & noexcept;
16865+
16866+
constexpr range_reference_t<V>& operator*() const;
16867+
16868+
constexpr @\exposid{iterator}@& operator++();
16869+
constexpr void operator++(int);
16870+
16871+
friend constexpr range_rvalue_reference_t<V> iter_move(const @\exposid{iterator}@& i)
16872+
noexcept(noexcept(ranges::iter_move(i.@\exposid{current_}@)));
16873+
16874+
friend constexpr void iter_swap(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y)
16875+
noexcept(noexcept(ranges::iter_swap(x.@\exposid{current_}@, y.@\exposid{current_}@)))
16876+
requires @\libconcept{indirectly_swappable}@<iterator_t<V>>;
16877+
};
16878+
}
16879+
\end{codeblock}
16880+
16881+
\begin{itemdecl}
16882+
constexpr explicit @\exposid{iterator}@(cache_latest_view& parent);
16883+
\end{itemdecl}
16884+
16885+
\begin{itemdescr}
16886+
\pnum
16887+
\effects
16888+
Initializes \exposid{current_} with
16889+
\tcode{ranges::begin(parent.\exposid{base_})}
16890+
and \exposid{parent_} with \tcode{addressof(parent)}.
16891+
\end{itemdescr}
16892+
16893+
\begin{itemdecl}
16894+
constexpr iterator_t<V> base() &&;
16895+
\end{itemdecl}
16896+
16897+
\begin{itemdescr}
16898+
\pnum
16899+
\returns
16900+
\tcode{std::move(\exposid{current_})}.
16901+
\end{itemdescr}
16902+
16903+
\begin{itemdecl}
16904+
constexpr const iterator_t<V>& base() const & noexcept;
16905+
\end{itemdecl}
16906+
16907+
\begin{itemdescr}
16908+
\pnum
16909+
\returns
16910+
\exposid{current_}.
16911+
\end{itemdescr}
16912+
16913+
\begin{itemdecl}
16914+
constexpr iterator& operator++();
16915+
\end{itemdecl}
16916+
16917+
\begin{itemdescr}
16918+
\pnum
16919+
\effects
16920+
Equivalent to:
16921+
\begin{codeblock}
16922+
@\exposid{parent_}@->@\exposid{cache_}@.reset();
16923+
++@\exposid{current_}@;
16924+
return *this;
16925+
\end{codeblock}
16926+
\end{itemdescr}
16927+
16928+
\begin{itemdecl}
16929+
constexpr void operator++(int);
16930+
\end{itemdecl}
16931+
16932+
\begin{itemdescr}
16933+
\pnum
16934+
\effects
16935+
Equivalent to: \tcode{++*this}.
16936+
\end{itemdescr}
16937+
16938+
\begin{itemdecl}
16939+
constexpr range_reference_t<V>& operator*() const;
16940+
\end{itemdecl}
16941+
16942+
\begin{itemdescr}
16943+
\pnum
16944+
\effects
16945+
Equivalent to:
16946+
\begin{codeblock}
16947+
if constexpr (is_reference_v<range_reference_t<V>>) {
16948+
if (!@\exposid{parent_}@->@\exposid{cache_}@) {
16949+
@\exposid{parent_}@->@\exposid{cache_}@ = addressof(@\exposid{as-lvalue}@(*@\exposid{current_}@));
16950+
}
16951+
return **@\exposid{parent_}@->@\exposid{cache_}@;
16952+
} else {
16953+
if (!@\exposid{parent_}@->c@\exposid{ache_}@) {
16954+
@\exposid{parent_}@->@\exposid{cache_}@.@\exposid{emplace-deref}@(@\exposid{current_}@);
16955+
}
16956+
return *@\exposid{parent_}@->@\exposid{cache_}@;
16957+
}
16958+
\end{codeblock}
16959+
\begin{note}
16960+
Evaluations of \tcode{operator*} on the same iterator object
16961+
can conflict\iref{intro.races}.
16962+
\end{note}
16963+
\end{itemdescr}
16964+
16965+
\begin{itemdecl}
16966+
friend constexpr range_rvalue_reference_t<V> iter_move(const @\exposid{iterator}@& i)
16967+
noexcept(noexcept(ranges::iter_move(i.@\exposid{current_}@)));
16968+
\end{itemdecl}
16969+
16970+
\begin{itemdescr}
16971+
\pnum
16972+
\effects
16973+
Equivalent to: \tcode{return ranges::iter_move(i.\exposid{current_});}
16974+
\end{itemdescr}
16975+
16976+
\begin{itemdecl}
16977+
friend constexpr void iter_swap(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y)
16978+
noexcept(noexcept(ranges::iter_swap(x.@\exposid{current_}@, y.@\exposid{current_}@)))
16979+
requires @\libconcept{indirectly_swappable}@<iterator_t<V>>;
16980+
\end{itemdecl}
16981+
16982+
\begin{itemdescr}
16983+
\pnum
16984+
\effects
16985+
Equivalent to
16986+
\tcode{ranges::iter_swap(x.\exposid{current_}, y.\exposid{current_})}.
16987+
\end{itemdescr}
16988+
16989+
\rSec3[range.cache.latest.sentinel]{Class \tcode{cache_latest_view::\exposid{sentinel}}}
16990+
16991+
\begin{codeblock}
16992+
namespace std::ranges {
16993+
template<@\libconcept{input_range}@ V>
16994+
requires @\libconcept{view}@<V>
16995+
class cache_latest_view<V>::@\exposid{sentinel}@ {
16996+
sentinel_t<V> @\exposid{end_}@ = sentinel_t<V>(); // \expos
16997+
16998+
constexpr explicit @\exposid{sentinel}@(cache_latest_view& parent); // \expos
16999+
17000+
public:
17001+
@\exposid{sentinel}@() = default;
17002+
17003+
constexpr sentinel_t<V> base() const;
17004+
17005+
friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y);
17006+
17007+
friend constexpr range_difference_t<V> operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y)
17008+
requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
17009+
friend constexpr range_difference_t<V> operator-(const @\exposid{sentinel}@& x, const @\exposid{iterator}@& y)
17010+
requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
17011+
};
17012+
}
17013+
\end{codeblock}
17014+
17015+
\begin{itemdecl}
17016+
constexpr explicit @\exposid{sentinel}@(cache_latest_view& parent);
17017+
\end{itemdecl}
17018+
17019+
\begin{itemdescr}
17020+
\pnum
17021+
\effects
17022+
Initializes \exposid{end_} with \tcode{ranges::end(parent.\exposid{base_})}.
17023+
\end{itemdescr}
17024+
17025+
\begin{itemdecl}
17026+
constexpr sentinel_t<V> base() const;
17027+
\end{itemdecl}
17028+
17029+
\begin{itemdescr}
17030+
\pnum
17031+
\returns
17032+
\exposid{end_}.
17033+
\end{itemdescr}
17034+
17035+
\begin{itemdecl}
17036+
friend constexpr bool operator==(const iterator& x, const sentinel& y);
17037+
\end{itemdecl}
17038+
17039+
\begin{itemdescr}
17040+
\pnum
17041+
\returns
17042+
\tcode{x.\exposid{current_} == y.\exposid{end_}}.
17043+
\end{itemdescr}
17044+
17045+
\begin{itemdecl}
17046+
friend constexpr range_difference_t<V> operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y)
17047+
requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
17048+
\end{itemdecl}
17049+
17050+
\begin{itemdescr}
17051+
\pnum
17052+
\returns
17053+
\tcode{x.\exposid{current_} - y.\exposid{end_}}.
17054+
\end{itemdescr}
17055+
17056+
\begin{itemdecl}
17057+
friend constexpr range_difference_t<V> operator-(const @\exposid{sentinel}@& x, const @\exposid{iterator}@& y)
17058+
requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
17059+
\end{itemdecl}
17060+
17061+
\begin{itemdescr}
17062+
\pnum
17063+
\returns
17064+
\tcode{x.\exposid{end_} - y.\exposid{current_}}.
17065+
\end{itemdescr}
17066+
1674017067
\rSec1[coro.generator]{Range generators}
1674117068

1674217069
\rSec2[coroutine.generator.overview]{Overview}

source/support.tex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -739,6 +739,7 @@
739739
// also in \libheader{algorithm}, \libheader{functional}, \libheader{iterator}, \libheader{memory}, \libheader{ranges}
740740
#define @\defnlibxname{cpp_lib_ranges_as_const}@ 202311L // freestanding, also in \libheader{ranges}
741741
#define @\defnlibxname{cpp_lib_ranges_as_rvalue}@ 202207L // freestanding, also in \libheader{ranges}
742+
#define @\defnlibxname{cpp_lib_ranges_cache_latest}@ 202411L // also in \libheader{ranges}
742743
#define @\defnlibxname{cpp_lib_ranges_cartesian_product}@ 202207L // freestanding, also in \libheader{ranges}
743744
#define @\defnlibxname{cpp_lib_ranges_chunk}@ 202202L // freestanding, also in \libheader{ranges}
744745
#define @\defnlibxname{cpp_lib_ranges_chunk_by}@ 202202L // freestanding, also in \libheader{ranges}

0 commit comments

Comments
 (0)