diff --git a/execution.bs b/execution.bs index 0b15fb3..2c77308 100644 --- a/execution.bs +++ b/execution.bs @@ -6169,7 +6169,7 @@ namespace std::execution { namespace std::execution { template<class Sch> concept scheduler = - derived_from<typename Sch::scheduler_concept, scheduler_t> && + derived_from<typename remove_cvref_t<Sch>::scheduler_concept, scheduler_t> && queryable<Sch> && requires(Sch&& sch) { { schedule(std::forward<Sch>(sch)) } -> sender; @@ -6227,7 +6227,7 @@ namespace std::execution { namespace std::execution { template<class Rcvr> concept receiver = - derived_from<typename Rcvr::receiver_concept, receiver_t> && + derived_from<typename remove_cvref_t<Rcvr>::receiver_concept, receiver_t> && requires(const remove_cvref_t<Rcvr>& rcvr) { { get_env(rcvr) } -> queryable; } && @@ -6561,7 +6561,8 @@ namespace std::execution { 1. `product-type` is presented here in pseudo-code form for the sake of exposition. It can be approximated in standard C++ with a `tuple`-like implementation that takes care - to keep the type structural. + to keep the type an aggregate that can be used as the initializer of a + structured binding declaration. 2. An expression of type `product-type` is usable as the initializer of a @@ -7459,7 +7460,7 @@ namespace std::execution { 2. The names `just`, `just_error`, and `just_stopped` denote customization point objects. Let `just-cpo` be one of `just`, `just_error`, or `just_stopped`. For a pack of subexpressions `ts`, let `Ts` - be the template parameter pack `decltype((ts))`. The expression + be the pack of types `decltype((ts))`. The expression just-cpo(ts...) is ill-formed if: - (movable-value<Ts> &&...) is `false`, or @@ -8382,7 +8383,7 @@ request but has no recommendataions at present. given an instance `env`, the expression `get_stop_token(env)` is well-formed and has type `inplace_stop_token`. -3. The names `split` and `ensure_started` denote pipeable sender adaptor closure objects. +3. The names `split` and `ensure_started` denote pipeable sender adaptor objects. Let the expression `shared-cpo` be one of `split` or `ensure_started`. For a subexpression `sndr`, let `Sndr` be `decltype((sndr))`. If sender_in<Sndr, shared-env> is @@ -8686,7 +8687,7 @@ request but has no recommendataions at present. 2. The member impls-for<shared-impl-tag>::start - is initialized with a callable object that has a call operator + is initialized with a callable object that has a function call operator equivalent to the following:
@@ -8704,7 +8705,7 @@ request but has no recommendataions at present.
                 
                 state.on_stop.emplace(
                   get_stop_token(get_env(rcvr)),
-                  on-stop-request{state.sh_state->stop_src})
+                  on-stop-request{state.sh_state->stop_src});
                 
2. If `shared-impl-tag` is `ensure-started-impl-tag`, @@ -8713,15 +8714,15 @@ request but has no recommendataions at present. 3. Otherwise, atomically does the following: - - Inserts `&state` into `state.sh_state->waiting_states`, and + - Inserts `addressof(state)` into `state.sh_state->waiting_states`, and - Reads the value of `state.sh_state->completed`. 4. If the value read from `state.sh_state->completed` is `true`, calls state.notify() and returns. - 4. Otherwise, if `shared-impl-tag` is - `split-impl-tag`, and if `&state` is the first item added + 5. Otherwise, if `shared-impl-tag` is + `split-impl-tag`, and if `addressof(state)` is the first item added to `state.sh_state->waiting_states`, calls state.sh_state->start-op(). @@ -8751,9 +8752,8 @@ request but has no recommendataions at present. 2. The names `when_all` and `when_all_with_variant` denote customization point objects. Let `sndrs` be a pack of subexpressions, let `Sndrs` be a pack of the types `decltype((sndrs))...`, and let `CD` be the type - common_type_t<DOMAIN-OF(sndrs)...>, where - DOMAIN-OF(sndr) is the type of - get-domain-early(sndr). The expressions `when_all(sndrs...)` and + common_type_t<decltype(get-domain-early(sndrs))...>. + The expressions `when_all(sndrs...)` and `when_all_with_variant(sndrs...)` are ill-formed if any of the following is true: @@ -8768,7 +8768,7 @@ request but has no recommendataions at present.
       transform_sender(
         CD(),
-        make-sender(when_all, {}, sndrs...));
+        make-sender(when_all, {}, sndrs...))
       
4. The exposition-only class template `impls-for` @@ -8823,9 +8823,9 @@ request but has no recommendataions at present.
where `e` is the expression: - +
-          std::forward<Sndr>(sndr).apply(make-state<Rcvr>{get_env(rcvr)})
+          std::forward<Sndr>(sndr).apply(make-state<Rcvr>())
           
and where `make-state` is the following exposition-only class template: @@ -8839,8 +8839,6 @@ request but has no recommendataions at present. template<class Rcvr> struct make-state { - const env_of_t<Rcvr>& env; - template<max-1-sender-in<env_of_t<Rcvr>>... Sndrs> auto operator()(auto, auto, Sndrs&&... sndrs) const { using values_tuple = see below; @@ -9025,7 +9023,7 @@ request but has no recommendataions at present. 1. `into_variant` adapts a sender with multiple value completion signatures into a sender with just one value completion signature consisting of a `variant` of `tuple`s. -2. The name `into_variant` denotes a pipeable sender adaptor closure object. For a +2. The name `into_variant` denotes a pipeable sender adaptor object. For a subexpression `sndr`, let `Sndr` be `decltype((sndr))`. If `Sndr` does not satisfy `sender`, `into_variant(sndr)` is ill-formed. @@ -9087,7 +9085,7 @@ request but has no recommendataions at present. sender that never completes with stopped, reporting cancellation by completing with an disengaged `optional`. -2. The name `stopped_as_optional` denotes a pipeable sender adaptor closure +2. The name `stopped_as_optional` denotes a pipeable sender adaptor object. For a subexpression `sndr`, let `Sndr` be `decltype((sndr))`. The expression `stopped_as_optional(sndr)` is expression-equivalent to: @@ -9124,7 +9122,7 @@ request but has no recommendataions at present. that never completes with stopped, reporting cancellation by completing with an error. -2. The name `stopped_as_error` denotes a pipeable sender adaptor closure object. +2. The name `stopped_as_error` denotes a pipeable sender adaptor object. For some subexpressions `sndr` and `err`, let `Sndr` be `decltype((sndr))` and let `Err` be `decltype((err))`. If the type `Sndr` does not satisfy `sender` or if the type `Err` doesn't satisfy `movable-value`, @@ -9498,7 +9496,7 @@ request but has no recommendataions at present. only if it is a function type with one of the following forms: * set_value_t(Vs...), where `Vs` - is an parameter pack of object or reference types. + is a pack of object or reference types. * set_error_t(Err), where `Err` is an object or reference type. * `set_stopped_t()` @@ -9511,11 +9509,11 @@ request but has no recommendataions at present. using gather-signatures = see below; - 2. Let `Fns...` be a template parameter pack of the arguments of the + 2. Let `Fns` be a pack of the arguments of the `completion_signatures` specialization named by `Completions`, let - `TagFns` be a template parameter pack of the function + `TagFns` be a pack of the function types in `Fns` whose return types are `Tag`, and let - Tsn be a template parameter pack + Tsn be a pack of the function argument types in the `n`-th type in `TagFns`. Then, given two variadic templates `Tuple` and `Variant`, the type @@ -9525,7 +9523,7 @@ request but has no recommendataions at present. Ts0...), META-APPLY(Tuple, Ts1...), ... META-APPLY(Tuple, Tsm-1...)), where `m` - is the size of the parameter pack `TagFns` and + is the size of the pack `TagFns` and META-APPLY(T, As...) is equivalent to:
@@ -9567,8 +9565,6 @@ request but has no recommendataions at present.
     
- - ### `execution::transform_completion_signatures` [exec.utils.tfxcmplsigs] ### {#spec-execution.snd_rec_utils.transform_completion_sigs} 1. `transform_completion_signatures` is an alias template used to transform one @@ -9596,7 +9592,7 @@ request but has no recommendataions at present. -- end example] -3. This subclause makes use of the following exposition-only entities: +3. [exec.utils.tfxcmplsigs] makes use of the following exposition-only entities:
     template<class... As>
@@ -9622,8 +9618,8 @@ request but has no recommendataions at present.
     }
     
- 1. `SetValue` shall name an alias template such that for any template - parameter pack `As...`, the type `SetValue` is either ill-formed + 1. `SetValue` shall name an alias template such that for any + pack of types `As`, the type `SetValue` is either ill-formed or else valid-completion-signatures<SetValue<As...>> is satisfied. @@ -9642,7 +9638,7 @@ request but has no recommendataions at present. named by gather-signatures<set_error_t, InputSignatures, type_identity_t, error-list>, where `error-list` is an alias template such that - error-list<Ts...> names + error-list<Ts...> is type-list<SetError<Ts>...>. 5. Let `Ss` name the type `completion_signatures<>` if @@ -9654,38 +9650,36 @@ request but has no recommendataions at present. 6. If any of the above types are ill-formed, then `transform_completion_signatures` is ill-formed, + SetValue, SetError, SetStopped>` is ill-formed. 7. Otherwise, `transform_completion_signatures` names the type + AdditionalSignatures, SetValue, SetError, SetStopped>` is the type `completion_signatures` where `Sigs...` is the unique set of types in all the template arguments of all the `completion_signatures` - specializations in `[AdditionalSignatures, Vs..., Es..., Ss]`. + specializations in the set `AdditionalSignatures, Vs..., Es..., Ss`. ## Execution contexts [exec.ctx] ## {#spec-execution.contexts} -1. This subclause specifies some execution resources on which work can be - scheduled. - ### `run_loop` [exec.run.loop] ### {#spec-execution.contexts.run_loop} 1. A `run_loop` is an execution resource on which work can be scheduled. It - maintains a simple, thread-safe first-in-first-out queue of work. Its `run()` + maintains a thread-safe first-in-first-out queue of work. Its `run()` member function removes elements from the queue and executes them in a loop - on whatever thread of execution calls `run()`. + on the thread of execution calls `run()`. 2. A `run_loop` instance has an associated count that corresponds to the - number of work items that are in its queue. Additionally, a `run_loop` has an + number of work items that are in its queue. Additionally, a `run_loop` instance has an associated state that can be one of starting, running, or finishing. -3. Concurrent invocations of the member functions of `run_loop`, other than - `run` and its destructor, do not introduce data races. The member functions +3. Concurrent invocations of the member functions of `run_loop` other than + `run` and its destructor do not introduce data races. The member functions `pop_front`, `push_back`, and `finish` execute atomically. -4. Implementations are encouraged to use an intrusive +4. *Recommended practice:* Implementations are encouraged to use an intrusive queue of operation states to hold the work units to make scheduling - allocation-free. + allocation-free. +
     namespace std::execution {
@@ -9694,16 +9688,18 @@ request but has no recommendataions at present.
         class run-loop-scheduler; // exposition only
         class run-loop-sender; // exposition only
         struct run-loop-opstate-base { // exposition only
-          virtual void execute() = 0;
-          run_loop* loop;
-          run-loop-opstate-base* next;
+          virtual void execute() = 0;  // exposition only
+          run_loop* loop;  // exposition only
+          run-loop-opstate-base* next;  // exposition only
         };
         template<receiver_of<completion_signatures<set_value_t()>> Rcvr>
           using run-loop-opstate = unspecified; // exposition only
 
+
+TODO: kebab these:
         // [exec.run.loop.members] Member functions:
-        run-loop-opstate-base* pop_front(); // exposition only
-        void push_back(run-loop-opstate-base*); // exposition only
+        run-loop-opstate-base* pop-front(); // exposition only
+        void push-back(run-loop-opstate-base*); // exposition only
 
       public:
         // [exec.run.loop.ctor] construct/copy/destroy
@@ -9726,7 +9722,7 @@ class run-loop-scheduler;
 
1. `run-loop-scheduler` is an unspecified type that models - the `scheduler` concept. + `scheduler`. 2. Instances of `run-loop-scheduler` remain valid until the end of the lifetime of the `run_loop` instance from which they were @@ -9737,17 +9733,21 @@ class run-loop-scheduler; 4. Let `sch` be an expression of type `run-loop-scheduler`. The expression - schedule(sch) is not potentially-throwing and has type - `run-loop-sender`. + schedule(sch) has type + `run-loop-sender` and is not potentially-throwing + if `sch` is not potentially-throwing.
 class run-loop-sender;
 
-1. `run-loop-sender` is an unspecified type such that - sender-of<run-loop-sender> is `true`. - Additionally, the types reported by its `error_types` associated type is - `exception_ptr`, and the value of its `sends_stopped` trait is `true`. +1. `run-loop-sender` is an unspecified type such that for any + type `Env`, completion_signatures_of_t<run-loop-sender, Env> + is: + +
+      completion_signatures<set_value_t(), set_error_t(exception_ptr), set_stopped_t()>
+      
2. An instance of `run-loop-sender` remains valid until the end of the lifetime of its associated `run_loop` instance. @@ -9776,7 +9776,7 @@ template<receiver_of<completion_signatures<set_value_t()>> Rcvr> struct run-loop-opstate; -1. run-loop-opstate<Rcvr> inherits unambiguously +1. run-loop-opstate<Rcvr> inherits privately and unambiguously from `run-loop-opstate-base`. 2. Let `o` be a non-`const` lvalue of type @@ -9791,8 +9791,8 @@ template<receiver_of<completion_signatures<set_value_t()>> Rcvr> refers. * The type run-loop-opstate<Rcvr> overrides - run-loop-opstate-base::execute() such that - o.execute() is equivalent to the following: + run-loop-opstate-base::execute() such that + o.execute() is equivalent to the following:
         if (get_stop_token(REC(o)).stop_requested()) {
@@ -9807,7 +9807,7 @@ template<receiver_of<completion_signatures<set_value_t()>> Rcvr>
 
         
         try {
-          o.loop->push_back(&o);
+          o.loop->push-back(&o);
         } catch(...) {
           set_error(std::move(REC(o)), current_exception());
         }
@@ -9832,27 +9832,27 @@ run_loop() noexcept;
 #### Member functions [exec.run.loop.members] #### {#spec-execution.contexts.run_loop.members}
 
 
-run-loop-opstate-base* pop_front();
+run-loop-opstate-base* pop-front();
 
1. Effects: Blocks ([defns.block]) until one of the following conditions is `true`: * count is `0` and state is finishing, in which case - `pop_front` returns `nullptr`; or + `pop-front` returns `nullptr`; or * count is greater than `0`, in which case an item is removed from the front of the queue, count is decremented by `1`, and the removed item is returned.
-void push_back(run-loop-opstate-base* item);
+void push-back(run-loop-opstate-base* item);
 
1. Effects: Adds `item` to the back of the queue and increments count by `1`. -2. Synchronization: This operation synchronizes with the `pop_front` +2. Synchronization: This operation synchronizes with the `pop-front` operation that obtains `item`.
@@ -9869,8 +9869,8 @@ void run();
 1. Effects: Equivalent to:
 
     
-    while (auto* op = pop_front()) {
-      op->execute();
+    while (auto* op = pop-front()) {
+      op->execute();
     }
     
@@ -9887,7 +9887,7 @@ void finish(); 1. Effects: Changes state to finishing. -2. Synchronization: This operation synchronizes with all `pop_front` +2. Synchronization: This operation synchronizes with all `pop-front` operations on this object. ## Coroutine utilities [exec.coro.utils] ## {#spec-execution.coro_utils} @@ -9952,7 +9952,7 @@ void finish(); Let `rcvr` be an rvalue expression of type `awaitable-receiver`, let `crcvr` be a `const` - lvalue that refers to `rcvr`, let `vs` be a parameter pack of types + lvalue that refers to `rcvr`, let `vs` be a pack of types `Vs...`, and let `err` be an arbitrary expression of type `Err`. Then: