Skip to content

Commit 615947a

Browse files
authored
Merge 2024-11 LWG Motion 3
P3138R5 views::cache_latest
2 parents a73c71e + 2ce684c commit 615947a

File tree

2 files changed

+349
-1
lines changed

2 files changed

+349
-1
lines changed

source/ranges.tex

+348-1
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<@\libconcept{input_range}@ V>
547+
requires @\libconcept{view}@<V>
548+
class cache_latest_view;
549+
550+
namespace 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,346 @@
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 @\libglobal{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+
\indexlibraryctor{cache_latest_view}%
16803+
\begin{itemdecl}
16804+
constexpr explicit cache_latest_view(V base);
16805+
\end{itemdecl}
16806+
16807+
\begin{itemdescr}
16808+
\pnum
16809+
\effects
16810+
Initializes \exposid{base_} with \tcode{std::move(base)}.
16811+
\end{itemdescr}
16812+
16813+
\indexlibrarymember{begin}{cache_latest_view}%
16814+
\begin{itemdecl}
16815+
constexpr auto begin();
16816+
\end{itemdecl}
16817+
16818+
\begin{itemdescr}
16819+
\pnum
16820+
\effects
16821+
Equivalent to: \tcode{return \exposid{iterator}(*this);}
16822+
\end{itemdescr}
16823+
16824+
\indexlibrarymember{end}{cache_latest_view}%
16825+
\begin{itemdecl}
16826+
constexpr auto end();
16827+
\end{itemdecl}
16828+
16829+
\begin{itemdescr}
16830+
\pnum
16831+
\effects
16832+
Equivalent to: \tcode{return \exposid{sentinel}(*this);}
16833+
\end{itemdescr}
16834+
16835+
\indexlibrarymember{size}{cache_latest_view}%
16836+
\begin{itemdecl}
16837+
constexpr auto size() requires sized_range<V>;
16838+
constexpr auto size() const requires sized_range<const V>;
16839+
\end{itemdecl}
16840+
16841+
\begin{itemdescr}
16842+
\pnum
16843+
\effects
16844+
Equivalent to: \tcode{return ranges::size(\exposid{base_});}
16845+
\end{itemdescr}
16846+
16847+
\rSec3[range.cache.latest.iterator]{Class \tcode{cache_latest_view::\exposid{iterator}}}
16848+
16849+
\begin{codeblock}
16850+
namespace std::ranges {
16851+
template<@\libconcept{input_range}@ V>
16852+
requires @\libconcept{view}@<V>
16853+
class cache_latest_view<V>::@\exposid{iterator}@ {
16854+
cache_latest_view* @\exposid{parent_}@; // \expos
16855+
iterator_t<V> @\exposid{current_}@; // \expos
16856+
16857+
constexpr explicit @\exposid{iterator}@(cache_latest_view& parent); // \expos
16858+
16859+
public:
16860+
using difference_type = range_difference_t<V>;
16861+
using value_type = range_value_t<V>;
16862+
using iterator_concept = input_iterator_tag;
16863+
16864+
@\exposid{iterator}@(@\exposid{iterator}@&&) = default;
16865+
@\exposid{iterator}@& operator=(@\exposid{iterator}@&&) = default;
16866+
16867+
constexpr iterator_t<V> base() &&;
16868+
constexpr const iterator_t<V>& base() const & noexcept;
16869+
16870+
constexpr range_reference_t<V>& operator*() const;
16871+
16872+
constexpr @\exposid{iterator}@& operator++();
16873+
constexpr void operator++(int);
16874+
16875+
friend constexpr range_rvalue_reference_t<V> iter_move(const @\exposid{iterator}@& i)
16876+
noexcept(noexcept(ranges::iter_move(i.@\exposid{current_}@)));
16877+
16878+
friend constexpr void iter_swap(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y)
16879+
noexcept(noexcept(ranges::iter_swap(x.@\exposid{current_}@, y.@\exposid{current_}@)))
16880+
requires @\libconcept{indirectly_swappable}@<iterator_t<V>>;
16881+
};
16882+
}
16883+
\end{codeblock}
16884+
16885+
\indexlibraryctor{cache_latest_view::\exposid{iterator}}%
16886+
\begin{itemdecl}
16887+
constexpr explicit @\exposid{iterator}@(cache_latest_view& parent);
16888+
\end{itemdecl}
16889+
16890+
\begin{itemdescr}
16891+
\pnum
16892+
\effects
16893+
Initializes \exposid{current_} with
16894+
\tcode{ranges::begin(parent.\exposid{base_})}
16895+
and \exposid{parent_} with \tcode{addressof(par\-ent)}.
16896+
\end{itemdescr}
16897+
16898+
\indexlibrarymember{base}{cache_latest_view::\exposid{iterator}}%
16899+
\begin{itemdecl}
16900+
constexpr iterator_t<V> base() &&;
16901+
\end{itemdecl}
16902+
16903+
\begin{itemdescr}
16904+
\pnum
16905+
\returns
16906+
\tcode{std::move(\exposid{current_})}.
16907+
\end{itemdescr}
16908+
16909+
\indexlibrarymember{base}{cache_latest_view::\exposid{iterator}}%
16910+
\begin{itemdecl}
16911+
constexpr const iterator_t<V>& base() const & noexcept;
16912+
\end{itemdecl}
16913+
16914+
\begin{itemdescr}
16915+
\pnum
16916+
\returns
16917+
\exposid{current_}.
16918+
\end{itemdescr}
16919+
16920+
\indexlibrarymember{operator++}{cache_latest_view::\exposid{iterator}}%
16921+
\begin{itemdecl}
16922+
constexpr iterator& operator++();
16923+
\end{itemdecl}
16924+
16925+
\begin{itemdescr}
16926+
\pnum
16927+
\effects
16928+
Equivalent to:
16929+
\begin{codeblock}
16930+
@\exposid{parent_}@->@\exposid{cache_}@.reset();
16931+
++@\exposid{current_}@;
16932+
return *this;
16933+
\end{codeblock}
16934+
\end{itemdescr}
16935+
16936+
\indexlibrarymember{operator++}{cache_latest_view::\exposid{iterator}}%
16937+
\begin{itemdecl}
16938+
constexpr void operator++(int);
16939+
\end{itemdecl}
16940+
16941+
\begin{itemdescr}
16942+
\pnum
16943+
\effects
16944+
Equivalent to: \tcode{++*this}.
16945+
\end{itemdescr}
16946+
16947+
\indexlibrarymember{operator*}{cache_latest_view::\exposid{iterator}}%
16948+
\begin{itemdecl}
16949+
constexpr range_reference_t<V>& operator*() const;
16950+
\end{itemdecl}
16951+
16952+
\begin{itemdescr}
16953+
\pnum
16954+
\effects
16955+
Equivalent to:
16956+
\begin{codeblock}
16957+
if constexpr (is_reference_v<range_reference_t<V>>) {
16958+
if (!@\exposid{parent_}@->@\exposid{cache_}@) {
16959+
@\exposid{parent_}@->@\exposid{cache_}@ = addressof(@\exposid{as-lvalue}@(*@\exposid{current_}@));
16960+
}
16961+
return **@\exposid{parent_}@->@\exposid{cache_}@;
16962+
} else {
16963+
if (!@\exposid{parent_}@->c@\exposid{ache_}@) {
16964+
@\exposid{parent_}@->@\exposid{cache_}@.@\exposid{emplace-deref}@(@\exposid{current_}@);
16965+
}
16966+
return *@\exposid{parent_}@->@\exposid{cache_}@;
16967+
}
16968+
\end{codeblock}
16969+
\begin{note}
16970+
Evaluations of \tcode{operator*} on the same iterator object
16971+
can conflict\iref{intro.races}.
16972+
\end{note}
16973+
\end{itemdescr}
16974+
16975+
\indexlibrarymember{iter_move}{cache_latest_view::\exposid{iterator}}%
16976+
\begin{itemdecl}
16977+
friend constexpr range_rvalue_reference_t<V> iter_move(const @\exposid{iterator}@& i)
16978+
noexcept(noexcept(ranges::iter_move(i.@\exposid{current_}@)));
16979+
\end{itemdecl}
16980+
16981+
\begin{itemdescr}
16982+
\pnum
16983+
\effects
16984+
Equivalent to: \tcode{return ranges::iter_move(i.\exposid{current_});}
16985+
\end{itemdescr}
16986+
16987+
\indexlibrarymember{iter_swap}{cache_latest_view::\exposid{iterator}}%
16988+
\begin{itemdecl}
16989+
friend constexpr void iter_swap(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y)
16990+
noexcept(noexcept(ranges::iter_swap(x.@\exposid{current_}@, y.@\exposid{current_}@)))
16991+
requires @\libconcept{indirectly_swappable}@<iterator_t<V>>;
16992+
\end{itemdecl}
16993+
16994+
\begin{itemdescr}
16995+
\pnum
16996+
\effects
16997+
Equivalent to
16998+
\tcode{ranges::iter_swap(x.\exposid{current_}, y.\exposid{current_})}.
16999+
\end{itemdescr}
17000+
17001+
\rSec3[range.cache.latest.sentinel]{Class \tcode{cache_latest_view::\exposid{sentinel}}}
17002+
17003+
\begin{codeblock}
17004+
namespace std::ranges {
17005+
template<@\libconcept{input_range}@ V>
17006+
requires @\libconcept{view}@<V>
17007+
class cache_latest_view<V>::@\exposid{sentinel}@ {
17008+
sentinel_t<V> @\exposid{end_}@ = sentinel_t<V>(); // \expos
17009+
17010+
constexpr explicit @\exposid{sentinel}@(cache_latest_view& parent); // \expos
17011+
17012+
public:
17013+
@\exposid{sentinel}@() = default;
17014+
17015+
constexpr sentinel_t<V> base() const;
17016+
17017+
friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y);
17018+
17019+
friend constexpr range_difference_t<V> operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y)
17020+
requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
17021+
friend constexpr range_difference_t<V> operator-(const @\exposid{sentinel}@& x, const @\exposid{iterator}@& y)
17022+
requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
17023+
};
17024+
}
17025+
\end{codeblock}
17026+
17027+
\indexlibraryctor{cache_latest_view::\exposid{sentinel}}%
17028+
\begin{itemdecl}
17029+
constexpr explicit @\exposid{sentinel}@(cache_latest_view& parent);
17030+
\end{itemdecl}
17031+
17032+
\begin{itemdescr}
17033+
\pnum
17034+
\effects
17035+
Initializes \exposid{end_} with \tcode{ranges::end(parent.\exposid{base_})}.
17036+
\end{itemdescr}
17037+
17038+
\indexlibrarymember{base}{cache_latest_view::\exposid{sentinel}}%
17039+
\begin{itemdecl}
17040+
constexpr sentinel_t<V> base() const;
17041+
\end{itemdecl}
17042+
17043+
\begin{itemdescr}
17044+
\pnum
17045+
\returns
17046+
\exposid{end_}.
17047+
\end{itemdescr}
17048+
17049+
\indexlibrarymember{operator==}{cache_latest_view::\exposid{iterator}}%
17050+
\indexlibrarymember{operator==}{cache_latest_view::\exposid{sentinel}}%
17051+
\begin{itemdecl}
17052+
friend constexpr bool operator==(const iterator& x, const sentinel& y);
17053+
\end{itemdecl}
17054+
17055+
\begin{itemdescr}
17056+
\pnum
17057+
\returns
17058+
\tcode{x.\exposid{current_} == y.\exposid{end_}}.
17059+
\end{itemdescr}
17060+
17061+
\indexlibrarymember{operator-}{cache_latest_view::\exposid{iterator}}%
17062+
\indexlibrarymember{operator-}{cache_latest_view::\exposid{sentinel}}%
17063+
\begin{itemdecl}
17064+
friend constexpr range_difference_t<V> operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y)
17065+
requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
17066+
\end{itemdecl}
17067+
17068+
\begin{itemdescr}
17069+
\pnum
17070+
\returns
17071+
\tcode{x.\exposid{current_} - y.\exposid{end_}}.
17072+
\end{itemdescr}
17073+
17074+
\indexlibrarymember{operator-}{cache_latest_view::\exposid{iterator}}%
17075+
\indexlibrarymember{operator-}{cache_latest_view::\exposid{sentinel}}%
17076+
\begin{itemdecl}
17077+
friend constexpr range_difference_t<V> operator-(const @\exposid{sentinel}@& x, const @\exposid{iterator}@& y)
17078+
requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
17079+
\end{itemdecl}
17080+
17081+
\begin{itemdescr}
17082+
\pnum
17083+
\returns
17084+
\tcode{x.\exposid{end_} - y.\exposid{current_}}.
17085+
\end{itemdescr}
17086+
1674017087
\rSec1[coro.generator]{Range generators}
1674117088

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

source/support.tex

+1
Original file line numberDiff line numberDiff line change
@@ -741,6 +741,7 @@
741741
// also in \libheader{algorithm}, \libheader{functional}, \libheader{iterator}, \libheader{memory}, \libheader{ranges}
742742
#define @\defnlibxname{cpp_lib_ranges_as_const}@ 202311L // freestanding, also in \libheader{ranges}
743743
#define @\defnlibxname{cpp_lib_ranges_as_rvalue}@ 202207L // freestanding, also in \libheader{ranges}
744+
#define @\defnlibxname{cpp_lib_ranges_cache_latest}@ 202411L // also in \libheader{ranges}
744745
#define @\defnlibxname{cpp_lib_ranges_cartesian_product}@ 202207L // freestanding, also in \libheader{ranges}
745746
#define @\defnlibxname{cpp_lib_ranges_chunk}@ 202202L // freestanding, also in \libheader{ranges}
746747
#define @\defnlibxname{cpp_lib_ranges_chunk_by}@ 202202L // freestanding, also in \libheader{ranges}

0 commit comments

Comments
 (0)