From Jason Turner

[exec.coro.util]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmpc_i3ha9p/{from.md → to.md} +885 -0
tmp/tmpc_i3ha9p/{from.md → to.md} RENAMED
@@ -0,0 +1,885 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## Coroutine utilities <a id="exec.coro.util">[[exec.coro.util]]</a>
2
+
3
+ ### `execution::as_awaitable` <a id="exec.as.awaitable">[[exec.as.awaitable]]</a>
4
+
5
+ `as_awaitable` transforms an object into one that is awaitable within a
6
+ particular coroutine. Subclause [[exec.coro.util]] makes use of the
7
+ following exposition-only entities:
8
+
9
+ ``` cpp
10
+ namespace std::execution {
11
+ template<class Sndr, class Promise>
12
+ concept awaitable-sender =
13
+ single-sender<Sndr, env_of_t<Promise>> &&
14
+ sender_to<Sndr, awaitable-receiver> && // see below
15
+ requires (Promise& p) {
16
+ { p.unhandled_stopped() } -> convertible_to<coroutine_handle<>>;
17
+ };
18
+
19
+ template<class Sndr>
20
+ concept has-queryable-await-completion-adaptor = // exposition only
21
+ sender<Sndr> &&
22
+ requires(Sndr&& sender) {
23
+ get_await_completion_adaptor(get_env(sender));
24
+ };
25
+
26
+ template<class Sndr, class Promise>
27
+ class sender-awaitable; // exposition only
28
+ }
29
+ ```
30
+
31
+ The type `sender-awaitable<Sndr, Promise>` is equivalent to:
32
+
33
+ ``` cpp
34
+ namespace std::execution {
35
+ template<class Sndr, class Promise>
36
+ class sender-awaitable {
37
+ struct unit {}; // exposition only
38
+ using value-type = // exposition only
39
+ single-sender-value-type<Sndr, env_of_t<Promise>>;
40
+ using result-type = // exposition only
41
+ conditional_t<is_void_v<value-type>, unit, value-type>;
42
+ struct awaitable-receiver; // exposition only
43
+
44
+ variant<monostate, result-type, exception_ptr> result{}; // exposition only
45
+ connect_result_t<Sndr, awaitable-receiver> state; // exposition only
46
+
47
+ public:
48
+ sender-awaitable(Sndr&& sndr, Promise& p);
49
+ static constexpr bool await_ready() noexcept { return false; }
50
+ void await_suspend(coroutine_handle<Promise>) noexcept { start(state); }
51
+ value-type await_resume();
52
+ };
53
+ }
54
+ ```
55
+
56
+ *`awaitable-receiver`* is equivalent to:
57
+
58
+ ``` cpp
59
+ struct awaitable-receiver {
60
+ using receiver_concept = receiver_t;
61
+ variant<monostate, result-type, exception_ptr>* result-ptr; // exposition only
62
+ coroutine_handle<Promise> continuation; // exposition only
63
+ // see below
64
+ };
65
+ ```
66
+
67
+ Let `rcvr` be an rvalue expression of type *`awaitable-receiver`*, let
68
+ `crcvr` be a const lvalue that refers to `rcvr`, let `vs` be a pack of
69
+ subexpressions, and let `err` be an expression of type `Err`. Then:
70
+
71
+ - If `constructible_from<result-type, decltype((vs))...>` is satisfied,
72
+ the expression `set_value( rcvr, vs...)` is equivalent to:
73
+ ``` cpp
74
+ try {
75
+ rcvr.result-ptr->template emplace<1>(vs...);
76
+ } catch(...) {
77
+ rcvr.result-ptr->template emplace<2>(current_exception());
78
+ }
79
+ rcvr.continuation.resume();
80
+ ```
81
+
82
+ Otherwise, `set_value(rcvr, vs...)` is ill-formed.
83
+ - The expression `set_error(rcvr, err)` is equivalent to:
84
+ ``` cpp
85
+ rcvr.result-ptr->template emplace<2>(AS-EXCEPT-PTR(err)); // see [exec.general]
86
+ rcvr.continuation.resume();
87
+ ```
88
+ - The expression `set_stopped(rcvr)` is equivalent to:
89
+ ``` cpp
90
+ static_cast<coroutine_handle<>>(rcvr.continuation.promise().unhandled_stopped()).resume();
91
+ ```
92
+ - For any expression `tag` whose type satisfies `forwarding-query` and
93
+ for any pack of subexpressions `as`,
94
+ `get_env(crcvr).query(tag, as...)` is expression-equivalent to:
95
+ ``` cpp
96
+ tag(get_env(as_const(crcvr.continuation.promise())), as...)
97
+ ```
98
+
99
+ ``` cpp
100
+ sender-awaitable(Sndr&& sndr, Promise& p);
101
+ ```
102
+
103
+ *Effects:* Initializes *state* with
104
+
105
+ ``` cpp
106
+ connect(std::forward<Sndr>(sndr),
107
+ awaitable-receiver{addressof(result), coroutine_handle<Promise>::from_promise(p)})
108
+ ```
109
+
110
+ ``` cpp
111
+ value-type await_resume();
112
+ ```
113
+
114
+ *Effects:* Equivalent to:
115
+
116
+ ``` cpp
117
+ if (result.index() == 2)
118
+ rethrow_exception(get<2>(result));
119
+ if constexpr (!is_void_v<value-type>)
120
+ return std::forward<value-type>(get<1>(result));
121
+ ```
122
+
123
+ `as_awaitable` is a customization point object. For subexpressions
124
+ `expr` and `p` where `p` is an lvalue, `Expr` names the type
125
+ `decltype((expr))` and `Promise` names the type
126
+ `decay_t<decltype((p))>`, `as_awaitable(expr, p)` is
127
+ expression-equivalent to, except that the evaluations of `expr` and `p`
128
+ are indeterminately sequenced:
129
+
130
+ - `expr.as_awaitable(p)` if that expression is well-formed. *Mandates:*
131
+ `is-awaitable<A, Promise>` is `true`, where `A` is the type of the
132
+ expression above.
133
+ - Otherwise, `(void(p), expr)` if `is-awaitable<Expr, U>` is `true`,
134
+ where `U` is an unspecified class type that is not `Promise` and that
135
+ lacks a member named `await_transform`. *Preconditions:*
136
+ `is-awaitable<Expr, Promise>` is `true` and the expression
137
+ `co_await expr` in a coroutine with promise type `U` is
138
+ expression-equivalent to the same expression in a coroutine with
139
+ promise type `Promise`.
140
+ - Otherwise, `sender-awaitable{adapted-expr, p}` if
141
+ ``` cpp
142
+ has-queryable-await-completion-adaptor<Expr>
143
+ ```
144
+
145
+ and
146
+ ``` cpp
147
+ awaitable-sender<decltype((adapted-expr)), Promise>
148
+ ```
149
+
150
+ are both satisfied, where *`adapted-expr`* is
151
+ `get_await_completion_adaptor(get_env(expr))(expr)`, except that
152
+ `expr` is evaluated only once.
153
+ - Otherwise, `sender-awaitable{expr, p}` if
154
+ `awaitable-sender<Expr, Promise>` is `true`.
155
+ - Otherwise, `(void(p), expr)`.
156
+
157
+ ### `execution::with_awaitable_senders` <a id="exec.with.awaitable.senders">[[exec.with.awaitable.senders]]</a>
158
+
159
+ `with_awaitable_senders`, when used as the base class of a coroutine
160
+ promise type, makes senders awaitable in that coroutine type.
161
+
162
+ In addition, it provides a default implementation of `unhandled_stopped`
163
+ such that if a sender completes by calling `set_stopped`, it is treated
164
+ as if an uncatchable "stopped" exception were thrown from the
165
+ *await-expression*.
166
+
167
+ [*Note 1*: The coroutine is never resumed, and the `unhandled_stopped`
168
+ of the coroutine caller’s promise type is called. — *end note*]
169
+
170
+ ``` cpp
171
+ namespace std::execution {
172
+ template<class-type Promise>
173
+ struct with_awaitable_senders {
174
+ template<class OtherPromise>
175
+ requires (!same_as<OtherPromise, void>)
176
+ void set_continuation(coroutine_handle<OtherPromise> h) noexcept;
177
+
178
+ coroutine_handle<> continuation() const noexcept { return continuation; }
179
+
180
+ coroutine_handle<> unhandled_stopped() noexcept {
181
+ return stopped-handler(continuation.address());
182
+ }
183
+
184
+ template<class Value>
185
+ see below await_transform(Value&& value);
186
+
187
+ private:
188
+ [[noreturn]] static coroutine_handle<>
189
+ default-unhandled-stopped(void*) noexcept { // exposition only
190
+ terminate();
191
+ }
192
+ coroutine_handle<> continuation{}; // exposition only
193
+ coroutine_handle<> (*stopped-handler)(void*) noexcept = // exposition only
194
+ &default-unhandled-stopped;
195
+ };
196
+ }
197
+ ```
198
+
199
+ ``` cpp
200
+ template<class OtherPromise>
201
+ requires (!same_as<OtherPromise, void>)
202
+ void set_continuation(coroutine_handle<OtherPromise> h) noexcept;
203
+ ```
204
+
205
+ *Effects:* Equivalent to:
206
+
207
+ ``` cpp
208
+ continuation = h;
209
+ if constexpr ( requires(OtherPromise& other) { other.unhandled_stopped(); } ) {
210
+ stopped-handler = [](void* p) noexcept -> coroutine_handle<> {
211
+ return coroutine_handle<OtherPromise>::from_address(p)
212
+ .promise().unhandled_stopped();
213
+ };
214
+ } else {
215
+ stopped-handler = &default-unhandled-stopped;
216
+ }
217
+ ```
218
+
219
+ ``` cpp
220
+ template<class Value>
221
+ call-result-t<as_awaitable_t, Value, Promise&> await_transform(Value&& value);
222
+ ```
223
+
224
+ *Effects:* Equivalent to:
225
+
226
+ ``` cpp
227
+ return as_awaitable(std::forward<Value>(value), static_cast<Promise&>(*this));
228
+ ```
229
+
230
+ ### `execution::affine_on` <a id="exec.affine.on">[[exec.affine.on]]</a>
231
+
232
+ `affine_on` adapts a sender into one that completes on the specified
233
+ scheduler. If the algorithm determines that the adapted sender already
234
+ completes on the correct scheduler it can avoid any scheduling
235
+ operation.
236
+
237
+ The name `affine_on` denotes a pipeable sender adaptor object. For
238
+ subexpressions `sch` and `sndr`, if `decltype((sch))` does not satisfy
239
+ `scheduler`, or `decltype((sndr))` does not satisfy `sender`,
240
+ `affine_on(sndr, sch)` is ill-formed.
241
+
242
+ Otherwise, the expression `affine_on(sndr, sch)` is
243
+ expression-equivalent to:
244
+
245
+ ``` cpp
246
+ transform_sender(get-domain-early(sndr), make-sender(affine_on, sch, sndr))
247
+ ```
248
+
249
+ except that `sndr` is evaluated only once.
250
+
251
+ The exposition-only class template *`impls-for`* [[exec.snd.expos]] is
252
+ specialized for `affine_on_t` as follows:
253
+
254
+ ``` cpp
255
+ namespace std::execution {
256
+ template<>
257
+ struct impls-for<affine_on_t> : default-impls {
258
+ static constexpr auto get-attrs =
259
+ [](const auto& data, const auto& child) noexcept -> decltype(auto) {
260
+ return JOIN-ENV(SCHED-ATTRS(data), FWD-ENV(get_env(child)));
261
+ };
262
+ };
263
+ }
264
+ ```
265
+
266
+ Let `out_sndr` be a subexpression denoting a sender returned from
267
+ `affine_on(sndr, sch)` or one equal to such, and let `OutSndr` be the
268
+ type `decltype((out_sndr))`. Let `out_rcvr` be a subexpression denoting
269
+ a receiver that has an environment of type `Env` such that
270
+ `sender_in<OutSndr, Env>` is `true`. Let `op` be an lvalue referring to
271
+ the operation state that results from connecting `out_sndr` to
272
+ `out_rcvr`. Calling `start(op)` will start `sndr` on the current
273
+ execution agent and execute completion operations on `out_rcvr` on an
274
+ execution agent of the execution resource associated with `sch`. If the
275
+ current execution resource is the same as the execution resource
276
+ associated with `sch`, the completion operation on `out_rcvr` may be
277
+ called before `start(op)` completes. If scheduling onto `sch` fails, an
278
+ error completion on `out_rcvr` shall be executed on an unspecified
279
+ execution agent.
280
+
281
+ ### `execution::inline_scheduler` <a id="exec.inline.scheduler">[[exec.inline.scheduler]]</a>
282
+
283
+ ``` cpp
284
+ namespace std::execution {
285
+ class inline_scheduler {
286
+ class inline-sender; // exposition only
287
+
288
+ template<receiver R>
289
+ class inline-state; // exposition only
290
+
291
+ public:
292
+ using scheduler_concept = scheduler_t;
293
+
294
+ constexpr inline-sender schedule() noexcept { return {}; }
295
+ constexpr bool operator==(const inline_scheduler&) const noexcept = default;
296
+ };
297
+ }
298
+ ```
299
+
300
+ `inline_scheduler` is a class that models `scheduler` [[exec.sched]].
301
+ All objects of type `inline_scheduler` are equal.
302
+
303
+ *`inline-sender`* is an exposition-only type that satisfies `sender`.
304
+ The type `completion_signatures_of_t<inline-sender>` is
305
+ `completion_signatures<set_value_t()>`.
306
+
307
+ Let `sndr` be an expression of type *`inline-sender`*, let `rcvr` be an
308
+ expression such that `receiver_of<decltype((rcvr)), CS>` is `true` where
309
+ `CS` is `completion_signatures<set_value_t()>`, then:
310
+
311
+ - the expression `connect(sndr, rcvr)` has type
312
+ `inline-state<remove_cvref_t<decltype((rcvr))>>` and is
313
+ potentially-throwing if and only if `((void)sndr, auto(rcvr))` is
314
+ potentially-throwing, and
315
+ - the expression `get_completion_scheduler<set_value_t>(get_env(sndr))`
316
+ has type `inline_scheduler` and is potentially-throwing if and only if
317
+ `get_env(sndr)` is potentially-throwing.
318
+
319
+ Let `o` be a non-`const` lvalue of type `inline-state<Rcvr>`, and let
320
+ `REC(o)` be a non-`const` lvalue reference to an object of type `Rcvr`
321
+ that was initialized with the expression `rcvr` passed to an invocation
322
+ of `connect` that returned `o`, then:
323
+
324
+ - the object to which `REC(o)` refers remains valid for the lifetime of
325
+ the object to which `o` refers, and
326
+ - the expression `start(o)` is equivalent to
327
+ `set_value(std::move(REC(o)))`.
328
+
329
+ ### `execution::task_scheduler` <a id="exec.task.scheduler">[[exec.task.scheduler]]</a>
330
+
331
+ ``` cpp
332
+ namespace std::execution {
333
+ class task_scheduler {
334
+ class ts-sender; // exposition only
335
+
336
+ template<receiver R>
337
+ class state; // exposition only
338
+
339
+ public:
340
+ using scheduler_concept = scheduler_t;
341
+
342
+ template<class Sch, class Allocator = allocator<void>>
343
+ requires (!same_as<task_scheduler, remove_cvref_t<Sch>>)
344
+ && scheduler<Sch>
345
+ explicit task_scheduler(Sch&& sch, Allocator alloc = {});
346
+
347
+ ts-sender schedule();
348
+
349
+ friend bool operator==(const task_scheduler& lhs, const task_scheduler& rhs)
350
+ noexcept;
351
+ template<class Sch>
352
+ requires (!same_as<task_scheduler, Sch>)
353
+ && scheduler<Sch>
354
+ friend bool operator==(const task_scheduler& lhs, const Sch& rhs) noexcept;
355
+
356
+ private:
357
+ shared_ptr<void> sch_; // exposition only
358
+ };
359
+ }
360
+ ```
361
+
362
+ `task_scheduler` is a class that models `scheduler` [[exec.sched]].
363
+ Given an object `s` of type `task_scheduler`, let `SCHED(s)` be the
364
+ object owned by `s.sch_`.
365
+
366
+ ``` cpp
367
+ template<class Sch, class Allocator = allocator<void>>
368
+ requires(!same_as<task_scheduler, remove_cvref_t<Sch>>) && scheduler<Sch>
369
+ explicit task_scheduler(Sch&& sch, Allocator alloc = {});
370
+ ```
371
+
372
+ *Effects:* Initialize *sch\_* with
373
+ `allocate_shared<remove_cvref_t<Sch>>(alloc, std::forward<Sch>(sch))`.
374
+
375
+ *Recommended practice:* Implementations should avoid the use of
376
+ dynamically allocated memory for small scheduler objects.
377
+
378
+ *Remarks:* Any allocations performed by construction of *ts-sender* or
379
+ *state* objects resulting from calls on `*this` are performed using a
380
+ copy of `alloc`.
381
+
382
+ ``` cpp
383
+ ts-sender schedule();
384
+ ```
385
+
386
+ *Effects:* Returns an object of type *ts-sender* containing a sender
387
+ initialized with `schedule(`*`SCHED`*`(*this))`.
388
+
389
+ ``` cpp
390
+ bool operator==(const task_scheduler& lhs, const task_scheduler& rhs) noexcept;
391
+ ```
392
+
393
+ *Effects:* Equivalent to: `return lhs == `*`SCHED`*`(rhs);`
394
+
395
+ ``` cpp
396
+ template<class Sch>
397
+ requires (!same_as<task_scheduler, Sch>)
398
+ && scheduler<Sch>
399
+ bool operator==(const task_scheduler& lhs, const Sch& rhs) noexcept;
400
+ ```
401
+
402
+ *Returns:* `false` if the type of *`SCHED`*`(lhs)` is not `Sch`,
403
+ otherwise *`SCHED`*`(lhs) == rhs`.
404
+
405
+ ``` cpp
406
+ namespace std::execution {
407
+ class task_scheduler::ts-sender { // exposition only
408
+ public:
409
+ using sender_concept = sender_t;
410
+
411
+ template<receiver Rcvr>
412
+ state<Rcvr> connect(Rcvr&& rcvr);
413
+ };
414
+ }
415
+ ```
416
+
417
+ *`ts-sender`* is an exposition-only class that models `sender`
418
+ [[exec.snd]] and for which `completion_signatures_of_t<ts-sender>`
419
+ denotes:
420
+
421
+ ``` cpp
422
+ completion_signatures<
423
+ set_value_t(),
424
+ set_error_t(error_code),
425
+ set_error_t(exception_ptr),
426
+ set_stopped_t()>
427
+ ```
428
+
429
+ Let `sch` be an object of type `task_scheduler` and let `sndr` be an
430
+ object of type *`ts-sender`* obtained from `schedule(sch)`. Then
431
+ `get_completion_scheduler<set_value_t>(get_env(sndr)) == sch` is `true`.
432
+ The object `SENDER(sndr)` is the sender object contained by `sndr` or an
433
+ object move constructed from it.
434
+
435
+ ``` cpp
436
+ template<receiver Rcvr>
437
+ state<Rcvr> connect(Rcvr&& rcvr);
438
+ ```
439
+
440
+ *Effects:* Let *`r`* be an object of a type that models `receiver` and
441
+ whose completion handlers result in invoking the corresponding
442
+ completion handlers of `rcvr` or copy thereof. Returns an object of type
443
+ *`state`*`<Rcvr>` containing an operation state object initialized with
444
+ `connect(`*`SENDER`*`(*this), std::move(`*`r`*`))`.
445
+
446
+ ``` cpp
447
+ namespace std::execution {
448
+ template<receiver R>
449
+ class task_scheduler::state { // exposition only
450
+ public:
451
+ using operation_state_concept = operation_state_t;
452
+
453
+ void start() & noexcept;
454
+ };
455
+ }
456
+ ```
457
+
458
+ *`state`* is an exposition-only class template whose specializations
459
+ model `operation_state` [[exec.opstate]].
460
+
461
+ ``` cpp
462
+ void start() & noexcept;
463
+ ```
464
+
465
+ *Effects:* Equivalent to `start(st)` where `st` is the operation state
466
+ object contained by `*this`.
467
+
468
+ ### `execution::task` <a id="exec.task">[[exec.task]]</a>
469
+
470
+ #### `task` overview <a id="task.overview">[[task.overview]]</a>
471
+
472
+ The `task` class template represents a sender that can be used as the
473
+ return type of coroutines. The first template parameter `T` defines the
474
+ type of the value completion datum [[exec.async.ops]] if `T` is not
475
+ `void`. Otherwise, there are no value completion datums. Inside
476
+ coroutines returning `task<T, E>` the operand of `co_return` (if any)
477
+ becomes the argument of `set_value`. The second template parameter
478
+ `Environment` is used to customize the behavior of `task`.
479
+
480
+ #### Class template `task` <a id="task.class">[[task.class]]</a>
481
+
482
+ ``` cpp
483
+ namespace std::execution {
484
+ template<class T, class Environment>
485
+ class task {
486
+ // [task.state]
487
+ template<receiver Rcvr>
488
+ class state; // exposition only
489
+
490
+ public:
491
+ using sender_concept = sender_t;
492
+ using completion_signatures = see below;
493
+ using allocator_type = see below;
494
+ using scheduler_type = see below;
495
+ using stop_source_type = see below;
496
+ using stop_token_type = decltype(declval<stop_source_type>().get_token());
497
+ using error_types = see below;
498
+
499
+ // [task.promise]
500
+ class promise_type;
501
+
502
+ task(task&&) noexcept;
503
+ ~task();
504
+
505
+ template<receiver Rcvr>
506
+ state<Rcvr> connect(Rcvr&& rcvr);
507
+
508
+ private:
509
+ coroutine_handle<promise_type> handle; // exposition only
510
+ };
511
+ }
512
+ ```
513
+
514
+ `task<T, E>` models `sender` [[exec.snd]] if `T` is `void`, a reference
515
+ type, or a cv-unqualified non-array object type and `E` is a class type.
516
+ Otherwise a program that instantiates the definition of `task<T, E>` is
517
+ ill-formed.
518
+
519
+ The nested types of `task` template specializations are determined based
520
+ on the `Environment` parameter:
521
+
522
+ - `allocator_type` is `Environment::allocator_type` if that
523
+ *qualified-id* is valid and denotes a type, `allocator<byte>`
524
+ otherwise.
525
+ - `scheduler_type` is `Environment::scheduler_type` if that
526
+ *qualified-id* is valid and denotes a type, `task_scheduler`
527
+ otherwise.
528
+ - `stop_source_type` is `Environment::stop_source_type` if that
529
+ *qualified-id* is valid and denotes a type, `inplace_stop_source`
530
+ otherwise.
531
+ - `error_types` is `Environment::error_types` if that *qualified-id* is
532
+ valid and denotes a type,
533
+ `completion_signatures<set_error_t(exception_ptr)>` otherwise.
534
+
535
+ A program is ill-formed if `error_types` is not a specialization of
536
+ `execution::completion_signatures` or if the template arguments of that
537
+ specialization contain an element which is not of the form
538
+ `set_error_t(E)` for some type `E`.
539
+
540
+ The type alias `completion_signatures` is a specialization of
541
+ `execution::completion_signatures` with the template arguments (in
542
+ unspecified order):
543
+
544
+ - `set_value_t()` if `T` is `void`, and `set_value_t(T)` otherwise;
545
+ - template arguments of the specialization of
546
+ `execution::completion_signatures` denoted by `error_types`; and
547
+ - `set_stopped_t()`.
548
+
549
+ `allocator_type` shall meet the *Cpp17Allocator* requirements.
550
+
551
+ #### `task` members <a id="task.members">[[task.members]]</a>
552
+
553
+ ``` cpp
554
+ task(task&& other) noexcept;
555
+ ```
556
+
557
+ *Effects:* Initializes *handle* with `exchange(other.`*`handle`*`, {})`.
558
+
559
+ ``` cpp
560
+ ~task();
561
+ ```
562
+
563
+ *Effects:* Equivalent to:
564
+
565
+ ``` cpp
566
+ if (handle)
567
+ handle.destroy();
568
+ ```
569
+
570
+ ``` cpp
571
+ template<receiver Rcvr>
572
+ state<Rcvr> connect(Rcvr&& recv);
573
+ ```
574
+
575
+ *Preconditions:* `bool(`*`handle`*`)` is `true`.
576
+
577
+ *Effects:* Equivalent to:
578
+
579
+ ``` cpp
580
+ return state<Rcvr>(exchange(handle, {}), std::forward<Rcvr>(recv));
581
+ ```
582
+
583
+ #### Class template `task::state` <a id="task.state">[[task.state]]</a>
584
+
585
+ ``` cpp
586
+ namespace std::execution {
587
+ template<class T, class Environment>
588
+ template<receiver Rcvr>
589
+ class task<T, Environment>::state { // exposition only
590
+ public:
591
+ using operation_state_concept = operation_state_t;
592
+
593
+ template<class R>
594
+ state(coroutine_handle<promise_type> h, R&& rr);
595
+
596
+ ~state();
597
+
598
+ void start() & noexcept;
599
+
600
+ private:
601
+ using own-env-t = see belownc; // exposition only
602
+ coroutine_handle<promise_type> handle; // exposition only
603
+ remove_cvref_t<Rcvr> rcvr; // exposition only
604
+ own-env-t own-env; // exposition only
605
+ Environment environment; // exposition only
606
+ };
607
+ }
608
+ ```
609
+
610
+ The type *`own-env-t`* is `Environment::template
611
+ env_type<decltype(get_env({}declval{}<Rcvr>({}))){}>` if that
612
+ *qualified-id* is valid and denotes a type, `env<>` otherwise.
613
+
614
+ ``` cpp
615
+ template<class R>
616
+ state(coroutine_handle<promise_type> h, R&& rr);
617
+ ```
618
+
619
+ *Effects:* Initializes
620
+
621
+ - *handle* with `std::move(h)`;
622
+ - *rcvr* with `std::forward<R>(rr)`;
623
+ - *own-env* with *`own-env-t`*`(get_env(`*`rcvr`*`))` if that expression
624
+ is valid and *`own-env-t`*`()` otherwise. If neither of these
625
+ expressions is valid, the program is ill-formed.
626
+ - *environment* with `Environment(`*`own-env`*`)` if that expression is
627
+ valid, otherwise `Environment(get_env(`*`rcvr`*`))` if this expression
628
+ is valid, otherwise `Environment()`. If neither of these expressions
629
+ is valid, the program is ill-formed.
630
+
631
+ ``` cpp
632
+ ~state();
633
+ ```
634
+
635
+ *Effects:* Equivalent to:
636
+
637
+ ``` cpp
638
+ if (handle)
639
+ handle.destroy();
640
+ ```
641
+
642
+ ``` cpp
643
+ void start() & noexcept;
644
+ ```
645
+
646
+ *Effects:* Let *`prom`* be the object *`handle`*`.promise()`. Associates
647
+ *`STATE`*`(`*`prom`*`)`, *`RCVR`*`(`*`prom`*`)`, and
648
+ *`SCHED`*`(`*`prom`*`)` with `*this` as follows:
649
+
650
+ - *`STATE`*`(`*`prom`*`)` is `*this`.
651
+ - *`RCVR`*`(`*`prom`*`)` is *rcvr*.
652
+ - *`SCHED`*`(`*`prom`*`)` is the object initialized with
653
+ `scheduler_type(get_scheduler(get_env(`*`rcvr`*`)))` if that
654
+ expression is valid and `scheduler_type()` otherwise. If neither of
655
+ these expressions is valid, the program is ill-formed.
656
+
657
+ Let *`st`* be `get_stop_token(get_env(`*`rcvr`*`))`. Initializes
658
+ *`prom`*`.`*`token`* and *`prom`*`.`*`source`* such that
659
+
660
+ - *`prom`*`.`*`token`*`.stop_requested()` returns
661
+ *`st`*`.stop_requested()`;
662
+ - *`prom`*`.`*`token`*`.stop_possible()` returns
663
+ *`st`*`.stop_possible()`; and
664
+ - for types `Fn` and `Init` such that both `invocable<Fn>` and
665
+ `constructible_from<Fn, Init>` are modeled,
666
+ `stop_token_type::callback_type<Fn>` models
667
+ `stoppable-callback-for<Fn, stop_token_type, Init>`.
668
+
669
+ After that invokes *`handle`*`.resume()`.
670
+
671
+ #### Class `task::promise_type` <a id="task.promise">[[task.promise]]</a>
672
+
673
+ ``` cpp
674
+ namespace std::execution {
675
+ template<class T, class Environment>
676
+ class task<T, Environment>::promise_type {
677
+ public:
678
+ template<class... Args>
679
+ promise_type(const Args&... args);
680
+
681
+ task get_return_object() noexcept;
682
+
683
+ auto initial_suspend() noexcept;
684
+ auto final_suspend() noexcept;
685
+
686
+ void uncaught_exception();
687
+ coroutine_handle<> unhandled_stopped();
688
+
689
+ void return_void(); // present only if is_void_v<T> is true
690
+ template<class V>
691
+ void return_value(V&& value); // present only if is_void_v<T> is false
692
+
693
+ template<class E>
694
+ unspecified yield_value(with_error<E> error);
695
+
696
+ template<class A>
697
+ auto await_transform(A&& a);
698
+ template<class Sch>
699
+ auto await_transform(change_coroutine_scheduler<Sch> sch);
700
+
701
+ unspecified get_env() const noexcept;
702
+
703
+ template<class... Args>
704
+ void* operator new(size_t size, Args&&... args);
705
+
706
+ void operator delete(void* pointer, size_t size) noexcept;
707
+
708
+ private:
709
+ using error-variant = see belownc; // exposition only
710
+
711
+ allocator_type alloc; // exposition only
712
+ stop_source_type source; // exposition only
713
+ stop_token_type token; // exposition only
714
+ optional<T> result; // exposition only; present only if is_void_v<T> is false
715
+ error-variant errors; // exposition only
716
+ };
717
+ }
718
+ ```
719
+
720
+ Let `prom` be an object of `promise_type` and let `tsk` be the `task`
721
+ object created by `prom.get_return_object()`. The description below
722
+ refers to objects `STATE(prom)`, `RCVR(prom)`, and `SCHED(prom)`
723
+ associated with `tsk` during evaluation of `task::state<Rcvr>::start`
724
+ for some receiver `Rcvr`.
725
+
726
+ *`error-variant`* is a `variant<monostate,
727
+ remove_cvref_t<E>...>`, with duplicate types removed, where `E...` are
728
+ the parameter types of the template arguments of the specialization of
729
+ `execution::completion_signatures` denoted by `error_types`.
730
+
731
+ ``` cpp
732
+ template<class... Args>
733
+ promise_type(const Args&... args);
734
+ ```
735
+
736
+ *Mandates:* The first parameter of type `allocator_arg_t` (if any) is
737
+ not the last parameter.
738
+
739
+ *Effects:* If `Args` contains an element of type `allocator_arg_t` then
740
+ *alloc* is initialized with the corresponding next element of `args`.
741
+ Otherwise, *alloc* is initialized with `allocator_type()`.
742
+
743
+ ``` cpp
744
+ task get_return_object() noexcept;
745
+ ```
746
+
747
+ *Returns:* A `task` object whose member *handle* is
748
+ `coroutine_handle<promise_type>::from_promise(*this)`.
749
+
750
+ ``` cpp
751
+ auto initial_suspend() noexcept;
752
+ ```
753
+
754
+ *Returns:* An awaitable object of unspecified type [[expr.await]] whose
755
+ member functions arrange for
756
+
757
+ - the calling coroutine to be suspended,
758
+ - the coroutine to be resumed on an execution agent of the execution
759
+ resource associated with *`SCHED`*`(*this)`.
760
+
761
+ ``` cpp
762
+ auto final_suspend() noexcept;
763
+ ```
764
+
765
+ *Returns:* An awaitable object of unspecified type [[expr.await]] whose
766
+ member functions arrange for the completion of the asynchronous
767
+ operation associated with *`STATE`*`(*this)` by invoking:
768
+
769
+ - `set_error(std::move(`*`RCVR`*`(*this)), std::move(e))` if
770
+ *`errors`*`.index()` is greater than zero and `e` is the value held by
771
+ *errors*, otherwise
772
+ - `set_value(std::move(`*`RCVR`*`(*this)))` if `is_void<T>` is `true`,
773
+ and otherwise
774
+ - `set_value(std::move(`*`RCVR`*`(*this)), *`*`result`*`)`.
775
+
776
+ ``` cpp
777
+ template<class Err>
778
+ auto yield_value(with_error<Err> err);
779
+ ```
780
+
781
+ *Mandates:* `std::move(err.error)` is convertible to exactly one of the
782
+ `set_error_t` argument types of `error_types`. Let *`Cerr`* be that
783
+ type.
784
+
785
+ *Returns:* An awaitable object of unspecified type [[expr.await]] whose
786
+ member functions arrange for the calling coroutine to be suspended and
787
+ then completes the asynchronous operation associated with
788
+ *`STATE`*`(*this)` by invoking
789
+ `set_error(std::move(`*`RCVR`*`(*this)), `*`Cerr`*`(std::move(err.error)))`.
790
+
791
+ ``` cpp
792
+ template<sender Sender>
793
+ auto await_transform(Sender&& sndr) noexcept;
794
+ ```
795
+
796
+ *Returns:* If `same_as<inline_scheduler, scheduler_type>` is `true`
797
+ returns `as_awaitable(std::forward<Sender>(sndr), *this)`; otherwise
798
+ returns
799
+ `as_awaitable(affine_on(std::forward<Sender>(sndr), `*`SCHED`*`(*this)), *this)`.
800
+
801
+ ``` cpp
802
+ template<class Sch>
803
+ auto await_transform(change_coroutine_scheduler<Sch> sch) noexcept;
804
+ ```
805
+
806
+ *Effects:* Equivalent to:
807
+
808
+ ``` cpp
809
+ return await_transform(just(exchange(SCHED(*this), scheduler_type(sch.scheduler))), *this);
810
+ ```
811
+
812
+ ``` cpp
813
+ void uncaught_exception();
814
+ ```
815
+
816
+ *Effects:* If the signature `set_error_t(exception_ptr)` is not an
817
+ element of `error_types`, calls `terminate()` [[except.terminate]].
818
+ Otherwise, stores `current_exception()` into *errors*.
819
+
820
+ ``` cpp
821
+ coroutine_handle<> unhandled_stopped();
822
+ ```
823
+
824
+ *Effects:* Completes the asynchronous operation associated with
825
+ *`STATE`*`(*this)` by invoking
826
+ `set_stopped(std::move(`*`RCVR`*`(*this)))`.
827
+
828
+ *Returns:* `noop_coroutine()`.
829
+
830
+ ``` cpp
831
+ unspecified get_env() const noexcept;
832
+ ```
833
+
834
+ *Returns:* An object `env` such that queries are forwarded as follows:
835
+
836
+ - `env.query(get_scheduler)` returns
837
+ `scheduler_type(`*`SCHED`*`(*this))`.
838
+ - `env.query(get_allocator)` returns *alloc*.
839
+ - `env.query(get_stop_token)` returns *token*.
840
+ - For any other query `q` and arguments `a...` a call to
841
+ `env.query(q, a...)` returns *`STATE`*`(*this)`.
842
+ `environment.query(q, a...)` if this expression is well-formed and
843
+ `forwarding_query(q)` is well-formed and is `true`. Otherwise
844
+ `env.query(q, a...)` is ill-formed.
845
+
846
+ ``` cpp
847
+ template<class... Args>
848
+ void* operator new(size_t size, const Args&... args);
849
+ ```
850
+
851
+ If there is no parameter with type `allocator_arg_t` then let `alloc` be
852
+ `allocator_type()`. Otherwise, let `arg_next` be the parameter following
853
+ the first `allocator_arg_t` parameter, and let `alloc` be
854
+ `allocator_type(arg_next)`. Let `PAlloc` be
855
+ `allocator_traits<allocator_type>::template rebind_alloc<U>`, where `U`
856
+ is an unspecified type whose size and alignment are both
857
+ \_\_STDCPP_DEFAULT_NEW_ALIGNMENT\_\_.
858
+
859
+ *Mandates:*
860
+
861
+ - The first parameter of type `allocator_arg_t` (if any) is not the last
862
+ parameter.
863
+ - `allocator_type(arg_next)` is a valid expression if there is a
864
+ parameter of type `allocator_arg_t`.
865
+ - `allocator_traits<PAlloc>::pointer` is a pointer type.
866
+
867
+ *Effects:* Initializes an allocator `palloc` of type `PAlloc` with
868
+ `alloc`. Uses `palloc` to allocate storage for the smallest array of `U`
869
+ sufficient to provide storage for a coroutine state of size `size`, and
870
+ unspecified additional state necessary to ensure that `operator delete`
871
+ can later deallocate this memory block with an allocator equal to
872
+ `palloc`.
873
+
874
+ *Returns:* A pointer to the allocated storage.
875
+
876
+ ``` cpp
877
+ void operator delete(void* pointer, size_t size) noexcept;
878
+ ```
879
+
880
+ *Preconditions:* `pointer` was returned from an invocation of the above
881
+ overload of `operator new` with a size argument equal to `size`.
882
+
883
+ *Effects:* Deallocates the storage pointed to by `pointer` using an
884
+ allocator equal to that used to allocate it.
885
+