diff --git a/source/algorithms.tex b/source/algorithms.tex index 0c5d2b5cb6..2c7c2223c3 100644 --- a/source/algorithms.tex +++ b/source/algorithms.tex @@ -3633,6 +3633,8 @@ namespace ranges { template using @\libglobal{set_difference_result}@ = in_out_result; + template + using @\libglobal{set_difference_truncated_result}@ = in_in_out_result; template<@\libconcept{input_iterator}@ I1, @\libconcept{sentinel_for}@ S1, @\libconcept{input_iterator}@ I2, @\libconcept{sentinel_for}@ S2, @\libconcept{weakly_incrementable}@ O, class Comp = ranges::less, @@ -3653,7 +3655,7 @@ @\libconcept{random_access_iterator}@ O, @\libconcept{sized_sentinel_for}@ OutS, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> requires @\libconcept{mergeable}@ - set_difference_result + set_difference_truncated_result set_difference(Ep&& exec, I1 first1, S1 last1, I2 first2, S2 last2, O result, OutS result_last, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); // freestanding-deleted @@ -3661,7 +3663,8 @@ @\exposconcept{sized-random-access-range}@ OutR, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> requires @\libconcept{mergeable}@, iterator_t, iterator_t, Comp, Proj1, Proj2> - set_difference_result, borrowed_iterator_t> + set_difference_truncated_result, borrowed_iterator_t, + borrowed_iterator_t> set_difference(Ep&& exec, R1&& r1, R2&& r2, OutR&& result_r, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); // freestanding-deleted } @@ -10584,9 +10587,10 @@ If, of those elements, $k$ elements from the first range are copied to the output range, then the first $k$ elements from the second range -are considered \term{skipped}. -If $N < M$, a non-copied element is also considered skipped -if it compares less than the $(N + 1)^\text{th}$ element +\indextext{element!skipped}% +are considered \defn{skipped}. +A non-copied element is also considered skipped +if it compares less than the $\min(M, N + 1)^\text{th}$ element of the sorted intersection. Copies the first $N$ elements of the sorted intersection to the range \range{result}{result + $N$}. @@ -10599,11 +10603,10 @@ for the overloads in namespace \tcode{std}. \item \tcode{\{last1, last2, result + $N$\}} - for the overloads in namespace \tcode{ranges}, - if $N$ is equal to $M$. + for the non-parallel algorithm overloads in namespace \tcode{ranges}. \item - Otherwise, \tcode{\{first1 + $A$, first2 + $B$, result_last\}} - for the overloads in namespace \tcode{ranges}, + Otherwise, \tcode{\{first1 + $A$, first2 + $B$, result + $N$\}} + for the parallel algorithm overloads in namespace \tcode{ranges}, where $A$ and $B$ are the numbers of copied or skipped elements in \range{first1}{last1} and \range{first2}{last2}, respectively. \end{itemize} @@ -10669,7 +10672,7 @@ @\libconcept{random_access_iterator}@ O, @\libconcept{sized_sentinel_for}@ OutS, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> requires @\libconcept{mergeable}@ - ranges::set_difference_result + ranges::set_difference_truncated_result ranges::set_difference(Ep&& exec, I1 first1, S1 last1, I2 first2, S2 last2, O result, OutS result_last, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); @@ -10677,7 +10680,8 @@ @\exposconcept{sized-random-access-range}@ OutR, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> requires @\libconcept{mergeable}@, iterator_t, iterator_t, Comp, Proj1, Proj2> - ranges::set_difference_result, borrowed_iterator_t> + ranges::set_difference_truncated_result, borrowed_iterator_t, + borrowed_iterator_t> ranges::set_difference(Ep&& exec, R1&& r1, R2&& r2, OutR&& result_r, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); \end{itemdecl} @@ -10716,6 +10720,13 @@ that are equivalent to them, the last $\max(m - n, 0)$ elements from \range{first1}{last1} are included in the sorted difference, in order. +Of those equivalent elements, +the first $\min(m, n)$ elements in both ranges +\indextext{element!skipped}% +are considered \defn{skipped}. +An element from the second range is also considered skipped +if it compares less than the $\min(N + 1, M)^\text{th}$ element +of the sorted difference. Copies the first $N$ elements of the sorted difference to the range \range{result}{result + $N$}. @@ -10727,14 +10738,19 @@ for the overloads in namespace \tcode{std}. \item \tcode{\{last1, result + $N$\}} - for the overloads in namespace \tcode{ranges}, - if $N$ is equal to $M$. + for the non-parallel overloads in namespace \tcode{ranges}. \item - Otherwise, \tcode{\{j1, result_last\}} - for the overloads in namespace \tcode{ranges}, - where the iterator \tcode{j1} - points to the position of the element in \range{first1}{last1} - corresponding to the $(N + 1)^\text{th}$ element of the sorted difference. + For the parallel algorithm overloads in namespace \tcode{ranges}: + \begin{itemize} + \item + \tcode{\{last1, first2 + $B$, result + $N$\}}, + if $N$ is equal to $M$, + where $B$ is the number of skipped elements in \range{first2}{last2}. + \item + Otherwise, \tcode{\{first1 + $A$, first2 + $B$, result_last\}}, + where $A$ and $B$ are the numbers of copied or skipped elements + in \range{first1}{last1} and \range{first2}{last2}, respectively. + \end{itemize} \end{itemize} \pnum diff --git a/source/containers.tex b/source/containers.tex index 63cf29baa1..f750596d8a 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -7980,9 +7980,15 @@ The maximum hard limit shall be no larger than \tcode{std::allocator_traits::max_size()}. \item -If user-specified limits are not within hard limits, or +If user-specified limits passed to +a \tcode{hive} constructor or \tcode{reshape} +are not within hard limits, or if the specified minimum limit is greater than the specified maximum limit, -the behavior is undefined. +the behavior is erroneous and the effects are +\impldef{effects of invalid \tcode{hive} limits}. +\begin{tailnote} +This condition can be checked using \tcode{is_within_hard_limits}. +\end{tailnote} \item An element block is said to be \defnx{within the bounds}{element block!bounds} of a pair of minimum/maximum limits @@ -8089,6 +8095,7 @@ constexpr hive_limits block_capacity_limits() const noexcept; static constexpr hive_limits block_capacity_default_limits() noexcept; static constexpr hive_limits block_capacity_hard_limits() noexcept; + static constexpr bool is_within_hard_limits(hive_limits) noexcept; void reshape(hive_limits block_limits); // \ref{hive.modifiers}, modifiers @@ -8478,7 +8485,9 @@ \pnum \throws -\tcode{length_error} if \tcode{n > max_size()}, +\tcode{length_error} if +satisfying the postcondition +would cause \tcode{capacity()} to exceed \tcode{max_size()}, as well as any exceptions thrown by the allocator. \pnum @@ -8604,6 +8613,20 @@ Constant. \end{itemdescr} +\indexlibrarymember{is_within_hard_limits}{hive}% +\begin{itemdecl} +static constexpr bool is_within_hard_limits(hive_limits lim) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{hl} be \tcode{block_capacity_hard_limits()}. + +\pnum +\returns +\tcode{hl.min <= lim.min \&\& lim.min <= lim.max \&\& lim.max <= hl.max}. +\end{itemdescr} + \indexlibrarymember{reshape}{hive}% \begin{itemdecl} void reshape(hive_limits block_limits); @@ -10999,8 +11022,13 @@ friend constexpr bool operator==(const inplace_vector& x, const inplace_vector& y); - friend constexpr @\exposid{synth-three-way-result}@ - operator<=>(const inplace_vector& x, const inplace_vector& y); + friend constexpr auto + operator<=>(const inplace_vector& x, const inplace_vector& y) + requires requires (const T t) { @\exposid{synth-three-way}@(t, t); } + { + return lexicographical_compare_three_way(x.begin(), x.end(), y.begin(), y.end(), + @\exposid{synth-three-way}@); + } friend constexpr void swap(inplace_vector& x, inplace_vector& y) noexcept(N == 0 || (is_nothrow_swappable_v && is_nothrow_move_constructible_v)) @@ -11418,6 +11446,26 @@ equal to the number of elements after the erased elements. \end{itemdescr} +\indexlibrarymember{swap}{inplace_vector}% +\begin{itemdecl} +constexpr void swap(inplace_vector& x) noexcept(N == 0 || + (is_nothrow_swappable_v && is_nothrow_move_constructible_v)); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{T} meets the \oldconcept{MoveConstructible} requirements. +Let $M$ be \tcode{min(size(), x.size())}. +For each non-negative integer $n < M$, +\tcode{(*this)[$n$]} is swappable +with \tcode{x[$n$]}\iref{swappable.requirements}. + +\pnum +\effects +Exchanges the contents of \tcode{*this} and \tcode{x}. +\end{itemdescr} + \rSec3[inplace.vector.erasure]{Erasure} \indexlibrarymember{erase}{inplace_vector}% @@ -11472,24 +11520,25 @@ template using @\placeholder{iter-value-type}@ = iterator_traits::value_type; // \expos template - using @\placeholder{iter-key-type}@ = remove_const_t< + using @\placeholder{iter-key-type}@ = remove_cvref_t< tuple_element_t<0, @\exposid{iter-value-type}@>>; // \expos template - using @\placeholder{iter-mapped-type}@ = - tuple_element_t<1, @\exposid{iter-value-type}@>; // \expos + using @\placeholder{iter-mapped-type}@ = remove_cvref_t< + tuple_element_t<1, @\exposid{iter-value-type}@>>; // \expos template using @\placeholder{iter-to-alloc-type}@ = pair< - const tuple_element_t<0, @\exposid{iter-value-type}@>, - tuple_element_t<1, @\exposid{iter-value-type}@>>; // \expos + const @\exposid{iter-key-type}@, + @\exposid{iter-mapped-type}@>; // \expos template using @\exposid{range-key-type}@ = - remove_const_t::first_type>; // \expos + remove_cvref_t>>; // \expos template - using @\exposid{range-mapped-type}@ = ranges::range_value_t::second_type; // \expos + using @\exposid{range-mapped-type}@ = + remove_cvref_t>>; // \expos template using @\exposid{range-to-alloc-type}@ = - pair::first_type, - typename ranges::range_value_t::second_type>; // \expos + pair, + @\exposid{range-mapped-type}@>; // \expos \end{codeblock} \rSec2[associative.map.syn]{Header \tcode{} synopsis} @@ -21486,7 +21535,7 @@ If \tcode{remove_cvref_t} is an integral type other than \tcode{bool}, then equivalent to \tcode{return i;}, \item -otherwise, equivalent to \tcode{return static_cast(i);}. +otherwise, equivalent to \tcode{return static_cast(std::forward(\brk{}i));}. \end{itemize} \begin{note} This function will always return an integral type other than \tcode{bool}. @@ -22433,7 +22482,7 @@ is \tcode{true}. Equivalent to: \begin{codeblock} -return ((static_cast(i) * stride(P)) + ... + 0); +return ((static_cast(std::move(i)) * stride(P)) + ... + 0); \end{codeblock} \end{itemdescr} @@ -22766,7 +22815,7 @@ \end{codeblock} is \tcode{true}. Equivalent to: \begin{codeblock} -return ((static_cast(i) * stride(P)) + ... + 0); +return ((static_cast(std::move(i)) * stride(P)) + ... + 0); \end{codeblock} \end{itemdescr} @@ -23130,7 +23179,7 @@ is \tcode{true}. Equivalent to: \begin{codeblock} -return ((static_cast(i) * stride(P)) + ... + 0); +return ((static_cast(std::move(i)) * stride(P)) + ... + 0); \end{codeblock} \end{itemdescr} @@ -23445,10 +23494,14 @@ \indexlibraryctor{layout_left_padded::mapping}% \begin{itemdecl} template -constexpr mapping(const extents_type& ext, OtherIndexType pad); +constexpr mapping(const extents_type& ext, OtherIndexType padding); \end{itemdecl} \begin{itemdescr} +\pnum +Let \tcode{pad} be +\tcode{extents_type::\exposid{index-cast}(std::move(padding))}. + \pnum \constraints \begin{itemize} @@ -23464,7 +23517,7 @@ \item \tcode{pad} is representable as a value of type \tcode{index_type}. \item -\tcode{extents_type::\exposid{index-cast}(pad)} is greater than zero. +\tcode{pad} is greater than zero. \item If \exposid{rank_} is greater than one, then \tcode{\exposid{LEAST-MULTIPLE-AT-LEAST}(pad, ext.extent(0))} @@ -23478,7 +23531,7 @@ is representable as a value of type \tcode{index_type}. \item If \tcode{padding_value} is not equal to \tcode{dynamic_extent}, -\tcode{padding_value} equals \tcode{extents_type::\exposid{in\-dex-cast}(pad)}. +\tcode{padding_value} equals \tcode{pad}. \end{itemize} \pnum @@ -23755,7 +23808,7 @@ \pnum \returns -\tcode{((static_cast(idxs) * stride(P_rank)) + ... + 0)}. +\tcode{((static_cast(std::move(idxs)) * stride(P_rank)) + ... + 0)}. \end{itemdescr} \begin{itemdecl} @@ -24082,10 +24135,14 @@ \indexlibraryctor{layout_right_padded::mapping}% \begin{itemdecl} template -constexpr mapping(const extents_type& ext, OtherIndexType pad); +constexpr mapping(const extents_type& ext, OtherIndexType padding); \end{itemdecl} \begin{itemdescr} +\pnum +Let \tcode{pad} be +\tcode{extents_type::\exposid{index-cast}(std::move(padding))}. + \pnum \constraints \begin{itemize} @@ -24101,7 +24158,7 @@ \item \tcode{pad} is representable as a value of type \tcode{index_type}. \item -\tcode{extents_type::\exposid{index-cast}(pad)} is greater than zero. +\tcode{pad} is greater than zero. \item If \exposid{rank_} is greater than one, then \tcode{\exposid{LEAST-MULTIPLE-AT-LEAST}(pad, ext.extent(\exposid{rank_} - 1))} @@ -24115,7 +24172,7 @@ is representable as a value of type \tcode{index_type}. \item If \tcode{padding_value} is not equal to \tcode{dynamic_extent}, -\tcode{padding_value} equals \tcode{extents_type::\linebreak \exposid{index-cast}(pad)}. +\tcode{padding_value} equals \tcode{pad}. \end{itemize} \pnum @@ -24390,7 +24447,7 @@ \pnum \returns -\tcode{((static_cast(idxs) * stride(P_rank)) + ... + 0)}. +\tcode{((static_cast(std::move(idxs)) * stride(P_rank)) + ... + 0)}. \end{itemdescr} \indexlibrarymember{layout_right_padded::mapping}{is_always_exhaustive}% diff --git a/source/exec.tex b/source/exec.tex index cba1458af9..cc47478622 100644 --- a/source/exec.tex +++ b/source/exec.tex @@ -1007,16 +1007,12 @@ \tcode{get_forward_progress_guarantee} is ill-formed. Otherwise, \tcode{get_forward_progress_guarantee(sch)} is expression-equivalent to: -\begin{itemize} -\item -\tcode{\exposid{MANDATE-NOTHROW}(\exposid{AS-CONST}(sch).query(get_forward_progress_guarantee))}, -if that expression is well-formed. +\begin{codeblock} +@\exposid{MANDATE-NOTHROW}@(@\exposid{AS-CONST}@(sch).query(get_forward_progress_guarantee)) +\end{codeblock} \mandates The type of the expression above is \tcode{forward_progress_guarantee}. -\item -Otherwise, \tcode{forward_progress_guarantee::weakly_parallel}. -\end{itemize} \pnum If \tcode{get_forward_progress_guarantee(sch)} for some scheduler \tcode{sch} @@ -1111,6 +1107,7 @@ @\exposconcept{queryable}@ && requires(Sch&& sch) { { schedule(std::forward(sch)) } -> @\libconcept{sender}@; + { get_forward_progress_guarantee(sch) } -> @\libconcept{same_as}@; { auto(get_completion_scheduler( get_env(schedule(std::forward(sch))))) } -> @\libconcept{same_as}@>; @@ -1242,6 +1239,9 @@ Otherwise, it is expression-equivalent to \tcode{\exposid{MANDATE-NOTHROW}(rcvr.set_value(vs...))}. +\mandates +If the expression above is well-formed, its type is \tcode{void}. + \rSec2[exec.set.error]{\tcode{execution::set_error}} \pnum @@ -1253,6 +1253,9 @@ Otherwise, it is expression-equivalent to \tcode{\exposid{MANDATE-NOTHROW}(rcvr.set_error(err))}. +\mandates +If the expression above is well-formed, its type is \tcode{void}. + \rSec2[exec.set.stopped]{\tcode{execution::set_stopped}} \pnum @@ -1264,6 +1267,9 @@ Otherwise, it is expression-equivalent to \tcode{\exposid{MANDATE-NOTHROW}(rcvr.set_stopped())}. +\mandates +If the expression above is well-formed, its type is \tcode{void}. + \rSec1[exec.opstate]{Operation states} \rSec2[exec.opstate.general]{General} @@ -1311,6 +1317,9 @@ Otherwise, it is expression-equivalent to \tcode{\exposid{MANDATE-NOTHROW}(op.start())}. +\mandates +If the expression above is well-formed, its type is \tcode{void}. + \pnum If \tcode{op.start()} does not start\iref{exec.async.ops} the asynchronous operation associated with the operation state \tcode{op}, @@ -1796,19 +1805,16 @@ static constexpr const auto& @\exposidnc{complete}@ = @\exposidnc{impls-for}@<@\exposidnc{tag-t}@>::@\exposidnc{complete}@; // \expos template - requires @\exposconcept{callable}@ void set_value(Args&&... args) && noexcept { @\exposid{complete}@(Index(), @\exposidnc{op}@->@\exposid{state}@, @\exposidnc{op}@->@\exposid{rcvr}@, set_value_t(), std::forward(args)...); } template - requires @\exposconcept{callable}@ void set_error(Error&& err) && noexcept { @\exposid{complete}@(Index(), @\exposidnc{op}@->@\exposid{state}@, @\exposidnc{op}@->@\exposid{rcvr}@, set_error_t(), std::forward(err)); } void set_stopped() && noexcept - requires @\exposconcept{callable}@ { @\exposid{complete}@(Index(), @\exposidnc{op}@->@\exposid{state}@, @\exposidnc{op}@->@\exposid{rcvr}@, set_stopped_t()); } @@ -5307,6 +5313,18 @@ are not satisfied, the expression \tcode{spawn_future(sndr, token, env)} is ill-formed. +\pnum +Let \exposid{try-cancelable} be the exposition-only class: + +\indexlibraryglobal{execution::\exposid{try-cancelable}}% +\begin{codeblock} +namespace std::execution { + struct @\exposid{try-cancelable}@ { // \expos + virtual void @\exposid{try-cancel}@() noexcept = 0; // \expos + }; +} +\end{codeblock} + \pnum Let \exposid{spawn-future-state-base} be the exposition-only class template: @@ -5317,7 +5335,8 @@ struct @\exposid{spawn-future-state-base}@; // \expos template - struct @\exposid{spawn-future-state-base}@> { // \expos + struct @\exposid{spawn-future-state-base}@> // \expos + : @\exposid{try-cancelable}@ { using @\exposid{variant-t}@ = @\seebelow@; // \expos @\exposid{variant-t}@ @\exposid{result}@; // \expos virtual void @\exposid{complete}@() noexcept = 0; // \expos @@ -5443,6 +5462,11 @@ void @\exposidnc{complete}@() noexcept override; // \expos void @\exposidnc{consume}@(@\libconcept{receiver}@ auto& rcvr) noexcept; // \expos void @\exposidnc{abandon}@() noexcept; // \expos + void @\exposidnc{try-cancel}@() noexcept override { // \expos + @\exposid{ssource}@.request_stop(); + @\exposid{try-set-stopped}@(); + } + void @\exposidnc{try-set-stopped}@() noexcept; // \expos private: using @\exposidnc{assoc-t}@ = // \expos @@ -5464,7 +5488,7 @@ \pnum For purposes of determining the existence of a data race, -\exposid{complete}, \exposid{consume}, and \exposid{abandon} +\exposid{complete}, \exposid{consume}, \exposid{try-set-stopped}, and \exposid{abandon} behave as atomic operations\iref{intro.multithread}. These operations on a single object of a type that is a specialization of \exposid{spawn-future-state} @@ -5481,13 +5505,18 @@ \begin{itemize} \item No effects if this invocation of \exposid{complete} happens before -an invocation of \exposid{consume} or \exposid{abandon} on \tcode{*this}; +an invocation of +\exposid{consume}, \exposid{try-set-\linebreak{}stopped}, or \exposid{abandon} +on \tcode{*this}; \item otherwise, if an invocation of \exposid{consume} on \tcode{*this} happens before -this invocation of \exposid{complete} then +this invocation of \exposid{complete} and +no invocation of \exposid{try-set-stopped} on \tcode{*this} happened before +this invocation of \tcode{complete} then there is a receiver, \tcode{rcvr}, registered and -that receiver is completed as if by \tcode{\exposid{consume}(rcvr)}; +that receiver is deregistered and completed +as if by \tcode{\exposid{consume}(rcvr)}; \item otherwise, \exposid{destroy} is invoked. @@ -5505,10 +5534,20 @@ \begin{itemize} \item If this invocation of \exposid{consume} happens before -an invocation of \exposid{complete} on \tcode{*this} then +an invocation of \exposid{complete} on \tcode{*this} and +no invocation of \exposid{try-set-stopped} on \tcode{*this} happened before +this invocation of \exposid{consume} then \tcode{rcvr} is registered to be completed when \exposid{complete} is subsequently invoked on \tcode{*this}; +\item +otherwise, +if this invocation of \exposid{consume} happens after +an invocation of \exposid{try-set-stopped} on \tcode{*this} and +no invocation of \exposid{complete} on \tcode{*this} happened before +this invocation of \exposid{consume} then +\tcode{rcvr} is completed as if by \tcode{set_stopped(std::move(rcvr))}; + \item otherwise, \tcode{rcvr} is completed as if by: @@ -5521,10 +5560,34 @@ }, std::move(tuple)); } }); +destroy(); \end{codeblock} \end{itemize} \end{itemdescr} +\indexlibrarymember{\exposid{try-set-stopped}}{execution::\exposid{spawn-future-state}}% +\begin{itemdecl} +void @\exposid{try-set-stopped}@() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +\begin{itemize} +\item +If an invocation of \exposid{consume} on \tcode{*this} happens before +this invocation of \exposid{try-set-stopped} and +no invocation of \exposid{complete} on \tcode{*this} happened before +this invocation of \exposid{try-set-stopped} then +there is a receiver, \tcode{rcvr}, registered and +that receiver is deregistered and completed as if by +\tcode{set_stopped(std::move(rcvr)), \exposid{destroy}()}; + +\item +otherwise, no effects. +\end{itemize} +\end{itemdescr} + \indexlibrarymember{\exposid{abandon}}{execution::\exposid{spawn-future-state}}% \begin{itemdecl} void @\exposid{abandon}@() noexcept; @@ -5567,6 +5630,87 @@ \end{codeblock} \end{itemdescr} +\pnum +Let \exposid{future-operation} be the exposition-only class template: + +\begin{codeblock} +namespace std::execution { + template + struct @\exposid{future-operation}@ { // \expos + struct @\exposid{callback}@ { // \expos + @\exposid{try-cancelable}@* @\exposid{state}@; // \expos + + void operator()() noexcept { + @\exposid{state}@->@\exposid{try-cancel}@(); + }; + }; + + using @\exposid{stop-token-t}@ = // \expos + stop_token_of_t>; + + using @\exposid{stop-callback-t}@ = // \expos + stop_callback_for_t<@\exposid{stop-token-t}@, @\exposid{callback}@>; + + struct @\exposid{receiverx}@ { // \expos + using receiver_concept = receiver_t; + @\exposid{future-operation}@* @\exposid{op}@; // \expos + + template + void set_value(T&&... ts) && noexcept { + @\exposid{op}@->@\exposid{set-complete}@(std::forward(ts)...); + } + + template + void set_error(E&& e) && noexcept { + @\exposid{op}@->@\exposid{set-complete}@(std::forward(e)); + } + + void set_stopped() && noexcept { + @\exposid{op}@->@\exposid{set-complete}@(); + } + + env_of_t get_env() const noexcept { + return execution::get_env(@\exposid{op}@->@\exposid{rcvr}@); + } + }; + + Rcvr @\exposid{rcvr}@; // \expos + StatePtr @\exposid{state}@; // \expos + @\exposid{receiverx}@ @\exposid{inner}@; // \expos + optional<@\exposid{stop-callback-t}@> @\exposid{stopCallback}@; // \expos + + + @\exposid{future-operation}@(StatePtr state, Rcvr rcvr) noexcept // \expos + : @\exposid{rcvr}@(std::move(rcvr)), @\exposid{state}@(std::move(state)), @\exposid{inner}@(this) + {} + + @\exposid{future-operation}@(@\exposid{future-operation}@&&) = delete; + + void @\exposid{run}@() & noexcept { // \expos + constexpr bool nothrow = + is_nothrow_constructible_v<@\exposid{stop-callback-t}@, @\exposid{stop-token-t}@, @\exposid{callback}@>; + try { + @\exposid{stopCallback}@.emplace(get_stop_token(@\exposid{rcvr}@), @\exposid{callback}@(@\exposid{state}@.get())); + } + catch (...) { + if constexpr (!nothrow) { + set_error(std::move(@\exposid{rcvr}@), current_exception()); + return; + } + } + + @\exposid{state}@.release()->@\exposid{consume}@(@\exposid{innex}@); + } + + template + void @\exposid{set-complete}@(T&&... ts) noexcept { // \expos + @\exposid{stopCallback}@.reset(); + CPO{}(std::move(@\exposid{rcvr}@), std::forward(ts)...); + } + }; +} +\end{codeblock} + \pnum The exposition-only class template \exposid{impls-for}\iref{exec.snd.expos} is specialized for \tcode{spawn_future_t} as follows: @@ -5577,6 +5721,7 @@ template<> struct @\exposid{impls-for}@ : @\exposid{default-impls}@ { static constexpr auto @\exposid{start}@ = @\seebelow@; // \expos + static constexpr auto @\exposid{get-state}@ = @\seebelow@; // \expos }; } \end{codeblock} @@ -5585,8 +5730,19 @@ The member \tcode{\exposid{impls-for}::\exposid{start}} is initialized with a callable object equivalent to the following lambda: \begin{codeblock} -[](auto& state, auto& rcvr) noexcept -> void { - state->@\exposid{consume}@(rcvr); +[](auto& state, auto&) noexcept -> void { + state.@\exposid{run}@(); +} +\end{codeblock} + +\pnum +The member \tcode{\exposid{impls-for}::\exposid{get-state}} +is initialized with a callable object equivalent to the following lambda: +\begin{codeblock} +[](Sndr sndr, Rcvr& rcvr) noexcept { + auto& [_, data] = sndr; + using state_ptr = remove_cvref_t; + return @\exposid{future-operation}@(std::move(data), std::move(rcvr)); } \end{codeblock} @@ -6386,7 +6542,7 @@ class @\exposid{run-loop-scheduler}@; // \expos class @\exposid{run-loop-sender}@; // \expos struct @\exposid{run-loop-opstate-base}@ { // \expos - virtual void @\exposid{execute}@() = 0; // \expos + virtual void @\exposid{execute}@() noexcept = 0; // \expos run_loop* @\exposid{loop}@; // \expos @\exposid{run-loop-opstate-base}@* @\exposid{next}@; // \expos }; @@ -6394,8 +6550,8 @@ using @\exposid{run-loop-opstate}@ = @\unspec@; // \expos // \ref{exec.run.loop.members}, member functions - @\exposid{run-loop-opstate-base}@* @\exposid{pop-front}@(); // \expos - void @\exposid{push-back}@(@\exposid{run-loop-opstate-base}@*); // \expos + @\exposid{run-loop-opstate-base}@* @\exposid{pop-front}@() noexcept; // \expos + void @\exposid{push-back}@(@\exposid{run-loop-opstate-base}@*) noexcept; // \expos public: // \ref{exec.run.loop.ctor}, constructor and destructor @@ -6404,9 +6560,9 @@ ~run_loop(); // \ref{exec.run.loop.members}, member functions - @\exposid{run-loop-scheduler}@ get_scheduler(); - void run(); - void finish(); + @\exposid{run-loop-scheduler}@ get_scheduler() noexcept; + void run() noexcept; + void finish() noexcept; }; } \end{codeblock} @@ -6506,11 +6662,7 @@ \item The expression \tcode{start($o$)} is equivalent to: \begin{codeblock} -try { - @$o$@.@\exposid{loop}@->@\exposid{push-back}@(addressof(@$o$@)); -} catch(...) { - set_error(std::move(@\exposid{REC}@(@$o$@)), current_exception()); -} +@$o$@.@\exposid{loop}@->@\exposid{push-back}@(addressof(@$o$@)); \end{codeblock} \end{itemize} @@ -6545,7 +6697,7 @@ \rSec3[exec.run.loop.members]{Member functions} \begin{itemdecl} -@\exposid{run-loop-opstate-base}@* @\exposid{pop-front}@(); +@\exposid{run-loop-opstate-base}@* @\exposid{pop-front}@() noexcept; \end{itemdecl} \begin{itemdescr} @@ -6566,7 +6718,7 @@ \end{itemdescr} \begin{itemdecl} -void @\exposid{push-back}@(@\exposid{run-loop-opstate-base}@* item); +void @\exposid{push-back}@(@\exposid{run-loop-opstate-base}@* item) noexcept; \end{itemdecl} \begin{itemdescr} @@ -6583,7 +6735,7 @@ \indexlibrarymember{get_scheduler}{run_loop}% \begin{itemdecl} -@\exposid{run-loop-scheduler}@ get_scheduler(); +@\exposid{run-loop-scheduler}@ get_scheduler() noexcept; \end{itemdecl} \begin{itemdescr} @@ -6595,7 +6747,7 @@ \indexlibrarymember{run}{run_loop}% \begin{itemdecl} -void run(); +void run() noexcept; \end{itemdecl} \begin{itemdescr} @@ -6623,7 +6775,7 @@ \indexlibrarymember{finish}{run_loop}% \begin{itemdecl} -void finish(); +void finish() noexcept; \end{itemdecl} \begin{itemdescr} @@ -6714,31 +6866,42 @@ Let \tcode{rcvr} be an rvalue expression of type \exposid{awaitable-receiver}, let \tcode{crcvr} be a const lvalue that refers to \tcode{rcvr}, let \tcode{vs} be a pack of subexpressions, and -let \tcode{err} be an expression of type \tcode{Err}. Then: +let \tcode{err} be an expression of type \tcode{Err}. +Let \tcode{\placeholder{MAKE-NOEXCEPT}(expr)} +for some subexpression \tcode{expr} be expression-equivalent to +\tcode{[\&] noexcept -> decltype(auto) \{ return (expr); \}()}. +Then: \begin{itemize} \item -If \tcode{\libconcept{constructible_from}<\exposid{result-type}, decltype((vs))...>} -is satisfied, -the expression \tcode{set_value(\newline rcvr, vs...)} is equivalent to: +The expression \tcode{set_value(rcvr, vs...)} is equivalent to: \begin{codeblock} try { rcvr.@\exposid{result-ptr}@->template emplace<1>(vs...); } catch(...) { rcvr.@\exposid{result-ptr}@->template emplace<2>(current_exception()); } -rcvr.@\exposid{continuation}@.resume(); +@\placeholder{MAKE-NOEXCEPT}@(rcvr.@\exposid{continuation}@.resume()); \end{codeblock} -Otherwise, \tcode{set_value(rcvr, vs...)} is ill-formed. + +\mandates +\tcode{\libconcept{constructible_from}<\exposid{result-type}, decltype((vs))...>} +is satisfied. \item The expression \tcode{set_error(rcvr, err)} is equivalent to: \begin{codeblock} -rcvr.@\exposid{result-ptr}@->template emplace<2>(@\exposid{AS-EXCEPT-PTR}@(err)); // see \ref{exec.general} -rcvr.@\exposid{continuation}@.resume(); +try { + rcvr.@\exposid{result-ptr}@->template emplace<2>(@\exposid{AS-EXCEPT-PTR}@(err)); // see \ref{exec.general} +} catch(...) { + rcvr.@\exposid{result-ptr}@->template emplace<2>(current_exception()); +} +@\placeholder{MAKE-NOEXCEPT}@(rcvr.@\exposid{continuation}@.resume()); \end{codeblock} \item The expression \tcode{set_stopped(rcvr)} is equivalent to: \begin{codeblock} -static_cast>(rcvr.@\exposid{continuation}@.promise().unhandled_stopped()).resume(); +@\placeholder{MAKE-NOEXCEPT}@( + static_cast>( + rcvr.@\exposid{continuation}@.promise().unhandled_stopped()).resume()); \end{codeblock} \item For any expression \tcode{tag} @@ -6746,7 +6909,8 @@ for any pack of subexpressions \tcode{as}, \tcode{get_env(crcvr).query(tag, as...)} is expression-equivalent to: \begin{codeblock} -tag(get_env(as_const(crcvr.@\exposid{continuation}@.promise())), as...) +tag(get_env(as_const(@\placeholder{MAKE-NOEXCEPT}@(crcvr.@\exposid{continuation}@.promise()))), + as...) \end{codeblock} \end{itemize} @@ -7284,8 +7448,22 @@ \tcode{set_error_t(E)} for some type \tcode{E}. \pnum -\tcode{allocator_type} shall meet the \oldconcept{Allocator} -requirements. +The type alias \tcode{completion_signatures} is a specialization +of \tcode{execution::completion_signatures} with the template +arguments (in unspecified order): +\begin{itemize} +\item \tcode{set_value_t()} if \tcode{T} is \tcode{void}, +and \tcode{set_value_t(T)} otherwise; +\item template arguments of the specialization of +\tcode{execution::completion_signatures} denoted by \tcode{error_types}; +and +\item \tcode{set_stopped_t()}. +\end{itemize} + +\pnum +\tcode{allocator_type} shall meet the \oldconcept{Allocator} requirements, +\tcode{scheduler_type} shall model \libconcept{scheduler}, and +\tcode{stop_source_type} shall model \exposconcept{stoppable-source}. \rSec3[task.members]{\tcode{task} members} @@ -7375,12 +7553,17 @@ void start() & noexcept; + stop_token_type @\exposidnc{get-stop-token}@(); // \expos + private: using @\exposidnc{own-env-t}@ = @\seebelownc@; // \expos coroutine_handle @\exposidnc{handle}@; // \expos remove_cvref_t @\exposidnc{rcvr}@; // \expos + optional @\exposidnc{source}@; // \expos @\exposidnc{own-env-t}@ @\exposidnc{own-env}@; // \expos Environment @\exposidnc{environment}@; // \expos + optional @\exposidnc{result}@; // \expos; present only if \tcode{is_void_v} is \tcode{false} + exception_ptr @\exposidnc{error}@; // \expos }; } \end{codeblock} @@ -7446,24 +7629,32 @@ if that expression is valid and \tcode{scheduler_type()} otherwise. If neither of these expressions is valid, the program is ill-formed. \end{itemize} -Let \tcode{\placeholder{st}} be \tcode{get_stop_token(get_env(\exposid{rcvr}))}. -Initializes \tcode{\placeholder{prom}.\exposid{token}} and -\tcode{\placeholder{prom}.\exposid{source}} such that +After that invokes \tcode{\exposid{handle}.resume()}. +\end{itemdescr} + +\indexlibrarymember{\exposid{get-stop-token}}{task::\exposid{state}}% +\begin{itemdecl} +stop_token_type @\exposidnc{get-stop-token}@(); // \expos +\end{itemdecl} +\begin{itemdescr} +\pnum +\effects +If +\tcode{\libconcept{same_as}().get_token()), decltype(get_\linebreak{}stop_token(get_env(\exposid{rcvr})))>} +is \tcode{true} +returns \tcode{get_stop_token(get_env(\exposid{rcvr}))}. +Otherwise, if \tcode{\exposid{source}.has_value()} is \tcode{false}, +initializes the contained value of \exposid{source} such that \begin{itemize} \item -\tcode{\placeholder{prom}.\exposid{token}.stop_requested()} returns -\tcode{\placeholder{st}.stop_requested()}; -\item -\tcode{\placeholder{prom}.\exposid{token}.stop_possible()} returns -\tcode{\placeholder{st}.stop_possible()}; and +\tcode{\exposid{source}->stop_requested()} returns +\tcode{get_stop_token(get_env(\exposid{rcvr}))->stop_requested()};\linebreak +and \item -for types \tcode{Fn} and \tcode{Init} such that both -\tcode{\libconcept{invocable}} and -\tcode{\libconcept{constructible_from}} are modeled, -\tcode{stop_token_type::callback_type} models -\tcode{\exposconcept{stoppable-callback-for}}. +\tcode{\exposid{source}->stop_possible()} returns +\tcode{get_stop_token(get_env(\exposid{rcvr}))->stop_possible()}. \end{itemize} -After that invokes \tcode{\exposid{handle}.resume()}. +Finally, returns \tcode{\exposid{source}->get_token()}. \end{itemdescr} \rSec3[task.promise]{Class \tcode{task::promise_type}} @@ -7507,10 +7698,6 @@ using @\exposidnc{error-variant}@ = @\seebelownc@; // \expos allocator_type @\exposidnc{alloc}@; // \expos - stop_source_type @\exposidnc{source}@; // \expos - stop_token_type @\exposidnc{token}@; // \expos - optional @\exposidnc{result}@; // \expos; present only if \tcode{is_void_v} is \tcode{false} - @\exposidnc{error-variant}@ @\exposidnc{errors}@; // \expos }; } \end{codeblock} @@ -7527,13 +7714,6 @@ during evaluation of \tcode{task::\exposid{state}::start} for some receiver \tcode{Rcvr}. -\pnum -\exposid{error-variant} is a \tcode{variant...>}, with duplicate types removed, where \tcode{E...} -are the parameter types of the template arguments of the specialization of -\tcode{execution::completion_signatures} denoted by -\tcode{error_types}. - \indexlibraryctor{task::promise_type}% \begin{itemdecl} template @@ -7573,17 +7753,19 @@ \returns An awaitable object of unspecified type\iref{expr.await} whose member functions arrange for the completion of the asynchronous -operation associated with \tcode{\exposid{STATE}(*this)} by invoking: +operation associated with \tcode{\exposid{STATE}(*this)}. +Let \tcode{st} be a reference to \tcode{\exposid{STATE}(*this)}. +The asynchronous completion first destroys the coroutine frame +using \tcode{st.\exposid{handle}.destroy()} and then invokes: \begin{itemize} \item -\tcode{set_error(std::move(\exposid{RCVR}(*this)), std::move(e))} -if \tcode{\exposid{errors}.index()} is greater than zero and -\tcode{e} is the value held by \exposid{errors}, otherwise +\tcode{set_error(std::move(st.\exposid{rcvr}), std::move(st.\exposid{error}))} +if \tcode{bool(st.\exposid{error})} is \tcode{true}, otherwise \item -\tcode{set_value(std::move(\exposid{RCVR}(*this)))} if \tcode{is_void} is \tcode{true}, +\tcode{set_value(std::move(st.\exposid{rcvr}))} if \tcode{is_void_v} is \tcode{true}, and otherwise \item - \tcode{set_value(std::move(\exposid{RCVR}(*this)), std::move(*\exposid{result}))}. + \tcode{set_value(std::move(st.\exposid{rcvr}), *std::move(st.\exposid{result}))}. \end{itemize} \end{itemdescr} @@ -7604,7 +7786,12 @@ An awaitable object of unspecified type\iref{expr.await} whose member functions arrange for the calling coroutine to be suspended and then completes the asynchronous operation associated with -\tcode{\exposid{STATE}(*this)} by invoking \tcode{set_error(std::move(\exposid{RCVR}(*this)), +\tcode{\exposid{STATE}(*this)}. +Let \tcode{st} be a reference to \tcode{\exposid{STATE}(*this)}. +Then the asynchronous operation completes by first +destroying the coroutine frame using \tcode{st.\exposid{handle}.destroy()} +and then invoking +\tcode{set_error(std::move(st.\exposid{rcvr}), \placeholder{Cerr}(std::move(err.error)))}. \end{itemdescr} @@ -7645,7 +7832,8 @@ \effects If the signature \tcode{set_error_t(exception_ptr)} is not an element of \tcode{error_types}, calls \tcode{terminate()}\iref{except.terminate}. -Otherwise, stores \tcode{current_exception()} into \exposid{errors}. +Otherwise, stores \tcode{current_exception()} into +\tcode{\exposid{STATE}(*this).\exposid{error}}. \end{itemdescr} \indexlibrarymember{unhandled_stopped}{task::promise_type}% @@ -7655,8 +7843,12 @@ \begin{itemdescr} \pnum \effects -Completes the asynchronous operation associated with \tcode{\exposid{STATE}(*this)} -by invoking \tcode{set_stopped(std::move(\exposid{RCVR}(*this)))}. +Completes the asynchronous operation associated with \tcode{\exposid{STATE}(*this)}. +Let \tcode{st} be a reference to \tcode{\exposid{STATE}(*this)}. +The asynchronous operation is completed by first +destroying the coroutine frame +using \tcode{st.\exposid{handle}.destroy()} and then +invoking \tcode{set_stopped(std::move(st.\exposid{rcvr}))}. \end{itemdescr} \begin{itemdescr} \pnum @@ -7696,10 +7888,11 @@ \begin{itemize} \item \tcode{env.query(get_scheduler)} returns \tcode{scheduler_type(\exposid{SCHED}(*this))}. \item \tcode{env.query(get_allocator)} returns \exposid{alloc}. -\item \tcode{env.query(get_stop_token)} returns \exposid{token}. +\item \tcode{env.query(get_stop_token)} returns +\tcode{\exposid{STATE}(*this).\exposid{get-stop-token}()}. \item For any other query \tcode{q} and arguments \tcode{a...} a call to \tcode{env.query(q, a...)} returns -\tcode{\exposid{STATE}(*this)}. \tcode{environment.query(q, a...)} if this expression +\tcode{\exposid{STATE}(*this)}. \tcode{\exposid{environment}.query(q, a...)} if this expression is well-formed and \tcode{forwarding_query(q)} is well-formed and is \tcode{true}. Otherwise \tcode{env.query(q, a...)} is ill-formed. \end{itemize} @@ -8266,12 +8459,11 @@ \begin{itemdescr} \pnum \effects -If \exposid{state} is +If \tcode{count} is zero, then +changes \exposid{state} to \exposid{joined} and returns \tcode{true}. +Otherwise, if \exposid{state} is \begin{itemize} \item -\exposid{unused}, \exposid{unused-and-closed}, or \exposid{joined}, then -changes \exposid{state} to \exposid{joined} and returns \tcode{true}; -\item \exposid{open} or \exposid{open-and-joining}, then changes \exposid{state} to \exposid{open-and-joining}, registers \tcode{st} with \tcode{*this} and returns \tcode{false}; diff --git a/source/iostreams.tex b/source/iostreams.tex index a430c8dc69..7613d622b2 100644 --- a/source/iostreams.tex +++ b/source/iostreams.tex @@ -7927,7 +7927,7 @@ Equivalent to: \begin{codeblock} string out = vformat(fmt, args); -vprint_nonunicode("{}", make_format_args(out)); +vprint_nonunicode(stream, "{}", make_format_args(out)); \end{codeblock} \end{itemdescr} diff --git a/source/iterators.tex b/source/iterators.tex index 7d97d4395a..ed599d9725 100644 --- a/source/iterators.tex +++ b/source/iterators.tex @@ -1692,6 +1692,9 @@ \range{++i}{s} denotes a range. \item \tcode{\libconcept{assignable_from}} is either modeled or not satisfied. + +\item If \tcode{I} and \tcode{S} are the same type, then + \tcode{i == i} is \tcode{true}. \end{itemize} \end{itemdescr} diff --git a/source/memory.tex b/source/memory.tex index eb7c889a51..d8327daa70 100644 --- a/source/memory.tex +++ b/source/memory.tex @@ -3468,9 +3468,9 @@ constexpr long use_count() const noexcept; constexpr explicit operator bool() const noexcept; template - constexpr bool owner_before(const shared_ptr& b) const noexcept; + bool owner_before(const shared_ptr& b) const noexcept; template - constexpr bool owner_before(const weak_ptr& b) const noexcept; + bool owner_before(const weak_ptr& b) const noexcept; size_t owner_hash() const noexcept; template constexpr bool owner_equal(const shared_ptr& b) const noexcept; @@ -4076,8 +4076,8 @@ \indexlibrarymember{owner_before}{shared_ptr}% \begin{itemdecl} -template constexpr bool owner_before(const shared_ptr& b) const noexcept; -template constexpr bool owner_before(const weak_ptr& b) const noexcept; +template bool owner_before(const shared_ptr& b) const noexcept; +template bool owner_before(const weak_ptr& b) const noexcept; \end{itemdecl} \begin{itemdescr} @@ -4793,9 +4793,9 @@ constexpr bool expired() const noexcept; constexpr shared_ptr lock() const noexcept; template - constexpr bool owner_before(const shared_ptr& b) const noexcept; + bool owner_before(const shared_ptr& b) const noexcept; template - constexpr bool owner_before(const weak_ptr& b) const noexcept; + bool owner_before(const weak_ptr& b) const noexcept; size_t owner_hash() const noexcept; template constexpr bool owner_equal(const shared_ptr& b) const noexcept; @@ -4992,8 +4992,8 @@ \indexlibrarymember{owner_before}{weak_ptr}% \begin{itemdecl} -template constexpr bool owner_before(const shared_ptr& b) const noexcept; -template constexpr bool owner_before(const weak_ptr& b) const noexcept; +template bool owner_before(const shared_ptr& b) const noexcept; +template bool owner_before(const weak_ptr& b) const noexcept; \end{itemdecl} \begin{itemdescr} @@ -5067,26 +5067,26 @@ template struct owner_less; template struct owner_less> { - constexpr bool operator()(const shared_ptr&, const shared_ptr&) const noexcept; - constexpr bool operator()(const shared_ptr&, const weak_ptr&) const noexcept; - constexpr bool operator()(const weak_ptr&, const shared_ptr&) const noexcept; + bool operator()(const shared_ptr&, const shared_ptr&) const noexcept; + bool operator()(const shared_ptr&, const weak_ptr&) const noexcept; + bool operator()(const weak_ptr&, const shared_ptr&) const noexcept; }; template struct owner_less> { - constexpr bool operator()(const weak_ptr&, const weak_ptr&) const noexcept; - constexpr bool operator()(const shared_ptr&, const weak_ptr&) const noexcept; - constexpr bool operator()(const weak_ptr&, const shared_ptr&) const noexcept; + bool operator()(const weak_ptr&, const weak_ptr&) const noexcept; + bool operator()(const shared_ptr&, const weak_ptr&) const noexcept; + bool operator()(const weak_ptr&, const shared_ptr&) const noexcept; }; template<> struct owner_less { template - constexpr bool operator()(const shared_ptr&, const shared_ptr&) const noexcept; + bool operator()(const shared_ptr&, const shared_ptr&) const noexcept; template - constexpr bool operator()(const shared_ptr&, const weak_ptr&) const noexcept; + bool operator()(const shared_ptr&, const weak_ptr&) const noexcept; template - constexpr bool operator()(const weak_ptr&, const shared_ptr&) const noexcept; + bool operator()(const weak_ptr&, const shared_ptr&) const noexcept; template - constexpr bool operator()(const weak_ptr&, const weak_ptr&) const noexcept; + bool operator()(const weak_ptr&, const weak_ptr&) const noexcept; using is_transparent = @\unspec@; }; @@ -6566,7 +6566,7 @@ \begin{itemdecl} template constexpr bool operator==(const indirect& lhs, const indirect& rhs) - noexcept(noexcept(*lhs == *rhs)); + noexcept(noexcept(bool(*lhs == *rhs))); \end{itemdecl} \begin{itemdescr} @@ -6605,7 +6605,8 @@ %FIXME: "friend" included on declaration in synopsis but not here. \begin{itemdecl} template - constexpr bool operator==(const indirect& lhs, const U& rhs) noexcept(noexcept(*lhs == rhs)); + constexpr bool operator==(const indirect& lhs, const U& rhs) + noexcept(noexcept(bool(*lhs == rhs))); \end{itemdecl} \begin{itemdescr} @@ -6929,8 +6930,9 @@ considering that owned object as an rvalue. Otherwise, if \tcode{\exposid{alloc} != other.\exposid{alloc}} is \tcode{true}, -constructs an object of type \tcode{polymorphic}, -considering the owned object in \tcode{other} as an rvalue, +constructs an owned object of type \tcode{U}, +where \tcode{U} is the type of the owned object in \tcode{other}, +with the owned object in \tcode{other} as an rvalue, using the allocator \exposid{alloc}. \end{itemdescr} @@ -7127,7 +7129,10 @@ \pnum \effects If \tcode{*this} is not valueless, -destroys the owned object using \tcode{allocator_traits::de\-stroy} and +calls \tcode{allocator_traits::destroy(p)}, +where \tcode{p} is a pointer of type \tcode{U*} to +the owned object and +\tcode{U} is the type of the owned object; then the storage is deallocated. \end{itemdescr} @@ -7159,7 +7164,9 @@ \item If \tcode{other} is not valueless, -a new owned object is constructed in \tcode{*this} using +a new owned object of type \tcode{U}, +where \tcode{U} is the type of the owned object in \tcode{other}, +is constructed in \tcode{*this} using \tcode{allocator_traits::construct} with the owned object from \tcode{other} as the argument, using either the allocator in \tcode{*this} or @@ -7225,7 +7232,9 @@ \item Otherwise, -constructs a new owned object with the owned object of +constructs a new owned object of type \tcode{U}, +where \tcode{U} is the type of the owned object in \tcode{other}, +with the owned object of \tcode{other} as the argument as an rvalue, using the allocator in \tcode{*this}. diff --git a/source/meta.tex b/source/meta.tex index b2a168331b..b6f5ccfbcc 100644 --- a/source/meta.tex +++ b/source/meta.tex @@ -257,7 +257,6 @@ template struct is_abstract; template struct is_final; template struct is_aggregate; - template struct is_consteval_only; template struct is_signed; template struct is_unsigned; @@ -510,8 +509,6 @@ constexpr bool @\libglobal{is_final_v}@ = is_final::value; template constexpr bool @\libglobal{is_aggregate_v}@ = is_aggregate::value; - template - constexpr bool @\libglobal{is_consteval_only_v}@ = is_consteval_only::value; template constexpr bool @\libglobal{is_signed_v}@ = is_signed::value; template @@ -1197,12 +1194,6 @@ \tcode{T} is an aggregate type\iref{dcl.init.aggr} & \tcode{T} shall be an array type, a complete type, or \cv~\keyword{void}. \\ \rowsep -\indexlibraryglobal{is_consteval_only}% -\tcode{template}\br - \tcode{struct is_consteval_only;} & - \tcode{T} is consteval-only\iref{basic.types.general} & - \tcode{remove_all_extents_t} shall be a complete type or \cv~\keyword{void}. \\ \rowsep - \indexlibrary{\idxcode{is_signed}!class}% \tcode{template}\br \tcode{struct is_signed;} & @@ -2932,7 +2923,7 @@ template consteval const ranges::range_value_t* define_static_string(R&& r); template - consteval span> define_static_array(R&& r); + consteval span, \seebelow> define_static_array(R&& r); template consteval const remove_cvref_t* define_static_object(T&& r); } @@ -3160,7 +3151,6 @@ consteval bool is_abstract_type(info type); consteval bool is_final_type(info type); consteval bool is_aggregate_type(info type); - consteval bool is_consteval_only_type(info type); consteval bool is_signed_type(info type); consteval bool is_unsigned_type(info type); consteval bool is_bounded_array_type(info type); @@ -3327,8 +3317,17 @@ \pnum Any function in namespace \tcode{std::meta} whose return type is \tcode{string_view} or \tcode{u8string_view} +%FIXME: V should not be \exposid since it's not a declared \expos varible, +%use math font or \placeholder instead. returns an object \exposid{V} such that \tcode{\exposid{V}.data()[\exposid{V}.size()]} equals \tcode{'\textbackslash 0'}. +Each element of the range +\tcode{\exposid{V}.data() +} \range{0}{\exposid{V}.size()} +is a potentially non-unique object with static storage duration that +is usable in constant expressions\iref{intro.object, expr.const}; +a pointer to such an element is not suitable for use as +a template argument for a constant template parameter of +pointer type\iref{temp.arg.nontype}. \begin{example} \begin{codeblock} struct C { }; @@ -3514,7 +3513,7 @@ \indexlibraryglobal{define_static_array}% \begin{itemdecl} template - consteval span> define_static_array(R&& r); + consteval span, \seebelow> define_static_array(R&& r); \end{itemdecl} \begin{itemdescr} @@ -3525,10 +3524,18 @@ using T = ranges::range_value_t; meta::info array = meta::reflect_constant_array(r); if (meta::is_array_type(meta::type_of(array))) { - return span(meta::extract(array), meta::extent(meta::type_of(array))); + return span(meta::extract(array), + meta::extent(meta::type_of(array))); } else { - return span(); + return span(static_cast(nullptr), 0); } + +\pnum +\remarks +The second template argument of the returned \tcode{span} type +is \tcode{static_cast(ranges::size(r))} +if \tcode{ranges::size(r)} is a constant expression, and +\tcode{dynamic_extent} otherwise. \end{codeblock} \end{itemdescr} @@ -3905,10 +3912,12 @@ Otherwise, if \tcode{r} represents a direct base class relationship, then \tcode{has_identifier(type_of(r))}. \item - Otherwise, \tcode{r} represents a data member description + Otherwise, if \tcode{r} represents a data member description $(T, N, A, W, \mathit{NUA})$\iref{class.mem.general}; \tcode{true} if $N$ is not $\bot$. Otherwise, \tcode{false}. +\item + Otherwise, \tcode{false}. \end{itemize} \end{itemdescr} @@ -6843,7 +6852,6 @@ consteval bool @\libglobal{is_abstract_type}@(info type); consteval bool @\libglobal{is_final_type}@(info type); consteval bool @\libglobal{is_aggregate_type}@(info type); -consteval bool @\libglobal{is_consteval_only_type}@(info type); consteval bool @\libglobal{is_signed_type}@(info type); consteval bool @\libglobal{is_unsigned_type}@(info type); consteval bool @\libglobal{is_bounded_array_type}@(info type); diff --git a/source/ranges.tex b/source/ranges.tex index 18bed31c3c..61cc34d210 100644 --- a/source/ranges.tex +++ b/source/ranges.tex @@ -8791,6 +8791,8 @@ constexpr auto size() requires (@\libconcept{sized_range}@ && ...); constexpr auto size() const requires (@\libconcept{sized_range}@ && ...); + constexpr auto reserve_hint() requires (@\libconcept{approximately_sized_range}@ && ...); + constexpr auto reserve_hint() const requires (@\libconcept{approximately_sized_range}@ && ...); }; template @@ -8963,6 +8965,26 @@ \end{codeblock} \end{itemdescr} +\indexlibrarymember{reserve_hint}{concat_view}% +\begin{itemdecl} +constexpr auto reserve_hint() requires (@\libconcept{approximately_sized_range}@ && ...); +constexpr auto reserve_hint() const requires (@\libconcept{approximately_sized_range}@ && ...); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +return apply( + [](auto... sizes) { + using CT = @\exposid{make-unsigned-like-t}@>; + return (CT(sizes) + ...); + }, + @\exposid{tuple-transform}@(ranges::reserve_hint, @\exposid{views_}@)); +\end{codeblock} +\end{itemdescr} + \rSec3[range.concat.iterator]{Class \tcode{concat_view::\exposid{iterator}}} \indexlibrarymember{iterator}{concat_view}% @@ -10237,7 +10259,10 @@ namespace std::ranges { template concept @\defexposconcept{has-tuple-element}@ = // \expos - @\exposconcept{tuple-like}@ && N < tuple_size_v; + @\exposconcept{tuple-like}@ && N < tuple_size_v && + requires(T t) { + { std::get(t) } -> @\libconcept{convertible_to}@&>; + }; template concept @\defexposconcept{returnable-element}@ = // \expos diff --git a/source/strings.tex b/source/strings.tex index d2c0d62791..b8619c9b4b 100644 --- a/source/strings.tex +++ b/source/strings.tex @@ -2153,6 +2153,7 @@ constexpr basic_string& append(const T& t, size_type pos, size_type n = npos); constexpr basic_string& append(const charT* s, size_type n); constexpr basic_string& append(const charT* s); + constexpr basic_string& append(const charT* s, size_type pos, size_type n); constexpr basic_string& append(size_type n, charT c); template constexpr basic_string& append(InputIterator first, InputIterator last); @@ -2173,6 +2174,7 @@ constexpr basic_string& assign(const T& t, size_type pos, size_type n = npos); constexpr basic_string& assign(const charT* s, size_type n); constexpr basic_string& assign(const charT* s); + constexpr basic_string& assign(const charT* s, size_type pos, size_type n); constexpr basic_string& assign(size_type n, charT c); template constexpr basic_string& assign(InputIterator first, InputIterator last); @@ -3353,6 +3355,18 @@ Equivalent to: \tcode{return append(s, traits::length(s));} \end{itemdescr} +\indexlibrarymember{append}{basic_string}% +\begin{itemdecl} +constexpr basic_string& append(const charT* s, size_type pos, size_type n); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\tcode{return append(basic_string_view(s).substr(pos, n));} +\end{itemdescr} + \indexlibrarymember{append}{basic_string}% \begin{itemdecl} constexpr basic_string& append(size_type n, charT c); @@ -3546,6 +3560,18 @@ Equivalent to: \tcode{return assign(s, traits::length(s));} \end{itemdescr} +\indexlibrarymember{assign}{basic_string}% +\begin{itemdecl} +constexpr basic_string& assign(const charT* s, size_type pos, size_type n); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\tcode{return assign(basic_string_view(s).substr(pos, n));} +\end{itemdescr} + \indexlibrarymember{assign}{basic_string}% \begin{itemdecl} constexpr basic_string& assign(initializer_list il); diff --git a/source/support.tex b/source/support.tex index ce4a1c9271..af21337ef8 100644 --- a/source/support.tex +++ b/source/support.tex @@ -848,6 +848,8 @@ #define @\defnlibxname{cpp_lib_start_lifetime_as}@ 202207L // freestanding, also in \libheader{memory} #define @\defnlibxname{cpp_lib_starts_ends_with}@ 201711L // also in \libheader{string}, \libheader{string_view} #define @\defnlibxname{cpp_lib_stdatomic_h}@ 202011L // also in \libheader{stdatomic.h} +#define @\defnlibxname{cpp_lib_stdbit_h}@ 202603L // also in \libheader{stdbit.h} +#define @\defnlibxname{cpp_lib_stdckdint_h}@ 202603L // also in \libheader{stdckdint.h} #define @\defnlibxname{cpp_lib_string_contains}@ 202011L // also in \libheader{string}, \libheader{string_view} #define @\defnlibxname{cpp_lib_string_resize_and_overwrite}@ 202110L // also in \libheader{string} #define @\defnlibxname{cpp_lib_string_subview}@ 202506L // also in \libheader{string}, \libheader{string_view} @@ -3625,6 +3627,9 @@ static consteval source_location current() noexcept; constexpr source_location() noexcept; + constexpr source_location(const source_location&) noexcept = default; + constexpr source_location& operator=(const source_location&) noexcept = default; + // source location field access constexpr uint_least32_t line() const noexcept; constexpr uint_least32_t column() const noexcept; @@ -3641,25 +3646,14 @@ \end{codeblock} \pnum -The type \tcode{source_location} meets the -\oldconcept{DefaultConstructible}, -\oldconcept{CopyConstructible}, -\oldconcept{Copy\-Assignable}, -\oldconcept{Swappable}, and -\oldconcept{Destructible} -requirements\iref{utility.arg.requirements,swappable.requirements}. -All of the following conditions are \tcode{true}: -\begin{itemize} -\item \tcode{is_nothrow_move_constructible_v} -\item \tcode{is_nothrow_move_assignable_v} -\item \tcode{is_nothrow_swappable_v} -\end{itemize} +The type \tcode{source_location} models \libconcept{semiregular}. +\tcode{is_nothrow_swappable_v} is \tcode{true}. \begin{note} The intent of \tcode{source_location} is to have a small size and efficient copying. It is unspecified whether the copy/move constructors and the copy/move assignment operators -are trivial and/or constexpr. +are trivial. \end{note} \pnum diff --git a/source/threads.tex b/source/threads.tex index 5762bd5817..7d67eed288 100644 --- a/source/threads.tex +++ b/source/threads.tex @@ -3525,11 +3525,11 @@ \pnum \remarks A weak compare-and-exchange operation may fail spuriously. -That is, even when the contents of memory referred to -by \tcode{expected} and \tcode{ptr} are equal, +That is, even when the value representations referred to +by \tcode{expected} and \tcode{ptr} compare equal, it may return \tcode{false} and -store back to \tcode{expected} the same memory contents -that were originally there. +store back to \tcode{expected} +the same value representation that was originally there. \begin{note} This spurious failure enables implementation of compare-and-exchange on a broader class of machines, e.g., load-locked store-conditional machines. @@ -4805,7 +4805,7 @@ pointed to by \keyword{this} during the atomic comparison. If the operation returns \tcode{true}, these operations are atomic read-modify-write -operations\iref{intro.multithread} on the memory +operations\iref{intro.races} on the memory pointed to by \keyword{this}. Otherwise, these operations are atomic load operations on that memory. @@ -4849,6 +4849,7 @@ \end{example} \pnum +\recommended Implementations should ensure that weak compare-and-exchange operations do not consistently return \tcode{false} unless either the atomic object has value different from \tcode{expected} or there are concurrent modifications to the @@ -4857,9 +4858,11 @@ \pnum \remarks A weak compare-and-exchange operation may fail spuriously. That is, even when -the contents of memory referred to by \tcode{expected} and \keyword{this} are -equal, it may return \tcode{false} and store back to \tcode{expected} the same memory -contents that were originally there. +the value representations referred to by \tcode{expected} and \keyword{this} +compare equal, +it may return \tcode{false} and +store back to \tcode{expected} +the same value representation that was originally there. \begin{note} This spurious failure enables implementation of compare-and-exchange on a broader class of diff --git a/source/utilities.tex b/source/utilities.tex index 7b5fe5d565..0d52de611a 100644 --- a/source/utilities.tex +++ b/source/utilities.tex @@ -5071,7 +5071,11 @@ this indicates that an optional object not containing a value shall be constructed. \pnum -Type \tcode{nullopt_t} shall not have a default constructor or an initializer-list constructor, and shall not be an aggregate. +Type \tcode{nullopt_t} does not have +a default constructor or an initializer-list constructor, and +is not an aggregate. +\tcode{nullopt_t} models \libconcept{copyable} and +\tcode{\libconcept{three_way_comparable}}. \rSec2[optional.bad.access]{Class \tcode{bad_optional_access}} @@ -8258,10 +8262,10 @@ friend constexpr bool operator==(const expected&, const unexpected&); private: - bool @\exposid{has_val}@; // \expos + bool @\exposid{has_val}@; // \expos union { - T @\exposid{val}@; // \expos - E @\exposid{unex}@; // \expos + remove_cv_t @\exposid{val}@; // \expos + E @\exposid{unex}@; // \expos }; }; } @@ -8736,6 +8740,18 @@ \tcode{is_nothrow_move_constructible_v || is_nothrow_move_constructible_v} is \tcode{true}. \end{itemize} + +%FIXME: Is this supposed to be part of the Remarks clause? +\pnum +This operator is trivial if: +\begin{itemize} +\item \tcode{is_trivially_copy_constructible_v} is \tcode{true}, and +\item \tcode{is_trivially_copy_assignable_v} is \tcode{true}, and +\item \tcode{is_trivially_destructible_v} is \tcode{true}, and +\item \tcode{is_trivially_copy_constructible_v} is \tcode{true}, and +\item \tcode{is_trivially_copy_assignable_v} is \tcode{true}, and +\item \tcode{is_trivially_destructible_v} is \tcode{true}. +\end{itemize} \end{itemdescr} \indexlibrarymember{operator=}{expected}% @@ -8793,6 +8809,18 @@ is_nothrow_move_assignable_v && is_nothrow_move_constructible_v && is_nothrow_move_assignable_v && is_nothrow_move_constructible_v \end{codeblock} + +%FIXME: Is this supposed to be part of the Remarks clause? +\pnum +This operator is trivial if: +\begin{itemize} +\item \tcode{is_trivially_move_constructible_v} is \tcode{true}, and +\item \tcode{is_trivially_move_assignable_v} is \tcode{true}, and +\item \tcode{is_trivially_destructible_v} is \tcode{true}, and +\item \tcode{is_trivially_move_constructible_v} is \tcode{true}, and +\item \tcode{is_trivially_move_assignable_v} is \tcode{true}, and +\item \tcode{is_trivially_destructible_v} is \tcode{true}. +\end{itemize} \end{itemdescr} \indexlibrarymember{operator=}{expected}% @@ -8987,7 +9015,7 @@ throw; } } else { - T tmp(std::move(@\exposid{val}@)); + remove_cv_t tmp(std::move(@\exposid{val}@)); destroy_at(addressof(@\exposid{val}@)); try { construct_at(addressof(@\exposid{unex}@), std::move(rhs.@\exposid{unex}@)); @@ -9940,6 +9968,14 @@ This operator is defined as deleted unless \tcode{is_copy_assignable_v} is \tcode{true} and \tcode{is_copy_constructible_v} is \tcode{true}. + +%FIXME: Is this supposed to be part of the Remarks clause? +\pnum +This operator is trivial if +\tcode{is_trivially_copy_constructible_v}, +\tcode{is_trivially_copy_assigna\-ble_v}, and +\tcode{is_trivially_destructible_v} +are all \tcode{true}. \end{itemdescr} \indexlibrarymember{operator=}{expected}% @@ -9979,6 +10015,14 @@ \remarks The exception specification is equivalent to \tcode{is_nothrow_move_constructible_v \&\& is_nothrow_move_assignable_v}. + +%FIXME: Is this supposed to be part of the Remarks clause? +\pnum +This operator is trivial if +\tcode{is_trivially_move_constructible_v}, +\tcode{is_trivially_move_assigna\-ble_v}, and +\tcode{is_trivially_destructible_v} +are all \tcode{true}. \end{itemdescr} \indexlibrarymember{operator=}{expected}% @@ -11748,19 +11792,20 @@ A \defnadj{callable}{object} is an object of a callable type. \pnum -A \defnx{call wrapper type}{call wrapper!type} is a type that holds a callable object -and supports a call operation that forwards to that object. +A \defnx{call wrapper type}{call wrapper!type} is a type that holds +a \defnadj{target}{object}, +which is either +a callable object or +an object representing a callable object, +and supports a call operation that forwards to that callable object. \pnum A \defn{call wrapper} is an object of a call wrapper type. -\pnum -A \defn{target object} is the callable object held by a call wrapper. - \pnum A call wrapper type may additionally hold a sequence of objects and references -that may be passed as arguments to the target object. +that may be passed as arguments to the callable object. These entities are collectively referred to as \defnx{bound argument entities}{bound argument entity}. @@ -13458,9 +13503,9 @@ \pnum \returns -A perfect forwarding call wrapper\iref{func.require} \tcode{g} that -does not have state entities, and -has the call pattern \tcode{!invoke(f, call_args...)}. +A perfect forwarding call wrapper\iref{func.require} \tcode{g} +whose target object is a copy of \tcode{cw}, and +whose call pattern is \tcode{!invoke(f, call_args...)}. \end{itemdescr} \rSec2[func.bind.partial]{Function templates \tcode{bind_front} and \tcode{bind_back}} @@ -13580,8 +13625,9 @@ \pnum \returns -A perfect forwarding call wrapper\iref{func.require} \tcode{g} that -does not have a target object, and has the call pattern: +A perfect forwarding call wrapper\iref{func.require} \tcode{g} +whose target object is a copy of \tcode{cw}, and +whose call pattern is: \begin{itemize} \item \tcode{invoke(f, bound_args..., call_args...)}