Skip to content

Commit 9f57dfd

Browse files
committed
fixup: add upto 34.9.11.11
1 parent 968f1ab commit 9f57dfd

File tree

1 file changed

+288
-0
lines changed

1 file changed

+288
-0
lines changed

source/exec.tex

Lines changed: 288 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3943,6 +3943,294 @@
39433943
evaluates \tcode{state.\exposid{sh_state}->\exposid{start-op}()}.
39443944
\end{itemize}
39453945

3946+
\rSec3[exec.when.all]{\tcode{execution::when_all}}
3947+
3948+
\pnum
3949+
\tcode{when_all} and \tcode{when_all_with_variant}
3950+
both adapt multiple input senders into a sender
3951+
that completes when all input senders have completed.
3952+
\tcode{when_all} only accepts senders
3953+
with a single value completion signature and
3954+
on success concatenates all the input senders' value result datums
3955+
into its own value completion operation.
3956+
\tcode{when_all_with_variant(sndrs...)} is semantically equivalent to
3957+
w\tcode{hen_all(into_variant(sndrs)...)},
3958+
where \tcode{sndrs} is a pack of subexpressions
3959+
whose types model \libconcept{sender}.
3960+
3961+
\pnum
3962+
The names \tcode{when_all} and \tcode{when_all_with_variant} denote
3963+
customization point objects.
3964+
Let \tcode{sndrs} be a pack of subexpressions,
3965+
let \tcode{Sndrs} be a pack of the types \tcode{decltype((sndrs))...}, and
3966+
let \tcode{CD} be
3967+
the type \tcode{common_type_t<decltype(\exposid{get-domain-early}(sndrs))...>}.
3968+
The expressions \tcode{when_all(sndrs...)} and
3969+
\tcode{when_all_with_variant(sndrs...)} are ill-formed
3970+
if any of the following is \tcode{true}:
3971+
\begin{itemize}
3972+
\item
3973+
\tcode{sizeof...(sndrs)} is \tcode{0}, or
3974+
\item
3975+
\tcode{(sender<Sndrs> \&\& ...)} is \tcode{false}, or
3976+
\item
3977+
\tcode{CD} is ill-formed.
3978+
\end{itemize}
3979+
3980+
\pnum
3981+
The expression \tcode{when_all(sndrs...)} is expression-equivalent to:
3982+
\begin{codeblock}
3983+
transform_sender(CD(), @\exposid{make-sender}@(when_all, {}, sndrs...))
3984+
\end{codeblock}
3985+
3986+
\pnum
3987+
The exposition-only class template \exposid{impls-for}\iref{exec.snd.general}
3988+
is specialized for \tcode{when_all_t} as follows:
3989+
\begin{codeblock}
3990+
namespace std::execution {
3991+
template<>
3992+
struct @\exposid{impls-for}@<when_all_t> : @\exposid{default-impls}@ {
3993+
static constexpr auto @\exposid{get-attrs}@ = @\seebelow@;
3994+
static constexpr auto @\exposid{get-env}@ = @\seebelow@;
3995+
static constexpr auto @\exposid{get-state}@ = @\seebelow@;
3996+
static constexpr auto @\exposid{start}@ = @\seebelow@;
3997+
static constexpr auto @\exposid{complete}@ = @\seebelow@;
3998+
};
3999+
}
4000+
\end{codeblock}
4001+
4002+
\pnum
4003+
The member \tcode{\exposid{impls-for}<when_all_t>::\exposid{get-attrs}}
4004+
is initialized with a callable object
4005+
equivalent to the following lambda expression:
4006+
\begin{codeblock}
4007+
[](auto&&, auto&&... child) noexcept {
4008+
if constexpr (@\libconcept{same_as}@<CD, default_domain>) {
4009+
return empty_env();
4010+
} else {
4011+
return @\exposid{MAKE-ENV}@(get_domain, CD());
4012+
}
4013+
}
4014+
\end{codeblock}
4015+
4016+
\pnum
4017+
The member \tcode{\exposid{impls-for}<when_all_t>::\exposid{get-env}}
4018+
is initialized with a callable object
4019+
equivalent to the following lambda expression:
4020+
\begin{codeblock}
4021+
[]<class State, class Rcvr>(auto&&, State& state, const Receiver& rcvr) noexcept {
4022+
return @\exposid{JOIN-ENV}@(
4023+
@\exposid{MAKE-ENV}@(get_stop_token, state.@\exposid{stop_src}@.get_token()), get_env(rcvr));
4024+
}
4025+
\end{codeblock}
4026+
4027+
\pnum
4028+
The member \tcode{\exposid{impls-for}<when_all_t>::\exposid{get-state}}
4029+
is initialized with a callable object
4030+
equivalent to the following lambda expression:
4031+
\begin{codeblock}
4032+
[]<class Sndr, class Rcvr>(Sndr&& sndr, Rcvr& rcvr) noexcept(@$e$@) -> decltype(e) {
4033+
return @$e$@;
4034+
}
4035+
\end{codeblock}
4036+
where $e$ is the expression
4037+
\begin{codeblock}
4038+
std::forward<Sndr>(sndr).apply(@\exposid{make-state}@<Rcvr>())
4039+
\end{codeblock}
4040+
and where \exposid{make-state} is the following exposition-only class template:
4041+
\begin{codeblock}
4042+
template<class Sndr, class Env>
4043+
concept @\defexposconcept{max-1-sender-in}@ = @\libconcept{sender_in}@<Sndr, Env> && // \expos
4044+
(tuple_size_v<value_types_of_t<Sndr, Env, tuple, tuple>> <= 1);
4045+
4046+
enum class @\exposid{disposition}@ { @\exposid{started}@, @\exposid{error}@, @\exposid{stopped}@ }; // \expos
4047+
4048+
template<class Rcvr>
4049+
struct @\exposid{make-state}@ {
4050+
template<@\exposconcept{max-1-sender-in}@<env_of_t<Rcvr>>... Sndrs>
4051+
auto operator()(auto, auto, Sndrs&&... sndrs) const {
4052+
using values_tuple = @\seebelow@;
4053+
using errors_variant = @\seebelow@;
4054+
using stop_callback = stop_callback_of_t<stop_token_of_t<env_of_t<Rcvr>>, @\exposid{on-stop-request}@>;
4055+
4056+
struct @\exposid{state-type}@ {
4057+
void arrive(Rcvr& rcvr) noexcept {
4058+
if (0 == --count) {
4059+
@\exposid{complete}@(rcvr);
4060+
}
4061+
}
4062+
4063+
void @\exposid{complete}@(Rcvr& rcvr) noexcept; // \seebelow
4064+
4065+
atomic<size_t> @\exposid{count}@{sizeof...(sndrs)}; // \expos
4066+
inplace_stop_source @\exposid{stop_src}@{}; // \expos
4067+
atomic<@\exposid{disposition}@> disp{@\exposid{disposition}@::@\exposid{started}@}; // \expos
4068+
errors_variant @\exposid{errors}@{}; // \expos
4069+
values_tuple @\exposid{values}@{}; // \expos
4070+
optional<stop_callback> @\exposid{on_stop}@{nullopt}; // \expos
4071+
};
4072+
4073+
return @\exposid{state-type}@{};
4074+
}
4075+
};
4076+
\end{codeblock}
4077+
4078+
\pnum
4079+
Let \exposid{copy-fail} be \tcode{exception_ptr}
4080+
if decay-copying any of the child senders' result datums can potentially throw;
4081+
otherwise, \exposid{none-such},
4082+
where \exposid{none-such} is an unspecified empty class type.
4083+
4084+
\pnum
4085+
The alias \tcode{values_tuple} denotes the type
4086+
\tcode{tuple<value_types_of_t<Sndrs, env_of_t<Rcvr>, decayed-tuple, optional>...>}
4087+
if that type is well-formed; otherwise, \tcode{tuple<>}.
4088+
4089+
\pnum
4090+
The alias \tcode{errors_variant} denotes
4091+
the type \tcode{variant<none-such, copy-fail, Es...>}
4092+
with duplicate types removed,
4093+
where \tcode{Es} is the pack of the decayed types
4094+
of all the child senders' possible error result datums.
4095+
4096+
\pnum
4097+
The member
4098+
\tcode{void \exposid{state-type}::\exposid{complete}(Rcvr\& rcvr) noexcept}
4099+
behaves as follows:
4100+
\begin{itemize}
4101+
\item
4102+
If \tcode{disp} is equal to \tcode{\exposid{disposition}::\exposid{started}},
4103+
evaluates:
4104+
\begin{codeblock}
4105+
auto tie = []<class... T>(tuple<T...>& t) noexcept { return tuple<T&...>(t); };
4106+
auto set = [&](auto&... t) noexcept { set_value(std::move(rcvr), std::move(t)...); };
4107+
4108+
@\exposid{on_stop}@.reset();
4109+
apply(
4110+
[&](auto&... opts) noexcept {
4111+
apply(set, tuple_cat(tie(*opts)...));
4112+
},
4113+
values);
4114+
\end{codeblock}
4115+
\item
4116+
Otherwise,
4117+
if \tcode{disp} is equal to \tcode{\exposid{disposition}::\exposid{error}},
4118+
evaluates:
4119+
\begin{codeblock}
4120+
@\exposid{on_stop}@.reset();
4121+
visit(
4122+
[&]<class Error>(Error& error) noexcept {
4123+
if constexpr (!@\libconcept{same_as}@<Error, @\exposid{none-such}@>) {
4124+
set_error(std::move(rcvr), std::move(error));
4125+
}
4126+
},
4127+
errors);
4128+
\end{codeblock}
4129+
\item
4130+
Otherwise, evaluates:
4131+
\begin{codeblock}
4132+
@\exposid{on_stop}@.reset();
4133+
set_stopped(std::move(rcvr));
4134+
\end{codeblock}
4135+
\end{itemize}
4136+
4137+
\pnum
4138+
The member \tcode{\exposid{impls-for}<when_all_t>::\exposid{start}}
4139+
is initialized with a callable object
4140+
equivalent to the following lambda expression:
4141+
\begin{codeblock}
4142+
[]<class State, class Rcvr, class... Ops>(
4143+
State& state, Rcvr& rcvr, Ops&... ops) noexcept -> void {
4144+
state.@\exposid{on_stop}@.emplace(
4145+
get_stop_token(get_env(rcvr)),
4146+
@\exposid{on-stop-request}@{state.@\exposid{stop_src}@});
4147+
if (state.@\exposid{stop_src}@.stop_requested()) {
4148+
state.@\exposid{on_stop.}@reset();
4149+
set_stopped(std::move(rcvr));
4150+
} else {
4151+
(start(ops), ...);
4152+
}
4153+
}
4154+
\end{codeblock}
4155+
4156+
\pnum
4157+
The member \exposid{\tcode{impls-for}<when_all_t>::\exposid{complete}}
4158+
is initialized with a callable object
4159+
equivalent to the following lambda expression:
4160+
\begin{codeblock}
4161+
[]<class Index, class State, class Rcvr, class Set, class... Args>(
4162+
this auto& complete, Index, State& state, Rcvr& rcvr, Set, Args&&... args) noexcept -> void {
4163+
if constexpr (@\libconcept{same_as}@<Set, set_error_t>) {
4164+
if (@\exposid{disposition}@::@\exposid{error}@ != state.disp.exchange(@\exposid{disposition}@::@\exposid{error}@)) {
4165+
state.@\exposid{stop_src}@.request_stop();
4166+
@\exposid{TRY-EMPLACE-ERROR}@(state.errors, std::forward<Args>(args)...);
4167+
}
4168+
} else if constexpr (@\libconcept{same_as}@<Set, set_stopped_t>) {
4169+
auto expected = @\exposid{disposition}@::@\exposid{started}@;
4170+
if (state.disp.compare_exchange_strong(expected, @\exposid{disposition}@::@\exposid{stopped}@)) {
4171+
state.@\exposid{stop_src}@.request_stop();
4172+
}
4173+
} else if constexpr (!@\libconcept{same_as}@<decltype(State::values), tuple<>>) {
4174+
if (state.disp == @\exposid{disposition}@::@\exposid{started}@) {
4175+
auto& opt = get<Index::value>(state.values);
4176+
@\exposid{TRY-EMPLACE-VALUE}@(complete, opt, std::forward<Args>(args)...);
4177+
}
4178+
}
4179+
state.@\exposid{arrive}@(rcvr);
4180+
}
4181+
\end{codeblock}
4182+
where \tcode{\exposid{TRY-EMPLACE-ERROR}(v, e)},
4183+
for subexpressions \tcode{v} and \tcode{e}, is equivalent to:
4184+
\begin{codeblock}
4185+
try {
4186+
v.template emplace<decltype(auto(e))>(e);
4187+
} catch (...) {
4188+
v.template emplace<exception_ptr>(current_exception());
4189+
}
4190+
\end{codeblock}
4191+
if the expression \tcode{decltype(auto(e))(e)} is potentially throwing;
4192+
otherwise, \tcode{v.template emplace<decltype(auto(e))>(e)};
4193+
and where \tcode{\exposid{TRY-EMPLACE-VALUE}(c, o, as...)},
4194+
for subexpressions \tcode{c}, \tcode{o}, and pack of subexpressions \tcode{as},
4195+
is equivalent to:
4196+
\begin{codeblock}
4197+
try {
4198+
o.emplace(as...);
4199+
} catch (...) {
4200+
c(Index(), state, rcvr, set_error, current_exception());
4201+
return;
4202+
}
4203+
\end{codeblock}
4204+
if the expression \tcode{decayed-tuple<decltype(as)...>\{as...\}}
4205+
is potentially throwing;
4206+
otherwise, \tcode{o.emplace(as...)}.
4207+
4208+
\pnum
4209+
The expression \tcode{when_all_with_variant(sndrs...)}
4210+
is expression-equivalent to:
4211+
\begin{codeblock}
4212+
transform_sender(CD(), @\exposid{make-sender}@(when_all_with_variant, {}, sndrs...));
4213+
\end{codeblock}
4214+
4215+
\pnum
4216+
Given subexpressions \tcode{sndr} and \tcode{env},
4217+
if
4218+
\tcode{\exposconcept{sender-for}<decltype((sndr)), when_all_with_variant_t>}
4219+
is \tcode{false},
4220+
then the expression \tcode{when_all_with_variant.transform_sender(sndr, env)}
4221+
is ill-formed;
4222+
otherwise, it is equivalent to:
4223+
\begin{codeblock}
4224+
auto&& [_, _, ...child] = sndr;
4225+
return when_all(into_variant(std::forward_like<decltype((sndr))>(child))...);
4226+
\end{codeblock}
4227+
\begin{note}
4228+
This causes the \tcode{when_all_with_variant(sndrs...)} sender
4229+
to become \tcode{when_all(into_variant(sndrs)...)}
4230+
when it is connected with a receiver
4231+
whose execution domain does not customize \tcode{when_all_with_variant}.
4232+
\end{note}
4233+
39464234
\rSec1[exec.util]{Sender/receiver utilities}
39474235

39484236

0 commit comments

Comments
 (0)