From Jason Turner

[exec.consumers]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmpebwvjzeh/{from.md → to.md} +341 -0
tmp/tmpebwvjzeh/{from.md → to.md} RENAMED
@@ -0,0 +1,341 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ### Sender consumers <a id="exec.consumers">[[exec.consumers]]</a>
2
+
3
+ #### `this_thread::sync_wait` <a id="exec.sync.wait">[[exec.sync.wait]]</a>
4
+
5
+ `this_thread::sync_wait` and `this_thread::sync_wait_with_variant` are
6
+ used to block the current thread of execution until the specified sender
7
+ completes and to return its async result. `sync_wait` mandates that the
8
+ input sender has exactly one value completion signature.
9
+
10
+ Let *`sync-wait-env`* be the following exposition-only class type:
11
+
12
+ ``` cpp
13
+ namespace std::this_thread {
14
+ struct sync-wait-env {
15
+ execution::run_loop* loop; // exposition only
16
+
17
+ auto query(execution::get_scheduler_t) const noexcept {
18
+ return loop->get_scheduler();
19
+ }
20
+
21
+ auto query(execution::get_delegation_scheduler_t) const noexcept {
22
+ return loop->get_scheduler();
23
+ }
24
+ };
25
+ }
26
+ ```
27
+
28
+ Let *`sync-wait-result-type`* and *`sync-wait-with-variant-result-type`*
29
+ be exposition-only alias templates defined as follows:
30
+
31
+ ``` cpp
32
+ namespace std::this_thread {
33
+ template<execution::sender_in<sync-wait-env> Sndr>
34
+ using sync-wait-result-type =
35
+ optional<execution::value_types_of_t<Sndr, sync-wait-env, decayed-tuple,
36
+ type_identity_t>>;
37
+
38
+ template<execution::sender_in<sync-wait-env> Sndr>
39
+ using sync-wait-with-variant-result-type =
40
+ optional<execution::value_types_of_t<Sndr, sync-wait-env>>;
41
+ }
42
+ ```
43
+
44
+ The name `this_thread::sync_wait` denotes a customization point object.
45
+ For a subexpression `sndr`, let `Sndr` be `decltype((sndr))`. The
46
+ expression `this_thread::sync_wait(sndr)` is expression-equivalent to
47
+ the following, except that `sndr` is evaluated only once:
48
+
49
+ ``` cpp
50
+ apply_sender(get-domain-early(sndr), sync_wait, sndr)
51
+ ```
52
+
53
+ *Mandates:*
54
+
55
+ - `sender_in<Sndr, sync-wait-env>` is `true`.
56
+ - The type `sync-wait-result-type<Sndr>` is well-formed.
57
+ - `same_as<decltype(e), sync-wait-result-type<Sndr>>` is `true`, where e
58
+ is the `apply_sender` expression above.
59
+
60
+ Let *`sync-wait-state`* and *`sync-wait-receiver`* be the following
61
+ exposition-only class templates:
62
+
63
+ ``` cpp
64
+ namespace std::this_thread {
65
+ template<class Sndr>
66
+ struct sync-wait-state { // exposition only
67
+ execution::run_loop loop; // exposition only
68
+ exception_ptr error; // exposition only
69
+ sync-wait-result-type<Sndr> result; // exposition only
70
+ };
71
+
72
+ template<class Sndr>
73
+ struct sync-wait-receiver { // exposition only
74
+ using receiver_concept = execution::receiver_t;
75
+ sync-wait-state<Sndr>* state; // exposition only
76
+
77
+ template<class... Args>
78
+ void set_value(Args&&... args) && noexcept;
79
+
80
+ template<class Error>
81
+ void set_error(Error&& err) && noexcept;
82
+
83
+ void set_stopped() && noexcept;
84
+
85
+ sync-wait-env get_env() const noexcept { return {&state->loop}; }
86
+ };
87
+ }
88
+ ```
89
+
90
+ ``` cpp
91
+ template<class... Args>
92
+ void set_value(Args&&... args) && noexcept;
93
+ ```
94
+
95
+ *Effects:* Equivalent to:
96
+
97
+ ``` cpp
98
+ try {
99
+ state->result.emplace(std::forward<Args>(args)...);
100
+ } catch (...) {
101
+ state->error = current_exception();
102
+ }
103
+ state->loop.finish();
104
+ ```
105
+
106
+ ``` cpp
107
+ template<class Error>
108
+ void set_error(Error&& err) && noexcept;
109
+ ```
110
+
111
+ *Effects:* Equivalent to:
112
+
113
+ ``` cpp
114
+ state->error = AS-EXCEPT-PTR(std::forward<Error>(err)); // see [exec.general]
115
+ state->loop.finish();
116
+ ```
117
+
118
+ ``` cpp
119
+ void set_stopped() && noexcept;
120
+ ```
121
+
122
+ *Effects:* Equivalent to *`state`*`->`*`loop`*`.finish()`.
123
+
124
+ For a subexpression `sndr`, let `Sndr` be `decltype((sndr))`. If
125
+ `sender_to<Sndr, sync-wait-receiver<Sndr>>` is `false`, the expression
126
+ `sync_wait.apply_sender(sndr)` is ill-formed; otherwise, it is
127
+ equivalent to:
128
+
129
+ ``` cpp
130
+ sync-wait-state<Sndr> state;
131
+ auto op = connect(sndr, sync-wait-receiver<Sndr>{&state});
132
+ start(op);
133
+
134
+ state.loop.run();
135
+ if (state.error) {
136
+ rethrow_exception(std::move(state.error));
137
+ }
138
+ return std::move(state.result);
139
+ ```
140
+
141
+ The behavior of `this_thread::sync_wait(sndr)` is undefined unless:
142
+
143
+ - It blocks the current thread of execution [[defns.block]] with forward
144
+ progress guarantee delegation [[intro.progress]] until the specified
145
+ sender completes. \[*Note 1*: The default implementation of
146
+ `sync_wait` achieves forward progress guarantee delegation by
147
+ providing a `run_loop` scheduler via the `get_delegation_scheduler`
148
+ query on the *`sync-wait-receiver`*’s environment. The `run_loop` is
149
+ driven by the current thread of execution. — *end note*]
150
+ - It returns the specified sender’s async results as follows:
151
+ - For a value completion, the result datums are returned in a `tuple`
152
+ in an engaged `optional` object.
153
+ - For an error completion, an exception is thrown.
154
+ - For a stopped completion, a disengaged `optional` object is
155
+ returned.
156
+
157
+ #### `this_thread::sync_wait_with_variant` <a id="exec.sync.wait.var">[[exec.sync.wait.var]]</a>
158
+
159
+ The name `this_thread::sync_wait_with_variant` denotes a customization
160
+ point object. For a subexpression `sndr`, let `Sndr` be
161
+ `decltype(into_variant(sndr))`. The expression
162
+ `this_thread::sync_wait_with_variant(sndr)` is expression-equivalent to
163
+ the following, except `sndr` is evaluated only once:
164
+
165
+ ``` cpp
166
+ apply_sender(get-domain-early(sndr), sync_wait_with_variant, sndr)
167
+ ```
168
+
169
+ *Mandates:*
170
+
171
+ - `sender_in<Sndr, sync-wait-env>` is `true`.
172
+ - The type `sync-wait-with-variant-result-type<Sndr>` is well-formed.
173
+ - `same_as<decltype(e), sync-wait-with-variant-result-type<Sndr>>` is
174
+ `true`, where e is the `apply_sender` expression above.
175
+
176
+ The expression `sync_wait_with_variant.apply_sender(sndr)` is equivalent
177
+ to:
178
+
179
+ ``` cpp
180
+ using result_type = sync-wait-with-variant-result-type<Sndr>;
181
+ if (auto opt_value = sync_wait(into_variant(sndr))) {
182
+ return result_type(std::move(get<0>(*opt_value)));
183
+ }
184
+ return result_type(nullopt);
185
+ ```
186
+
187
+ The behavior of `this_thread::sync_wait_with_variant(sndr)` is undefined
188
+ unless:
189
+
190
+ - It blocks the current thread of execution [[defns.block]] with forward
191
+ progress guarantee delegation [[intro.progress]] until the specified
192
+ sender completes. \[*Note 1*: The default implementation of
193
+ `sync_wait_with_variant` achieves forward progress guarantee
194
+ delegation by relying on the forward progress guarantee delegation
195
+ provided by `sync_wait`. — *end note*]
196
+ - It returns the specified sender’s async results as follows:
197
+ - For a value completion, the result datums are returned in an engaged
198
+ `optional` object that contains a `variant` of `tuple`s.
199
+ - For an error completion, an exception is thrown.
200
+ - For a stopped completion, a disengaged `optional` object is
201
+ returned.
202
+
203
+ #### `execution::spawn` <a id="exec.spawn">[[exec.spawn]]</a>
204
+
205
+ `spawn` attempts to associate the given input sender with the given
206
+ token’s async scope and, on success, eagerly starts the input sender.
207
+
208
+ The name `spawn` denotes a customization point object. For
209
+ subexpressions `sndr`, `token`, and `env`,
210
+
211
+ - let `Sndr` be `decltype((sndr))`,
212
+ - let `Token` be `remove_cvref_t<decltype((token))>`, and
213
+ - let `Env` be `remove_cvref_t<decltype((env))>`.
214
+
215
+ If any of `sender<Sndr>`, `scope_token<Token>`, or `queryable<Env>` are
216
+ not satisfied, the expression `spawn({}sndr, token, env)` is ill-formed.
217
+
218
+ Let *`spawn-state-base`* be the exposition-only class:
219
+
220
+ ``` cpp
221
+ namespace std::execution {
222
+ struct spawn-state-base { // exposition only
223
+ virtual void complete() noexcept = 0; // exposition only
224
+ };
225
+ }
226
+ ```
227
+
228
+ Let *`spawn-receiver`* be the exposition-only class:
229
+
230
+ ``` cpp
231
+ namespace std::execution {
232
+ struct spawn-receiver { // exposition only
233
+ using receiver_concept = receiver_t;
234
+
235
+ spawn-state-base* state; // exposition only
236
+ void set_value() && noexcept { state->complete(); }
237
+ void set_stopped() && noexcept { state->complete(); }
238
+ };
239
+ }
240
+ ```
241
+
242
+ Let *`spawn-state`* be the exposition-only class template:
243
+
244
+ ``` cpp
245
+ namespace std::execution {
246
+ template<class Alloc, scope_token Token, sender Sender>
247
+ struct spawn-state : spawn-state-base { // exposition only
248
+ using op-t = connect_result_t<Sender, spawn-receiver>; // exposition only
249
+
250
+ spawn-state(Alloc alloc, Sender&& sndr, Token token); // exposition only
251
+ void complete() noexcept override; // exposition only
252
+ void run(); // exposition only
253
+
254
+ private:
255
+ using alloc-t = // exposition only
256
+ allocator_traits<Alloc>::template rebind_alloc<spawn-state>;
257
+
258
+ alloc-t alloc; // exposition only
259
+ op-t op; // exposition only
260
+ Token token; // exposition only
261
+
262
+ void destroy() noexcept; // exposition only
263
+ };
264
+ }
265
+ ```
266
+
267
+ ``` cpp
268
+ spawn-state(Alloc alloc, Sender&& sndr, Token token);
269
+ ```
270
+
271
+ *Effects:* Initializes *alloc* with `alloc`, *token* with `token`, and
272
+ *op* with:
273
+
274
+ ``` cpp
275
+ connect(std::move(sndr), spawn-receiver(this))
276
+ ```
277
+
278
+ ``` cpp
279
+ void run();
280
+ ```
281
+
282
+ *Effects:* Equivalent to:
283
+
284
+ ``` cpp
285
+ if (token.try_associate())
286
+ start(op);
287
+ else
288
+ destroy();
289
+ ```
290
+
291
+ ``` cpp
292
+ void complete() noexcept override;
293
+ ```
294
+
295
+ *Effects:* Equivalent to:
296
+
297
+ ``` cpp
298
+ auto token = std::move(this->token);
299
+
300
+ destroy();
301
+ token.disassociate();
302
+ ```
303
+
304
+ ``` cpp
305
+ void destroy() noexcept;
306
+ ```
307
+
308
+ *Effects:* Equivalent to:
309
+
310
+ ``` cpp
311
+ auto alloc = std::move(this->alloc);
312
+
313
+ allocator_traits<alloc-t>::destroy(alloc, this);
314
+ allocator_traits<alloc-t>::deallocate(alloc, this, 1);
315
+ ```
316
+
317
+ For the expression `spawn(sndr, token, env)` let `new_sender` be the
318
+ expression `token.wrap(sndr)` and let `alloc` and `senv` be defined as
319
+ follows:
320
+
321
+ - if the expression `get_allocator(env)` is well-formed, then `alloc` is
322
+ the result of `get_allocator(env)` and `senv` is the expression `env`,
323
+ - otherwise if the expression `get_allocator(get_env(new_sender))` is
324
+ well-formed, then `alloc` is the result of
325
+ `get_allocator(get_env(new_sender))` and `senv` is the expression
326
+ `JOIN-ENV(prop(get_allocator, alloc), env)`,
327
+ - otherwise `alloc` is `allocator<void>()` and `senv` is the expression
328
+ `env`.
329
+
330
+ The expression `spawn(sndr, token, env)` is of type `void` and has the
331
+ following effects:
332
+
333
+ - Uses `alloc` to allocate and construct an object `o` of type that is a
334
+ specialization of `spawn-state` from `alloc`,
335
+ `write_env(token.wrap(sndr), senv)`, and `token` and then invokes
336
+ `o.run()`. If an exception is thrown then any constructed objects are
337
+ destroyed and any allocated memory is deallocated.
338
+
339
+ The expression `spawn(sndr, token)` is expression-equivalent to
340
+ `spawn(sndr, token, execution::env<>({}))`.
341
+