From d9102f759246fe34d6313ab85399c6689c913c64 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Wed, 15 Feb 2023 19:25:17 -0800 Subject: [PATCH] P2770R0 Stashing stashing iterators for proper flattening Fixes NB US 126 (C++23 CD). --- source/ranges.tex | 201 +++++++++++++++++++++++++++++++++------------- source/regex.tex | 2 + 2 files changed, 146 insertions(+), 57 deletions(-) diff --git a/source/ranges.tex b/source/ranges.tex index 81aa587718..b408a199db 100644 --- a/source/ranges.tex +++ b/source/ranges.tex @@ -4267,7 +4267,7 @@ to temporarily cache values as it is iterated over. \end{note} -\rSec2[range.adaptor.tuple]{Range adaptor helpers} +\rSec2[range.adaptor.helpers]{Range adaptor helpers} \begin{codeblock} namespace std::ranges { @@ -4284,6 +4284,11 @@ (static_cast(invoke(f, std::forward(elements))), ...); }, std::forward(t)); } + + template + constexpr T& @\exposid{as-lvalue}@(T&& t) { // \expos + return static_cast(t); + } } \end{codeblock} @@ -6439,6 +6444,8 @@ V @\exposid{base_}@ = V(); // \expos + @\exposidnc{non-propagating-cache}@> @\exposidnc{outer_}@; // \expos, present only + // when \tcode{!\libconcept{forward_range}} @\exposidnc{non-propagating-cache}@> @\exposid{inner_}@; // \expos, present only // when \tcode{!is_reference_v<\exposid{InnerRng}>} @@ -6450,14 +6457,20 @@ constexpr V base() && { return std::move(@\exposid{base_}@); } constexpr auto begin() { - constexpr bool use_const = @\exposconcept{simple-view}@ && - is_reference_v<@\exposid{InnerRng}@>; - return @\exposid{iterator}@{*this, ranges::begin(@\exposid{base_}@)}; + if constexpr (@\libconcept{forward_range}@) { + constexpr bool use_const = @\exposconcept{simple-view}@ && + is_reference_v<@\exposid{InnerRng}@>; + return @\exposid{iterator}@{*this, ranges::begin(@\exposid{base_}@)}; + } else { + @\exposid{outer_}@ = ranges::begin(@\exposid{base_}@); + return @\exposid{iterator}@{*this}; + } } constexpr auto begin() const - requires @\libconcept{input_range}@ && - is_reference_v> + requires @\libconcept{forward_range}@ && + is_reference_v> && + @\libconcept{input_range}@> { return @\exposid{iterator}@{*this, ranges::begin(@\exposid{base_}@)}; } constexpr auto end() { @@ -6470,10 +6483,10 @@ } constexpr auto end() const - requires @\libconcept{input_range}@ && - is_reference_v> { - if constexpr (@\libconcept{forward_range}@ && - @\libconcept{forward_range}@> && + requires @\libconcept{forward_range}@ && + is_reference_v> && + @\libconcept{input_range}@> { + if constexpr (@\libconcept{forward_range}@> && @\libconcept{common_range}@ && @\libconcept{common_range}@>) return @\exposid{iterator}@{*this, ranges::end(@\exposid{base_}@)}; @@ -6515,20 +6528,28 @@ static constexpr bool @\exposidnc{ref-is-glvalue}@ = // \expos is_reference_v>; - @\exposidnc{OuterIter}@ @\exposid{outer_}@ = @\exposidnc{OuterIter}@(); // \expos + @\exposidnc{OuterIter}@ @\exposid{outer_}@ = @\exposidnc{OuterIter}@(); // \expos, present only + // if \exposid{Base} models \libconcept{forward_range} optional<@\exposidnc{InnerIter}@> @\exposid{inner_}@; // \expos @\exposidnc{Parent}@* @\exposid{parent_}@ = nullptr; // \expos constexpr void @\exposidnc{satisfy}@(); // \expos + constexpr @\exposidnc{OuterIter}@& @\exposidnc{outer}@(); // \expos + constexpr const @\exposidnc{OuterIter}@& @\exposidnc{outer}@() const; // \expos + + constexpr @\exposidnc{iterator}@(@\exposidnc{Parent}@& parent, @\exposidnc{OuterIter}@ outer) + requires @\libconcept{forward_range}@<@\exposidnc{Base}@>; // \expos + constexpr explicit @\exposidnc{iterator}@(@\exposidnc{Parent}@& parent) + requires (!@\libconcept{forward_range}@<@\exposidnc{Base}@>); // \expos + public: using iterator_concept = @\seebelow@; using iterator_category = @\seebelow@; // not always present using value_type = range_value_t>; using difference_type = @\seebelow@; - @\exposid{iterator}@() requires @\libconcept{default_initializable}@<@\exposid{OuterIter}@> = default; - constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, @\exposid{OuterIter}@ outer); + @\exposid{iterator}@() = default; constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) requires Const && @\libconcept{convertible_to}@, @\exposid{OuterIter}@> && @@ -6556,7 +6577,7 @@ @\libconcept{common_range}@>; friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\exposid{ref-is-glvalue}@ && @\libconcept{equality_comparable}@> && + requires @\exposid{ref-is-glvalue}@ && @\libconcept{forward_range}@<@\exposid{Base}@> && @\libconcept{equality_comparable}@>>; friend constexpr decltype(auto) iter_move(const @\exposid{iterator}@& i) @@ -6623,6 +6644,18 @@ \tcode{join_view} iterators use the \exposid{satisfy} function to skip over empty inner ranges. +\begin{itemdecl} +constexpr @\exposid{OuterIter}@& @\exposid{outer}@(); +constexpr const @\exposid{OuterIter}@& @\exposid{outer}@() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\exposid{outer_} if \exposid{Base} models \libconcept{forward_range}; +otherwise, \tcode{*\exposid{parent_}->\exposid{outer_}}. +\end{itemdescr} + \begin{itemdecl} constexpr void @\exposid{satisfy}@(); \end{itemdecl} @@ -6639,8 +6672,8 @@ return @\exposid{parent_}@->@\exposid{inner_}@.@\exposid{emplace-deref}@(x); }; -for (; @\exposid{outer_}@ != ranges::end(@\exposid{parent_}@->@\exposid{base_}@); ++@\exposid{outer_}@) { - auto&& inner = update_inner(@\exposid{outer_}@); +for (; @\exposid{outer}@() != ranges::end(@\exposid{parent_}@->@\exposid{base_}@); ++@\exposid{outer}@()) { + auto&& inner = update_inner(@\exposid{outer}@()); @\exposid{inner_}@ = ranges::begin(inner); if (*@\exposid{inner_}@ != ranges::end(inner)) return; @@ -6652,7 +6685,8 @@ \indexlibraryctor{join_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, @\exposid{OuterIter}@ outer); +constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, @\exposid{OuterIter}@ outer) + requires @\libconcept{forward_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} @@ -6662,6 +6696,19 @@ \exposid{parent_} with \tcode{addressof(parent)}; then calls \tcode{\exposid{satisfy}()}. \end{itemdescr} +\indexlibraryctor{join_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr explicit @\exposid{iterator}@(@\exposid{Parent}@& parent) + requires (!@\libconcept{forward_range}@<@\exposid{Base}@>); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{parent_} with \tcode{addressof(parent)}; +then calls \tcode{\exposid{satisfy}()}. +\end{itemdescr} + \indexlibraryctor{join_view::\exposid{iterator}}% \begin{itemdecl} constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) @@ -6676,6 +6723,12 @@ Initializes \exposid{outer_} with \tcode{std::move(i.\exposid{outer_})}, \exposid{inner_} with \tcode{std::move(i.\exposid{inner_})}, and \exposid{parent_} with \tcode{i.\exposid{parent_}}. + +\pnum +\begin{note} +\tcode{Const} can only be \tcode{true} +when \exposid{Base} models \libconcept{forward_range}. +\end{note} \end{itemdescr} \indexlibrarymember{operator->}{join_view::\exposid{iterator}}% @@ -6699,7 +6752,7 @@ \pnum Let \tcode{\placeholder{inner-range}} be: \begin{itemize} -\item If \exposid{ref-is-glvalue} is \tcode{true}, \tcode{*\exposid{outer_}}. +\item If \exposid{ref-is-glvalue} is \tcode{true}, \tcode{*\exposid{outer}()}. \item Otherwise, \tcode{*\exposid{parent_}->\exposid{inner_}}. \end{itemize} @@ -6707,9 +6760,8 @@ \effects Equivalent to: \begin{codeblock} -auto&& inner_rng = @\placeholder{inner-range}@; -if (++*@\exposid{inner_}@ == ranges::end(inner_rng)) { - ++@\exposid{outer_}@; +if (++*@\exposid{inner_}@ == ranges::end(@\exposid{as-lvalue}@(@\placeholder{inner-range}@))) { + ++@\exposid{outer}@(); @\exposid{satisfy}@(); } return *this; @@ -6759,9 +6811,9 @@ Equivalent to: \begin{codeblock} if (@\exposid{outer_}@ == ranges::end(@\exposid{parent_}@->@\exposid{base_}@)) - @\exposid{inner_}@ = ranges::end(*--@\exposid{outer_}@); -while (*@\exposid{inner_}@ == ranges::begin(*@\exposid{outer_}@)) - *@\exposid{inner_}@ = ranges::end(*--@\exposid{outer_}@); + @\exposid{inner_}@ = ranges::end(@\exposid{as-lvalue}@(*--@\exposid{outer_}@)); +while (*@\exposid{inner_}@ == ranges::begin(@\exposid{as-lvalue}@(*@\exposid{outer_}@))) + *@\exposid{inner_}@ = ranges::end(@\exposid{as-lvalue}@(*--@\exposid{outer_}@)); --*@\exposid{inner_}@; return *this; \end{codeblock} @@ -6789,7 +6841,7 @@ \indexlibrarymember{operator==}{join_view::\exposid{iterator}}% \begin{itemdecl} friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\exposid{ref-is-glvalue}@ && @\libconcept{equality_comparable}@> && + requires @\exposid{ref-is-glvalue}@ && @\libconcept{forward_range}@<@\exposid{Base}@> && @\libconcept{equality_comparable}@>>; \end{itemdecl} @@ -6874,7 +6926,7 @@ \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return x.\exposid{outer_} == y.\exposid{end_};} +Equivalent to: \tcode{return x.\exposid{outer}() == y.\exposid{end_};} \end{itemdescr} \rSec2[range.join.with]{Join with view} @@ -6928,6 +6980,8 @@ using @\exposid{InnerRng}@ = range_reference_t; // \expos V @\exposid{base_}@ = V(); // \expos + @\exposid{non-propagating-cache}@> @\exposid{outer_it_}@; // \expos, present only + // when \tcode{!\libconcept{forward_range}} @\exposid{non-propagating-cache}@> @\exposid{inner_}@; // \expos, present only // when \tcode{!is_reference_v<\exposid{InnerRng}>} Pattern @\exposid{pattern_}@ = Pattern(); // \expos @@ -6953,14 +7007,21 @@ constexpr V base() && { return std::move(@\exposid{base_}@); } constexpr auto begin() { - constexpr bool use_const = - @\exposconcept{simple-view}@ && is_reference_v<@\exposid{InnerRng}@> && @\exposconcept{simple-view}@; - return @\exposid{iterator}@{*this, ranges::begin(@\exposid{base_}@)}; + if constexpr (@\libconcept{forward_range}@) { + constexpr bool use_const = + @\exposconcept{simple-view}@ && is_reference_v<@\exposid{InnerRng}@> && @\exposconcept{simple-view}@; + return @\exposid{iterator}@{*this, ranges::begin(@\exposid{base_}@)}; + } + else { + @\exposid{outer_it_}@ = ranges::begin(@\exposid{base_}@); + return @\exposid{iterator}@{*this}; + } } constexpr auto begin() const - requires @\libconcept{input_range}@ && + requires @\libconcept{forward_range}@ && @\libconcept{forward_range}@ && - is_reference_v> { + is_reference_v> && + @\libconcept{input_range}@> { return @\exposid{iterator}@{*this, ranges::begin(@\exposid{base_}@)}; } @@ -6973,10 +7034,11 @@ return @\exposid{sentinel}@<@\exposconcept{simple-view}@ && @\exposconcept{simple-view}@>{*this}; } constexpr auto end() const - requires @\libconcept{input_range}@ && @\libconcept{forward_range}@ && - is_reference_v> { + requires @\libconcept{forward_range}@ && @\libconcept{forward_range}@ && + is_reference_v> && + @\libconcept{input_range}@> { using InnerConstRng = range_reference_t; - if constexpr (@\libconcept{forward_range}@ && @\libconcept{forward_range}@ && + if constexpr (@\libconcept{forward_range}@ && @\libconcept{common_range}@ && @\libconcept{common_range}@) return @\exposid{iterator}@{*this, ranges::end(@\exposid{base_}@)}; else @@ -7039,12 +7101,18 @@ static constexpr bool @\exposid{ref-is-glvalue}@ = is_reference_v<@\exposid{InnerBase}@>; // \expos @\exposid{Parent}@* @\exposid{parent_}@ = nullptr; // \expos - @\exposid{OuterIter}@ @\exposid{outer_it_}@ = @\exposid{OuterIter}@(); // \expos + @\exposid{OuterIter}@ @\exposid{outer_it_}@ = @\exposid{OuterIter}@(); // \expos, present only + // if \exposid{Base} models \libconcept{forward_range} variant<@\exposid{PatternIter}@, @\exposid{InnerIter}@> @\exposid{inner_it_}@; // \expos - constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, iterator_t<@\exposid{Base}@> outer); // \expos - constexpr auto&& @\exposid{update-inner}@(const @\exposid{OuterIter}@&); // \expos - constexpr auto&& @\exposid{get-inner}@(const @\exposid{OuterIter}@&); // \expos + constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, @\exposid{OuterIter}@ outer) + requires @\libconcept{forward_range}@<@\exposid{Base}@>; // \expos + constexpr explicit @\exposid{iterator}@(@\exposid{Parent}@& parent) + requires (!@\libconcept{forward_range}@<@\exposid{Base}@>); // \expos + constexpr @\exposid{OuterIter}@& @\exposid{outer}@(); // \expos + constexpr const @\exposid{OuterIter}@& @\exposid{outer}@() const; // \expos + constexpr auto& @\exposid{update-inner}@(); // \expos + constexpr auto& @\exposid{get-inner}@(); // \expos constexpr void @\exposid{satisfy}@(); // \expos public: @@ -7053,7 +7121,7 @@ using value_type = @\seebelow@; using difference_type = @\seebelow@; - @\exposid{iterator}@() requires @\libconcept{default_initializable}@<@\exposid{OuterIter}@> = default; + @\exposid{iterator}@() = default; constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) requires Const && @\libconcept{convertible_to}@, @\exposid{OuterIter}@> && @\libconcept{convertible_to}@, @\exposid{InnerIter}@> && @@ -7075,7 +7143,7 @@ @\exposconcept{bidirectional-common}@<@\exposid{InnerBase}@> && @\exposconcept{bidirectional-common}@<@\exposid{PatternBase}@>; friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\exposid{ref-is-glvalue}@ && @\libconcept{equality_comparable}@<@\exposid{OuterIter}@> && + requires @\exposid{ref-is-glvalue}@ && @\libconcept{forward_range}@<@\exposid{Base}@> && @\libconcept{equality_comparable}@<@\exposid{InnerIter}@>; friend constexpr decltype(auto) iter_move(const @\exposid{iterator}@& x) { @@ -7165,7 +7233,19 @@ \end{codeblock} \begin{itemdecl} -constexpr auto&& @\exposid{update-inner}@(const @\exposid{OuterIter}@& x); +constexpr @\exposid{OuterIter}@& @\exposid{outer}@(); +constexpr const @\exposid{OuterIter}@& @\exposid{outer}@() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\exposid{outer_it_} if \exposid{Base} models \libconcept{forward_range}; +otherwise, \tcode{*\exposid{parent_}->\exposid{outer_it_}}. +\end{itemdescr} + +\begin{itemdecl} +constexpr auto& @\exposid{update-inner}@(); \end{itemdecl} \begin{itemdescr} @@ -7174,14 +7254,14 @@ Equivalent to: \begin{codeblock} if constexpr (@\exposid{ref-is-glvalue}@) - return *x; + return @\exposid{as-lvalue}@(*@\exposid{outer}@()); else - return @\exposid{parent_}@->@\exposid{inner_}@.@\exposid{emplace-deref}@(x); + return @\exposid{parent_}@->@\exposid{inner_}@.@\exposid{emplace-deref}@(@\exposid{outer}@()); \end{codeblock} \end{itemdescr} \begin{itemdecl} -constexpr auto&& @\exposid{get-inner}@(const @\exposid{OuterIter}@& x); +constexpr auto& @\exposid{get-inner}@(); \end{itemdecl} \begin{itemdescr} @@ -7190,7 +7270,7 @@ Equivalent to: \begin{codeblock} if constexpr (@\exposid{ref-is-glvalue}@) - return *x; + return @\exposid{as-lvalue}@(*@\exposid{outer}@()); else return *@\exposid{parent_}@->@\exposid{inner_}@; \end{codeblock} @@ -7209,13 +7289,11 @@ if (@\exposid{inner_it_}@.index() == 0) { if (std::get<0>(@\exposid{inner_it_}@) != ranges::end(@\exposid{parent_}@->@\exposid{pattern_}@)) break; - auto&& inner = @\exposid{update-inner}@(@\exposid{outer_it_}@); - @\exposid{inner_it_}@.emplace<1>(ranges::begin(inner)); + @\exposid{inner_it_}@.emplace<1>(ranges::begin(@\exposid{update-inner}@())); } else { - auto&& inner = @\exposid{get-inner}@(@\exposid{outer_it_}@); - if (std::get<1>(@\exposid{inner_it_}@) != ranges::end(inner)) + if (std::get<1>(@\exposid{inner_it_}@) != ranges::end(@\exposid{get-inner}@())) break; - if (++@\exposid{outer_it_}@ == ranges::end(@\exposid{parent_}@->@\exposid{base_}@)) { + if (++@\exposid{outer}@() == ranges::end(@\exposid{parent_}@->@\exposid{base_}@)) { if constexpr (@\exposid{ref-is-glvalue}@) @\exposid{inner_it_}@.emplace<0>(); break; @@ -7232,19 +7310,22 @@ \end{itemdescr} \begin{itemdecl} -constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, iterator_t<@\exposid{Base}@> outer); +constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, @\exposid{OuterIter}@ outer) + requires @\libconcept{forward_range}@<@\exposid{Base}@>; +constexpr explicit @\exposid{iterator}@(@\exposid{Parent}@& parent) + requires (!@\libconcept{forward_range}@<@\exposid{Base}@>); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{parent_} with \tcode{addressof(parent)} and +Initializes \exposid{parent_} with \tcode{addressof(parent)}. +For the first overload, also initializes \exposid{outer_it_} with \tcode{std::move(outer)}. Then, equivalent to: \begin{codeblock} -if (@\exposid{outer_it_}@ != ranges::end(@\exposid{parent_}@->@\exposid{base_}@)) { - auto&& inner = @\exposid{update-inner}@(@\exposid{outer_it_}@); - @\exposid{inner_it_}@.emplace<1>(ranges::begin(inner)); +if (@\exposid{outer}@() != ranges::end(@\exposid{parent_}@->@\exposid{base_}@)) { + @\exposid{inner_it_}@.emplace<1>(ranges::begin(@\exposid{update-inner}@())); @\exposidnc{satisfy}@(); } \end{codeblock} @@ -7270,6 +7351,12 @@ else @\exposid{inner_it_}@.emplace<1>(std::get<1>(std::move(i.@\exposid{inner_it_}@))); \end{codeblock} + +\pnum +\begin{note} +\tcode{Const} can only be \tcode{true} +when \exposid{Base} models \libconcept{forward_range}. +\end{note} \end{itemdescr} \begin{itemdecl} @@ -7387,7 +7474,7 @@ \begin{itemdecl} friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\exposid{ref-is-glvalue}@ && @\libconcept{equality_comparable}@<@\exposid{OuterIter}@> && + requires @\exposid{ref-is-glvalue}@ && @\libconcept{forward_range}@<@\exposid{Base}@> && @\libconcept{equality_comparable}@<@\exposid{InnerIter}@>; \end{itemdecl} @@ -7457,7 +7544,7 @@ \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return x.\exposid{outer_it_} == y.\exposid{end_};} +Equivalent to: \tcode{return x.\exposid{outer}() == y.\exposid{end_};} \end{itemdescr} \rSec2[range.lazy.split]{Lazy split view} diff --git a/source/regex.tex b/source/regex.tex index 48d66e9123..bf47562be9 100644 --- a/source/regex.tex +++ b/source/regex.tex @@ -3264,6 +3264,7 @@ public: using regex_type = basic_regex; using iterator_category = forward_iterator_tag; + using iterator_concept = input_iterator_tag; using value_type = match_results; using difference_type = ptrdiff_t; using pointer = const value_type*; @@ -3534,6 +3535,7 @@ public: using regex_type = basic_regex; using iterator_category = forward_iterator_tag; + using iterator_concept = input_iterator_tag; using value_type = sub_match; using difference_type = ptrdiff_t; using pointer = const value_type*;