forked from cplusplus/draft
-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathexec.tex
5667 lines (4944 loc) · 197 KB
/
exec.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
%!TEX root = std.tex
\rSec0[exec]{Execution control library}
\rSec1[exec.general]{General}
\pnum
This Clause describes components
supporting execution of function objects\iref{function.objects}.
\pnum
The following subclauses describe
the requirements, concepts, and components
for execution control primitives as summarized in \tref{exec.summary}.
\begin{libsumtab}{Execution control library summary}{exec.summary}
\ref{exec.sched} & Schedulers & \tcode{<execution>} \\
\ref{exec.recv} & Receivers & \\
\ref{exec.opstate} & Operation states & \\
\ref{exec.snd} & Senders & \\
\end{libsumtab}
\pnum
\tref{exec.pos} shows
the types of customization point objects\iref{customization.point.object}
used in the execution control library.
\begin{floattable}{Types of customization point objects in the execution control library}{exec.pos}{lx{0.23\hsize}x{0.45\hsize}}
\topline
\lhdr{Customization point} & \chdr{Purpose} & \rhdr{Examples} \\
\lhdr{object type} & & \\
\capsep
core &
provide core execution functionality, and connection between core components &
e.g., \libglobalref{connect}, \libglobalref{start} \\
completion functions &
called by senders to announce the completion of the work (success, error, or cancellation) &
\libglobalref{set_value}, \libglobalref{set_error}, \libglobalref{set_stopped} \\
senders &
allow the specialization of the provided sender algorithms &
\begin{itemize}
\item sender factories (e.g., \libglobalref{schedule}, \libglobalref{just}, \libglobalref{read_env})
\item sender adaptors (e.g., \libglobalref{continues_on}, \libglobalref{then}, \libglobalref{let_value})
\item sender consumers (e.g., \libglobalref{sync_wait})
\end{itemize}
\\
queries &
allow querying different properties of objects &
\begin{itemize}
\item general queries (e.g., \libglobalref{get_allocator}, \libglobalref{get_stop_token})
\item environment queries (e.g., \tcode{get_scheduler}, \libglobalref{get_delegation_scheduler})
\item scheduler queries (e.g., \libglobalref{get_forward_progress_guarantee})
\item sender attribute queries (e.g., \libglobalref{get_completion_scheduler})
\end{itemize}
\\
\end{floattable}
\pnum
This clause makes use of the following exposition-only entities.
\pnum
For a subexpression \tcode{expr},
let \tcode{\exposid{MANDATE-NOTHROW}(expr)} be
expression-equivalent to \tcode{expr}.
\mandates
\tcode{noexcept(expr)} is \tcode{true}.
\pnum
\begin{codeblock}
namespace std {
template<class T>
concept @\defexposconcept{movable-value}@ = // \expos
@\libconcept{move_constructible}@<decay_t<T>> &&
@\libconcept{constructible_from}@<decay_t<T>, T> &&
(!is_array_v<remove_reference_t<T>>);
}
\end{codeblock}
\pnum
For function types \tcode{F1} and \tcode{F2} denoting
\tcode{R1(Args1...)} and \tcode{R2(Args2...)}, respectively,
\tcode{\exposid{MATCHING-SIG}(F1, F2)} is \tcode{true} if and only if
\tcode{\libconcept{same_as}<R1(Args1\&\&...), R2(Args2\&\&...)>}
is \tcode{true}.
\pnum
For a subexpression \tcode{err},
let \tcode{Err} be \tcode{decltype((err))} and
let \tcode{\exposid{AS-EXCEPT-PTR}(err)} be:
\begin{itemize}
\item
\tcode{err} if \tcode{decay_t<Err>} denotes the type \tcode{exception_ptr}.
\expects
\tcode{!err} is \tcode{false}.
\item
Otherwise,
\tcode{make_exception_ptr(system_error(err))}
if \tcode{decay_t<Err>} denotes the type \tcode{error_code}.
\item
Otherwise, \tcode{make_exception_ptr(err)}.
\end{itemize}
\rSec1[exec.queryable]{Queries and queryables}
\rSec2[exec.queryable.general]{General}
\pnum
A \defnadj{queryable}{object} is
a read-only collection of key/value pair
where each key is a customization point object known as a \defn{query object}.
A \defn{query} is an invocation of a query object
with a queryable object as its first argument and
a (possibly empty) set of additional arguments.
A query imposes syntactic and semantic requirements on its invocations.
\pnum
Let \tcode{q} be a query object,
let \tcode{args} be a (possibly empty) pack of subexpressions,
let \tcode{env} be a subexpression
that refers to a queryable object \tcode{o} of type \tcode{O}, and
let \tcode{cenv} be a subexpression referring to \tcode{o}
such that \tcode{decltype((cenv))} is \tcode{const O\&}.
The expression \tcode{q(env, args...)} is equal to\iref{concepts.equality}
the expression \tcode{q(cenv, args...)}.
\pnum
The type of a query expression cannot be \tcode{void}.
\pnum
The expression \tcode{q(env, args...)} is
equality-preserving\iref{concepts.equality} and
does not modify the query object or the arguments.
\pnum
If the expression \tcode{env.query(q, args...)} is well-formed,
then it is expression-equivalent to \tcode{q(env, args...)}.
\pnum
Unless otherwise specified,
the result of a query is valid as long as the queryable object is valid.
\rSec2[exec.queryable.concept]{\tcode{queryable} concept}
\begin{codeblock}
namespace std {
template<class T>
concept @\defexposconcept{queryable}@ = @\libconcept{destructible}@<T>; // \expos
}
\end{codeblock}
\pnum
The exposition-only \exposconcept{queryable} concept specifies
the constraints on the types of queryable objects.
\pnum
Let \tcode{env} be an object of type \tcode{Env}.
The type \tcode{Env} models \exposconcept{queryable}
if for each callable object \tcode{q} and a pack of subexpressions \tcode{args},
if \tcode{requires \{ q(env, args...) \}} is \tcode{true} then
\tcode{q(env, args...)} meets any semantic requirements imposed by \tcode{q}.
\rSec1[exec.async.ops]{Asynchronous operations}
\pnum
An \defnadj{execution}{resource} is a program entity that manages
a (possibly dynamic) set of execution agents\iref{thread.req.lockable.general},
which it uses to execute parallel work on behalf of callers.
\begin{example}
The currently active thread,
a system-provided thread pool, and
uses of an API associated with an external hardware accelerator
are all examples of execution resources.
\end{example}
Execution resources execute asynchronous operations.
An execution resource is either valid or invalid.
\pnum
An \defnadj{asynchronous}{operation} is
a distinct unit of program execution that
\begin{itemize}
\item
is explicitly created;
\item
can be explicitly started once at most;
\item
once started, eventually completes exactly once
with a (possibly empty) set of result datums and
in exactly one of three \defnx{dispositions}{disposition}:
success, failure, or cancellation;
\begin{itemize}
\item
A successful completion, also known as a \defnadj{value}{completion},
can have an arbitrary number of result datums.
\item
A failure completion, also known as an \defnadj{error}{completion},
has a single result datum.
\item
A cancellation completion, also known as a \defnadj{stopped}{completion},
has no result datum.
\end{itemize}
An asynchronous operation's \defnadj{async}{result}
is its disposition and its (possibly empty) set of result datums.
\item
can complete on a different execution resource
than the execution resource on which it started; and
\item
can create and start other asynchronous operations
called \defnadj{child}{operations}.
A child operation is an asynchronous operation
that is created by the parent operation and,
if started, completes before the parent operation completes.
A \defnadj{parent}{operation} is the asynchronous operation
that created a particular child operation.
\end{itemize}
\begin{note}
An asynchronous operation can execute synchronously;
that is, it can complete during the execution of its start operation
on the thread of execution that started it.
\end{note}
\pnum
An asynchronous operation has associated state
known as its \defnadj{operation}{state}.
\pnum
An asynchronous operation has an associated environment.
An \defn{environment} is a queryable object\iref{exec.queryable}
representing the execution-time properties of the operation's caller.
The caller of an asynchronous operation is
its parent operation or the function that created it.
\pnum
An asynchronous operation has an associated receiver.
A \defn{receiver} is an aggregation of three handlers
for the three asynchronous completion dispositions:
\begin{itemize}
\item a value completion handler for a value completion,
\item an error completion handler for an error completion, and
\item a stopped completion handler for a stopped completion.
\end{itemize}
A receiver has an associated environment.
An asynchronous operation's operation state owns the operation's receiver.
The environment of an asynchronous operation
is equal to its receiver's environment.
\pnum
For each completion disposition, there is a \defnadj{completion}{function}.
A completion function is
a customization point object\iref{customization.point.object}
that accepts an asynchronous operation's receiver as the first argument and
the result datums of the asynchronous operation as additional arguments.
The value completion function invokes
the receiver's value completion handler with the value result datums;
likewise for the error completion function and the stopped completion function.
A completion function has
an associated type known as its \defnadj{completion}{tag}
that is the unqualified type of the completion function.
A valid invocation of a completion function is called
a \defnadj{completion}{operation}.
\pnum
The \defn{lifetime of an asynchronous operation},
also known as the operation's \defn{async lifetime},
begins when its start operation begins executing and
ends when its completion operation begins executing.
If the lifetime of an asynchronous operation's associated operation state
ends before the lifetime of the asynchronous operation,
the behavior is undefined.
After an asynchronous operation executes a completion operation,
its associated operation state is invalid.
Accessing any part of an invalid operation state is undefined behavior.
\pnum
An asynchronous operation shall not execute a completion operation
before its start operation has begun executing.
After its start operation has begun executing,
exactly one completion operation shall execute.
The lifetime of an asynchronous operation's operation state can end
during the execution of the completion operation.
\pnum
A \defn{sender} is a factory for one or more asynchronous operations.
\defnx{Connecting}{connect} a sender and a receiver creates
an asynchronous operation.
The asynchronous operation's associated receiver is equal to
the receiver used to create it, and
its associated environment is equal to
the environment associated with the receiver used to create it.
The lifetime of an asynchronous operation's associated operation state
does not depend on the lifetimes of either the sender or the receiver
from which it was created.
A sender is started when it is connected to a receiver and
the resulting asynchronous operation is started.
A sender's async result is the async result of the asynchronous operation
created by connecting it to a receiver.
A sender sends its results by way of the asynchronous operation(s) it produces,
and a receiver receives those results.
A sender is either valid or invalid;
it becomes invalid when its parent sender (see below) becomes invalid.
\pnum
A \defn{scheduler} is an abstraction of an execution resource
with a uniform, generic interface for scheduling work onto that resource.
It is a factory for senders
whose asynchronous operations execute value completion operations
on an execution agent belonging to
the scheduler's associated execution resource.
A \defn{schedule-expression} obtains such a sender from a scheduler.
A \defn{schedule sender} is the result of a schedule expression.
On success, an asynchronous operation produced by a schedule sender executes
a value completion operation with an empty set of result datums.
Multiple schedulers can refer to the same execution resource.
A scheduler can be valid or invalid.
A scheduler becomes invalid when the execution resource to which it refers
becomes invalid,
as do any schedule senders obtained from the scheduler, and
any operation states obtained from those senders.
\pnum
An asynchronous operation has one or more associated completion schedulers
for each of its possible dispositions.
A \defn{completion scheduler} is a scheduler
whose associated execution resource is used to execute
a completion operation for an asynchronous operation.
A value completion scheduler is a scheduler
on which an asynchronous operation's value completion operation can execute.
Likewise for error completion schedulers and stopped completion schedulers.
\pnum
A sender has an associated queryable object\iref{exec.queryable}
known as its \defnx{attributes}{attribute}
that describes various characteristics of the sender and
of the asynchronous operation(s) it produces.
For each disposition,
there is a query object for reading the associated completion scheduler
from a sender's attributes;
i.e., a value completion scheduler query object
for reading a sender's value completion scheduler, etc.
If a completion scheduler query is well-formed,
the returned completion scheduler is unique
for that disposition for any asynchronous operation the sender creates.
A schedule sender is required to have a value completion scheduler attribute
whose value is equal to the scheduler that produced the schedule sender.
\pnum
A \defn{completion signature} is a function type
that describes a completion operation.
An asynchronous operation has a finite set of possible completion signatures
corresponding to the completion operations
that the asynchronous operation potentially evaluates\iref{basic.def.odr}.
For a completion function \tcode{set},
receiver \tcode{rcvr}, and
pack of arguments \tcode{args},
let \tcode{c} be the completion operation \tcode{set(rcvr, args...)}, and
let \tcode{F} be
the function type \tcode{decltype(auto(set))(decltype((args))...)}.
A completion signature \tcode{Sig} is associated with \tcode{c}
if and only if
\tcode{\exposid{MATCHING-SIG}(Sig, F)} is \tcode{true}\iref{exec.general}).
Together, a sender type and an environment type \tcode{Env} determine
the set of completion signatures of an asynchronous operation
that results from connecting the sender with a receiver
that has an environment of type \tcode{Env}.
The type of the receiver does not affect
an asynchronous operation's completion signatures,
only the type of the receiver's environment.
\pnum
A sender algorithm is a function that takes and/or returns a sender.
There are three categories of sender algorithms:
\begin{itemize}
\item
A \defn{sender factory} is a function
that takes non-senders as arguments and that returns a sender.
\item
A \defn{sender adaptor} is a function
that constructs and returns a parent sender
from a set of one or more child senders and
a (possibly empty) set of additional arguments.
An asynchronous operation created by a parent sender is
a parent operation to the child operations created by the child senders.
\item
A \defn{sender consumer} is a function
that takes one or more senders and
a (possibly empty) set of additional arguments, and
whose return type is not the type of a sender.
\end{itemize}
\rSec1[execution.syn]{Header \tcode{<execution>} synopsis}
\indexheader{execution}%
\begin{codeblock}
namespace std {
// \ref{execpol.type}, execution policy type trait
template<class T> struct is_execution_policy;
template<class T> constexpr bool @\libglobal{is_execution_policy_v}@ = is_execution_policy<T>::value;
}
namespace std::execution {
// \ref{execpol.seq}, sequenced execution policy
class sequenced_policy;
// \ref{execpol.par}, parallel execution policy
class parallel_policy;
// \ref{execpol.parunseq}, parallel and unsequenced execution policy
class parallel_unsequenced_policy;
// \ref{execpol.unseq}, unsequenced execution policy
class unsequenced_policy;
// \ref{execpol.objects}, execution policy objects
inline constexpr sequenced_policy seq{ @\unspec@ };
inline constexpr parallel_policy par{ @\unspec@ };
inline constexpr parallel_unsequenced_policy par_unseq{ @\unspec@ };
inline constexpr unsequenced_policy unseq{ @\unspec@ };
}
namespace std {
// \ref{exec.general}, helper concepts
template<class T>
concept @\exposconceptnc{movable-value}@ = @\seebelownc@; // \expos
template<class From, class To>
concept @\defexposconceptnc{decays-to}@ = @\libconcept{same_as}@<decay_t<From>, To>; // \expos
template<class T>
concept @\defexposconceptnc{class-type}@ = @\exposconceptnc{decays-to}@<T, T> && is_class_v<T>; // \expos
// \ref{exec.queryable}, queryable objects
template<class T>
concept @\exposconceptnc{queryable}@ = @\seebelownc@; // \expos
// \ref{exec.queries}, queries
struct @\libglobal{forwarding_query_t}@ { @\unspec@ };
struct @\libglobal{get_allocator_t}@ { @\unspec@ };
struct @\libglobal{get_stop_token_t}@ { @\unspec@ };
inline constexpr forwarding_query_t @\libglobal{forwarding_query}@{};
inline constexpr get_allocator_t @\libglobal{get_allocator}@{};
inline constexpr get_stop_token_t @\libglobal{get_stop_token}@{};
template<class T>
using stop_token_of_t = remove_cvref_t<decltype(get_stop_token(declval<T>()))>;
template<class T>
concept @\defexposconceptnc{forwarding-query}@ = forwarding_query(T{}); // \expos
}
namespace std::execution {
// \ref{exec.queries}, queries
struct @\libglobal{get_domain_t}@ { @\unspec@ };
struct @\libglobal{get_scheduler_t}@ { @\unspec@ };
struct @\libglobal{get_delegation_scheduler_t}@ { @\unspec@ };
struct @\libglobal{get_forward_progress_guarantee_t}@ { @\unspec@ };
template<class CPO>
struct @\libglobal{get_completion_scheduler_t}@ { @\unspec@ };
inline constexpr get_domain_t @\libglobal{get_domain}@{};
inline constexpr get_scheduler_t @\libglobal{get_scheduler}@{};
inline constexpr get_delegation_scheduler_t @\libglobal{get_delegation_scheduler}@{};
enum class forward_progress_guarantee;
inline constexpr get_forward_progress_guarantee_t @\libglobal{get_forward_progress_guarantee}@{};
template<class CPO>
constexpr get_completion_scheduler_t<CPO> @\libglobal{get_completion_scheduler}@{};
struct @\libglobal{get_env_t}@ { @\unspec@ };
inline constexpr get_env_t @\libglobal{get_env}@{};
template<class T>
using @\libglobal{env_of_t}@ = decltype(get_env(declval<T>()));
// \ref{exec.prop}, class template \tcode{prop}
template<class QueryTag, class ValueType>
struct prop;
// \ref{exec.env}, class template \tcode{env}
template<@\exposconcept{queryable}@... Envs>
struct env;
// \ref{exec.domain.default}, execution domains
struct default_domain;
// \ref{exec.sched}, schedulers
struct @\libglobal{scheduler_t}@ {};
template<class Sch>
concept @\libconcept{scheduler}@ = @\seebelow@;
// \ref{exec.recv}, receivers
struct @\libglobal{receiver_t}@ {};
template<class Rcvr>
concept @\libconcept{receiver}@ = @\seebelow@;
template<class Rcvr, class Completions>
concept @\libconcept{receiver_of}@ = @\seebelow@;
struct @\libglobal{set_value_t}@ { @\unspec@ };
struct @\libglobal{set_error_t}@ { @\unspec@ };
struct @\libglobal{set_stopped_t}@ { @\unspec@ };
inline constexpr set_value_t @\libglobal{set_value}@{};
inline constexpr set_error_t @\libglobal{set_error}@{};
inline constexpr set_stopped_t @\libglobal{set_stopped}@{};
// \ref{exec.opstate}, operation states
struct @\libglobal{operation_state_t}@ {};
template<class O>
concept @\libconcept{operation_state}@ = @\seebelow@;
struct @\libglobal{start_t}@;
inline constexpr start_t @\libglobal{start}@{};
// \ref{exec.snd}, senders
struct @\libglobal{sender_t}@ {};
template<class Sndr>
concept @\libconcept{sender}@ = @\seebelow@;
template<class Sndr, class Env = env<>>
concept @\libconcept{sender_in}@ = @\seebelow@;
template<class Sndr, class Rcvr>
concept @\libconcept{sender_to}@ = @\seebelow@;
template<class... Ts>
struct @\exposidnc{type-list}@; // \expos
// \ref{exec.getcomplsigs}, completion signatures
struct get_completion_signatures_t;
inline constexpr get_completion_signatures_t get_completion_signatures {};
template<class Sndr, class Env = env<>>
requires @\libconcept{sender_in}@<Sndr, Env>
using completion_signatures_of_t = @\exposid{call-result-t}@<get_completion_signatures_t, Sndr, Env>;
template<class... Ts>
using @\exposidnc{decayed-tuple}@ = tuple<decay_t<Ts>...>; // \expos
template<class... Ts>
using @\exposidnc{variant-or-empty}@ = @\seebelownc@; // \expos
template<class Sndr, class Env = env<>,
template<class...> class Tuple = @\exposid{decayed-tuple}@,
template<class...> class Variant = @\exposid{variant-or-empty}@>
requires @\libconcept{sender_in}@<Sndr, Env>
using value_types_of_t = @\seebelow@;
template<class Sndr, class Env = env<>,
template<class...> class Variant = @\exposid{variant-or-empty}@>
requires @\libconcept{sender_in}@<Sndr, Env>
using error_types_of_t = @\seebelow@;
template<class Sndr, class Env = env<>>
requires @\libconcept{sender_in}@<Sndr, Env>
constexpr bool sends_stopped = @\seebelow@;
template<class Sndr, class Env>
using @\exposidnc{single-sender-value-type}@ = @\seebelownc@; // \expos
template<class Sndr, class Env>
concept @\exposconcept{single-sender}@ = @\seebelow@; // \expos
template<@\libconcept{sender}@ Sndr>
using tag_of_t = @\seebelow@;
// \ref{exec.snd.transform}, sender transformations
template<class Domain, @\libconcept{sender}@ Sndr, @\exposconcept{queryable}@... Env>
requires (sizeof...(Env) <= 1)
constexpr @\libconcept{sender}@ decltype(auto) transform_sender(
Domain dom, Sndr&& sndr, const Env&... env) noexcept(@\seebelow@);
// \ref{exec.snd.transform.env}, environment transformations
template<class Domain, @\libconcept{sender}@ Sndr, @\exposconcept{queryable}@ Env>
constexpr @\exposconcept{queryable}@ decltype(auto) transform_env(
Domain dom, Sndr&& sndr, Env&& env) noexcept;
// \ref{exec.snd.apply}, sender algorithm application
template<class Domain, class Tag, @\libconcept{sender}@ Sndr, class... Args>
constexpr decltype(auto) apply_sender(
Domain dom, Tag, Sndr&& sndr, Args&&... args) noexcept(@\seebelow@);
// \ref{exec.connect}, the connect sender algorithm
struct @\libglobal{connect_t}@;
inline constexpr connect_t @\libglobal{connect}@{};
template<class Sndr, class Rcvr>
using @\libglobal{connect_result_t}@ =
decltype(connect(declval<Sndr>(), declval<Rcvr>()));
// \ref{exec.factories}, sender factories
struct @\libglobal{just_t}@ { @\unspec@ };
struct @\libglobal{just_error_t}@ { @\unspec@ };
struct @\libglobal{just_stopped_t}@ { @\unspec@ };
struct @\libglobal{schedule_t}@ { @\unspec@ };
inline constexpr just_t @\libglobal{just}@{};
inline constexpr just_error_t @\libglobal{just_error}@{};
inline constexpr just_stopped_t @\libglobal{just_stopped}@{};
inline constexpr schedule_t @\libglobal{schedule}@{};
inline constexpr @\unspec@ @\libglobal{read_env}@{};
template<@\libconcept{scheduler}@ Sndr>
using @\libglobal{schedule_result_t}@ = decltype(schedule(declval<Sndr>()));
// \ref{exec.adapt}, sender adaptors
template<@\exposconcept{class-type}@ D>
struct @\libglobal{sender_adaptor_closure}@ { };
struct @\libglobal{starts_on_t}@ { @\unspec@ };
struct @\libglobal{continues_on_t}@ { @\unspec@ };
struct @\libglobal{on_t}@ { @\unspec@ };
struct @\libglobal{schedule_from_t}@ { @\unspec@ };
struct @\libglobal{then_t}@ { @\unspec@ };
struct @\libglobal{upon_error_t}@ { @\unspec@ };
struct @\libglobal{upon_stopped_t}@ { @\unspec@ };
struct @\libglobal{let_value_t}@ { @\unspec@ };
struct @\libglobal{let_error_t}@ { @\unspec@ };
struct @\libglobal{let_stopped_t}@ { @\unspec@ };
struct @\libglobal{bulk_t}@ { @\unspec@ };
struct @\libglobal{split_t}@ { @\unspec@ };
struct @\libglobal{when_all_t}@ { @\unspec@ };
struct @\libglobal{when_all_with_variant_t}@ { @\unspec@ };
struct @\libglobal{into_variant_t}@ { @\unspec@ };
struct @\libglobal{stopped_as_optional_t}@ { @\unspec@ };
struct @\libglobal{stopped_as_error_t}@ { @\unspec@ };
inline constexpr starts_on_t @\libglobal{starts_on}@{};
inline constexpr continues_on_t @\libglobal{continues_on}@{};
inline constexpr on_t @\libglobal{on}@{};
inline constexpr schedule_from_t @\libglobal{schedule_from}@{};
inline constexpr then_t @\libglobal{then}@{};
inline constexpr upon_error_t @\libglobal{upon_error}@{};
inline constexpr upon_stopped_t @\libglobal{upon_stopped}@{};
inline constexpr let_value_t @\libglobal{let_value}@{};
inline constexpr let_error_t @\libglobal{let_error}@{};
inline constexpr let_stopped_t @\libglobal{let_stopped}@{};
inline constexpr bulk_t @\libglobal{bulk}@{};
inline constexpr split_t @\libglobal{split}@{};
inline constexpr when_all_t @\libglobal{when_all}@{};
inline constexpr when_all_with_variant_t @\libglobal{when_all_with_variant}@{};
inline constexpr into_variant_t @\libglobal{into_variant}@{};
inline constexpr stopped_as_optional_t @\libglobal{stopped_as_optional}@{};
inline constexpr stopped_as_error_t @\libglobal{stopped_as_error}@{};
// \ref{exec.util}, sender and receiver utilities
// \ref{exec.util.cmplsig}
template<class Fn>
concept @\exposconceptnc{completion-signature}@ = @\seebelownc@; // \expos
template<@\exposconcept{completion-signature}@... Fns>
struct @\libglobal{completion_signatures}@ {};
template<class Sigs>
concept @\exposconceptnc{valid-completion-signatures}@ = @\seebelownc@; // \expos
// \ref{exec.util.cmplsig.trans}
template<
@\exposconcept{valid-completion-signatures}@ InputSignatures,
@\exposconcept{valid-completion-signatures}@ AdditionalSignatures = completion_signatures<>,
template<class...> class SetValue = @\seebelow@,
template<class> class SetError = @\seebelow@,
@\exposconcept{valid-completion-signatures}@ SetStopped = completion_signatures<set_stopped_t()>>
using transform_completion_signatures = completion_signatures<@\seebelow@>;
template<
@\libconcept{sender}@ Sndr,
class Env = env<>,
@\exposconcept{valid-completion-signatures}@ AdditionalSignatures = completion_signatures<>,
template<class...> class SetValue = @\seebelow@,
template<class> class SetError = @\seebelow@,
@\exposconcept{valid-completion-signatures}@ SetStopped = completion_signatures<set_stopped_t()>>
requires @\libconcept{sender_in}@<Sndr, Env>
using transform_completion_signatures_of =
transform_completion_signatures<
completion_signatures_of_t<Sndr, Env>,
AdditionalSignatures, SetValue, SetError, SetStopped>;
// \ref{exec.run.loop}, run_loop
class run_loop;
}
namespace std::this_thread {
// \ref{exec.consumers}, consumers
struct @\libglobal{sync_wait_t}@ { @\unspec@ };
struct @\libglobal{sync_wait_with_variant_t}@ { @\unspec@ };
inline constexpr sync_wait_t @\libglobal{sync_wait}@{};
inline constexpr sync_wait_with_variant_t @\libglobal{sync_wait_with_variant}@{};
}
namespace std::execution {
// \ref{exec.as.awaitable}
struct @\libglobal{as_awaitable_t}@ { @\unspec@ };
inline constexpr as_awaitable_t @\libglobal{as_awaitable}@{};
// \ref{exec.with.awaitable.senders}
template<@\exposconcept{class-type}@ Promise>
struct with_awaitable_senders;
}
\end{codeblock}
\pnum
The exposition-only type \tcode{\exposid{variant-or-empty}<Ts...>}
is defined as follows:
\begin{itemize}
\item
If \tcode{sizeof...(Ts)} is greater than zero,
\tcode{\exposid{variant-or-empty}<Ts...>} denotes \tcode{variant<Us...>}
where \tcode{Us...} is the pack \tcode{decay_t<Ts>...}
with duplicate types removed.
\item
Otherwise, \tcode{\exposid{variant-or-empty}<Ts...>} denotes
the exposition-only class type:
\begin{codeblock}
namespace std::execution {
struct @\exposidnc{empty-variant}@ { // \expos
@\exposidnc{empty-variant}@() = delete;
};
}
\end{codeblock}
\end{itemize}
\pnum
For types \tcode{Sndr} and \tcode{Env},
\tcode{\exposid{single-sender-value-type}<Sndr, Env>} is an alias for:
\begin{itemize}
\item
\tcode{value_types_of_t<Sndr, Env, decay_t, type_identity_t>}
if that type is well-formed,
\item
Otherwise, \tcode{void}
if \tcode{value_types_of_t<Sndr, Env, tuple, variant>} is
\tcode{variant<tuple<>>} or \tcode{vari\-ant<>},
\item
Otherwise, \tcode{value_types_of_t<Sndr, Env, \exposid{decayed-tuple}, type_identity_t>}
if that type is well-formed,
\item
Otherwise, \tcode{\exposid{single-sender-value-type}<Sndr, Env>} is ill-formed.
\end{itemize}
\pnum
The exposition-only concept \exposconcept{single-sender} is defined as follows:
\begin{codeblock}
namespace std::execution {
template<class Sndr, class Env>
concept @\defexposconcept{single-sender}@ = @\libconcept{sender_in}@<Sndr, Env> &&
requires {
typename @\exposid{single-sender-value-type}@<Sndr, Env>;
};
}
\end{codeblock}
\rSec1[exec.queries]{Queries}
\rSec2[exec.fwd.env]{\tcode{forwarding_query}}
\pnum
\tcode{forwarding_query} asks a query object
whether it should be forwarded through queryable adaptors.
\pnum
The name \tcode{forwarding_query} denotes a query object.
For some query object \tcode{q} of type \tcode{Q},
\tcode{forwarding_query(q)} is expression-equivalent to:
\begin{itemize}
\item
\tcode{\exposid{MANDATE-NOTHROW}(q.query(forwarding_query))}
if that expression is well-formed.
\mandates
The expression above has type \tcode{bool} and
is a core constant expression if \tcode{q} is a core constant expression.
\item
Otherwise, \tcode{true} if \tcode{\libconcept{derived_from}<Q, forwarding_query_t>} is \tcode{true}.
\item
Otherwise, \tcode{false}.
\end{itemize}
\rSec2[exec.get.allocator]{\tcode{get_allocator}}
\pnum
\tcode{get_allocator} asks a queryable object for its associated allocator.
\pnum
The name \tcode{get_allocator} denotes a query object.
For a subexpression \tcode{env},
\tcode{get_allocator(env)} is expression-equivalent to
\tcode{\exposid{MANDATE-NOTHROW}(as_const(env).query(get_allocator))}.
\mandates
If the expression above is well-formed,
its type satisfies
\exposconcept{simple-allocator}\iref{allocator.requirements.general}.
\pnum
\tcode{forwarding_query(get_allocator)} is a core constant expression and
has value \tcode{true}.
\rSec2[exec.get.stop.token]{\tcode{get_stop_token}}
\pnum
\tcode{get_stop_token} asks a queryable object for an associated stop token.
\pnum
The name \tcode{get_stop_token} denotes a query object.
For a subexpression \tcode{env},
\tcode{get_stop_token(env)} is expression-equivalent to:
\begin{itemize}
\item
\tcode{\exposid{MANDATE-NOTHROW}(as_const(env).query(get_stop_token))}
if that expression is well-formed.
\mandates
The type of the expression above satisfies \libconcept{stoppable_token}.
\item
Otherwise, \tcode{never_stop_token\{\}}.
\end{itemize}
\pnum
\tcode{forwarding_query(get_stop_token)} is a core constant expression and
has value \tcode{true}.
\rSec2[exec.get.env]{\tcode{execution::get_env}}
\pnum
\tcode{execution::get_env} is a customization point object.
For a subexpression \tcode{o},
\tcode{execution::get_env(o)} is expression-equivalent to:
\begin{itemize}
\item
\tcode{\exposid{MANDATE-NOTHROW}(as_const(o).get_env())}
if that expression is well-formed.
\mandates
The type of the expression above satisfies
\exposconcept{queryable}\iref{exec.queryable}.
\item
Otherwise, \tcode{env<>\{\}}.
\end{itemize}
\pnum
The value of \tcode{get_env(o)} shall be valid while \tcode{o} is valid.
\pnum
\begin{note}
When passed a sender object,
\tcode{get_env} returns the sender's associated attributes.
When passed a receiver,
\tcode{get_env} returns the receiver's associated execution environment.
\end{note}
\rSec2[exec.get.domain]{\tcode{execution::get_domain}}
\pnum
\tcode{get_domain} asks a queryable object
for its associated execution domain tag.
\pnum
The name \tcode{get_domain} denotes a query object.
For a subexpression \tcode{env},
\tcode{get_domain(env)} is expression-equivalent to
\tcode{\exposid{MANDATE-NOTHROW}(as_const(env).query(get_domain))}.
\pnum
\tcode{forwarding_query(execution::get_domain)} is
a core constant expression and has value \tcode{true}.
\rSec2[exec.get.scheduler]{\tcode{execution::get_scheduler}}
\pnum
\tcode{get_scheduler} asks a queryable object for its associated scheduler.
\pnum
The name \tcode{get_scheduler} denotes a query object.
For a subexpression \tcode{env},
\tcode{get_scheduler(env)} is expression-equivalent to
\tcode{\exposid{MANDATE-NOTHROW}(as_const(env).query(get_scheduler))}.
\mandates
If the expression above is well-formed,
its type satisfies \libconcept{scheduler}.
\pnum
\tcode{forwarding_query(execution::get_scheduler)} is
a core constant expression and has value \tcode{true}.
\rSec2[exec.get.delegation.scheduler]{\tcode{execution::get_delegation_scheduler}}
\pnum
\tcode{get_delegation_scheduler} asks a queryable object for a scheduler
that can be used to delegate work to
for the purpose of forward progress delegation\iref{intro.progress}.
\pnum
The name \tcode{get_delegation_scheduler} denotes a query object.
For a subexpression \tcode{env},
\tcode{get_delegation_scheduler(env)} is expression-equivalent to
\tcode{\exposid{MANDATE-NOTHROW}(as_const(env).query(get_delegation_scheduler))}.
\mandates
If the expression above is well-formed,
its type satisfies \libconcept{scheduler}.
\pnum
\tcode{forwarding_query(execution::get_delegation_scheduler)} is
a core constant expression and has value \tcode{true}.
\rSec2[exec.get.fwd.progress]{\tcode{execution::get_forward_progress_guarantee}}
\begin{codeblock}
namespace std::execution {
enum class @\libglobal{forward_progress_guarantee}@ {
concurrent,
parallel,
weakly_parallel
};
}
\end{codeblock}
\pnum
\tcode{get_forward_progress_guarantee} asks a scheduler about
the forward progress guarantee of execution agents
created by that scheduler's associated execution resource\iref{intro.progress}.
\pnum
The name \tcode{get_forward_progress_guarantee} denotes a query object.
For a subexpression \tcode{sch}, let \tcode{Sch} be \tcode{decltype((sch))}.
If \tcode{Sch} does not satisfy \libconcept{scheduler},
\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}(as_const(sch).query(get_forward_progress_guarantee))},
if that expression is well-formed.
\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}
returns \tcode{forward_progress_guaran\-tee::concurrent},
all execution agents created by that scheduler's associated execution resource
shall provide the concurrent forward progress guarantee.
If it returns \tcode{forward_progress_guarantee::parallel},
all such execution agents
shall provide at least the parallel forward progress guarantee.
\rSec2[exec.get.compl.sched]{\tcode{execution::get_completion_scheduler}}
\pnum
\tcode{get_completion_scheduler<\exposid{completion-tag>}} obtains
the completion scheduler associated with a completion tag
from a sender's attributes.
\pnum
The name \tcode{get_completion_scheduler} denotes a query object template.
For a subexpression \tcode{q},
the expression \tcode{get_completion_scheduler<\exposid{completion-tag}>(q)}
is ill-formed if \exposid{completion-tag} is not one of
\tcode{set_value_t}, \tcode{set_error_t}, or \tcode{set_stopped_t}.
Otherwise, \tcode{get_completion_scheduler<\exposid{completion-tag}>(q)}
is expression-equivalent to
\begin{codeblock}
@\exposid{MANDATE-NOTHROW}@(as_const(q).query(get_completion_scheduler<@\exposid{completion-tag}@>))
\end{codeblock}
\mandates
If the expression above is well-formed,
its type satisfies \libconcept{scheduler}.
\pnum
Let \exposid{completion-fn} be a completion function\iref{exec.async.ops};
let \exposid{completion-tag} be
the associated completion tag of \exposid{completion-fn};
let \tcode{args} be a pack of subexpressions; and
let \tcode{sndr} be a subexpression
such that \tcode{\libconcept{sender}<decltype((sndr))>} is \tcode{true} and
\tcode{get_completion_scheduler<\exposid{completion-tag}>(get_env(sndr))}
is well-formed and denotes a scheduler \tcode{sch}.
If an asynchronous operation
created by connecting \tcode{sndr} with a receiver \tcode{rcvr}
causes the evaluation of \tcode{\exposid{completion-fn}(rcvr, args...)},
the behavior is undefined
unless the evaluation happens on an execution agent
that belongs to \tcode{sch}'s associated execution resource.
\pnum
The expression
\tcode{forwarding_query(get_completion_scheduler<\exposid{completion-tag}>)}
is a core constant expression and has value \tcode{true}.
\rSec1[exec.sched]{Schedulers}