From Jason Turner

[exec.let]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmpxxojwcyz/{from.md → to.md} +222 -0
tmp/tmpxxojwcyz/{from.md → to.md} RENAMED
@@ -0,0 +1,222 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #### `execution::let_value`, `execution::let_error`, `execution::let_stopped` <a id="exec.let">[[exec.let]]</a>
2
+
3
+ `let_value`, `let_error`, and `let_stopped` transform a sender’s value,
4
+ error, and stopped completions, respectively, into a new child
5
+ asynchronous operation by passing the sender’s result datums to a
6
+ user-specified callable, which returns a new sender that is connected
7
+ and started.
8
+
9
+ For `let_value`, `let_error`, and `let_stopped`, let *`set-cpo`* be
10
+ `set_value`, `set_error`, and `set_stopped`, respectively. Let the
11
+ expression *`let-cpo`* be one of `let_value`, `let_error`, or
12
+ `let_stopped`. For a subexpression `sndr`, let `let-env(sndr)` be
13
+ expression-equivalent to the first well-formed expression below:
14
+
15
+ - `\exposid{SCHED-ENV}(get_completion_scheduler<\exposid{decayed-typeof}<\exposid{set-cpo}>>(get_env(sndr)))`
16
+ - `\exposid{MAKE-ENV}(get_domain, get_domain(get_env(sndr)))`
17
+ - `(void(sndr), env<>{})`
18
+
19
+ The names `let_value`, `let_error`, and `let_stopped` denote pipeable
20
+ sender adaptor objects. For subexpressions `sndr` and `f`, let `F` be
21
+ the decayed type of `f`. If `decltype((sndr))` does not satisfy `sender`
22
+ or if `decltype((f))` does not satisfy `movable-value`, the expression
23
+ `let-cpo(sndr, f)` is ill-formed. If `F` does not satisfy `invocable`,
24
+ the expression `let_stopped(sndr, f)` is ill-formed.
25
+
26
+ Otherwise, the expression `let-cpo(sndr, f)` is expression-equivalent
27
+ to:
28
+
29
+ ``` cpp
30
+ transform_sender(get-domain-early(sndr), make-sender(let-cpo, f, sndr))
31
+ ```
32
+
33
+ except that `sndr` is evaluated only once.
34
+
35
+ The exposition-only class template *`impls-for`* [[exec.snd.expos]] is
36
+ specialized for *`let-cpo`* as follows:
37
+
38
+ ``` cpp
39
+ namespace std::execution {
40
+ template<class State, class Rcvr, class... Args>
41
+ void let-bind(State& state, Rcvr& rcvr, Args&&... args); // exposition only
42
+
43
+ template<>
44
+ struct impls-for<decayed-typeof<let-cpo>> : default-impls {
45
+ static constexpr auto get-state = see below;
46
+ static constexpr auto complete = see below;
47
+
48
+ template<class Sndr, class... Env>
49
+ static consteval void check-types();
50
+ };
51
+ }
52
+ ```
53
+
54
+ Let *`receiver2`* denote the following exposition-only class template:
55
+
56
+ ``` cpp
57
+ namespace std::execution {
58
+ template<class Rcvr, class Env>
59
+ struct receiver2 {
60
+ using receiver_concept = receiver_t;
61
+
62
+ template<class... Args>
63
+ void set_value(Args&&... args) && noexcept {
64
+ execution::set_value(std::move(rcvr), std::forward<Args>(args)...);
65
+ }
66
+
67
+ template<class Error>
68
+ void set_error(Error&& err) && noexcept {
69
+ execution::set_error(std::move(rcvr), std::forward<Error>(err));
70
+ }
71
+
72
+ void set_stopped() && noexcept {
73
+ execution::set_stopped(std::move(rcvr));
74
+ }
75
+
76
+ decltype(auto) get_env() const noexcept {
77
+ return see below;
78
+ }
79
+
80
+ Rcvr& rcvr; // exposition only
81
+ Env env; // exposition only
82
+ };
83
+ }
84
+ ```
85
+
86
+ Invocation of the function `receiver2::get_env` returns an object `e`
87
+ such that
88
+
89
+ - `decltype(e)` models `queryable` and
90
+ - given a query object `q`, the expression `e.query(q)` is
91
+ expression-equivalent to `env.query(q)` if that expression is valid;
92
+ otherwise, if the type of `q` satisfies `forwarding-query`,
93
+ `e.query(q)` is expression-equivalent to `get_env(rcvr).query(q)`;
94
+ otherwise, `e.query(q)` is ill-formed.
95
+
96
+ ``` cpp
97
+ template<class Sndr, class... Env>
98
+ static consteval void check-types();
99
+ ```
100
+
101
+ *Effects:* Equivalent to:
102
+
103
+ ``` cpp
104
+ using LetFn = remove_cvref_t<data-type<Sndr>>;
105
+ auto cs = get_completion_signatures<child-type<Sndr>, FWD-ENV-T(Env)...>();
106
+ auto fn = []<class... Ts>(decayed-typeof<set-cpo>(*)(Ts...)) {
107
+ if constexpr (!is-valid-let-sender) // see below
108
+ throw unspecified-exception();
109
+ };
110
+ cs.for-each(overload-set(fn, [](auto){}));
111
+ ```
112
+
113
+ where *`unspecified-exception`* is a type derived from `exception`, and
114
+ where *`is-valid-let-sender`* is `true` if and only if all of the
115
+ following are `true`:
116
+
117
+ - `(constructible_from<decay_t<Ts>, Ts> &&...)`
118
+ - `invocable<LetFn, decay_t<Ts>&...>`
119
+ - `sender<invoke_result_t<LetFn, decay_t<Ts>&...>>`
120
+ - `sizeof...(Env) == 0 || sender_in<invoke_result_t<LetFn, decay_t<Ts>&...>, `*`env-t`*`...>`
121
+
122
+ where *`env-t`* is the pack
123
+ `decltype(`*`let-cpo`*`.transform_env(declval<Sndr>(), declval<Env>()))`.
124
+
125
+ `\exposid{impls-for}<\exposid{decayed-typeof}<\exposid{let-cpo}>>::\exposid{get-state}`
126
+
127
+ is initialized with a callable object equivalent to the following:
128
+
129
+ ``` cpp
130
+ []<class Sndr, class Rcvr>(Sndr&& sndr, Rcvr& rcvr) requires see below {
131
+ auto& [_, fn, child] = sndr;
132
+ using fn_t = decay_t<decltype(fn)>;
133
+ using env_t = decltype(let-env(child));
134
+ using args_variant_t = see below;
135
+ using ops2_variant_t = see below;
136
+
137
+ struct state-type {
138
+ fn_t fn; // exposition only
139
+ env_t env; // exposition only
140
+ args_variant_t args; // exposition only
141
+ ops2_variant_t ops2; // exposition only
142
+ };
143
+ return state-type{allocator-aware-forward(std::forward_like<Sndr>(fn), rcvr),
144
+ let-env(child), {}, {}};
145
+ }
146
+ ```
147
+
148
+ Let `Sigs` be a pack of the arguments to the `completion_signatures`
149
+ specialization named by
150
+ `completion_signatures_of_t<child-type<Sndr>, FWD-ENV-T(env_of_t<Rcvr>)>`.
151
+ Let `LetSigs` be a pack of those types in `Sigs` with a return type of
152
+ `decayed-typeof<set-cpo>`. Let *`as-tuple`* be an alias template such
153
+ that `as-tuple<Tag(Args...)>` denotes the type `decayed-tuple<Args...>`.
154
+ Then `args_variant_t` denotes the type
155
+ `variant<monostate, as-tuple<LetSigs>...>` except with duplicate types
156
+ removed.
157
+
158
+ Given a type `Tag` and a pack `Args`, let *`as-sndr2`* be an alias
159
+ template such that `as-sndr2<Tag(Args...)>` denotes the type
160
+ `call-result-t<F, decay_t<Args>&...>`. Then `ops2_variant_t` denotes the
161
+ type
162
+
163
+ ``` cpp
164
+ variant<monostate, connect_result_t<as-sndr2<LetSigs>, receiver2<Rcvr, env_t>>...>
165
+ ```
166
+
167
+ except with duplicate types removed.
168
+
169
+ The *requires-clause* constraining the above lambda is satisfied if and
170
+ only if the types `args_variant_t` and `ops2_variant_t` are well-formed.
171
+
172
+ The exposition-only function template *`let-bind`* has effects
173
+ equivalent to:
174
+
175
+ ``` cpp
176
+ using args_t = decayed-tuple<Args...>;
177
+ auto mkop2 = [&] {
178
+ return connect(
179
+ apply(std::move(state.fn),
180
+ state.args.template emplace<args_t>(std::forward<Args>(args)...)),
181
+ receiver2{rcvr, std::move(state.env)});
182
+ };
183
+ start(state.ops2.template emplace<decltype(mkop2())>(emplace-from{mkop2}));
184
+ ```
185
+
186
+ `\exposid{impls-for}<\exposid{decayed-typeof}<\exposid{let-cpo}>>::\exposid{complete}`
187
+
188
+ is initialized with a callable object equivalent to the following:
189
+
190
+ ``` cpp
191
+ []<class Tag, class... Args>
192
+ (auto, auto& state, auto& rcvr, Tag, Args&&... args) noexcept -> void {
193
+ if constexpr (same_as<Tag, decayed-typeof<set-cpo>>) {
194
+ TRY-EVAL(rcvr, let-bind(state, rcvr, std::forward<Args>(args)...));
195
+ } else {
196
+ Tag()(std::move(rcvr), std::forward<Args>(args)...);
197
+ }
198
+ }
199
+ ```
200
+
201
+ Let `sndr` and `env` be subexpressions, and let `Sndr` be
202
+ `decltype((sndr))`. If `sender-for<Sndr, decayed-typeof<let-cpo>>` is
203
+ `false`, then the expression `let-cpo.transform_env(sndr, env)` is
204
+ ill-formed. Otherwise, it is equal to:
205
+
206
+ ``` cpp
207
+ auto& [_, _, child] = sndr;
208
+ return JOIN-ENV(let-env(child), FWD-ENV(env));
209
+ ```
210
+
211
+ Let the subexpression `out_sndr` denote the result of the invocation
212
+ `let-cpo(sndr, f)` or an object equal to such, and let the subexpression
213
+ `rcvr` denote a receiver such that the expression
214
+ `connect(out_sndr, rcvr)` is well-formed. The expression
215
+ `connect(out_sndr, rcvr)` has undefined behavior unless it creates an
216
+ asynchronous operation [[exec.async.ops]] that, when started:
217
+
218
+ - invokes `f` when *`set-cpo`* is called with `sndr`’s result datums,
219
+ - makes its completion dependent on the completion of a sender returned
220
+ by `f`, and
221
+ - propagates the other completion operations sent by `sndr`.
222
+