Init
This commit is contained in:
2142
cppdraft/exec/adapt.md
Normal file
2142
cppdraft/exec/adapt.md
Normal file
File diff suppressed because it is too large
Load Diff
81
cppdraft/exec/adapt/general.md
Normal file
81
cppdraft/exec/adapt/general.md
Normal file
@@ -0,0 +1,81 @@
|
||||
[exec.adapt.general]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#exec.adapt.general)
|
||||
|
||||
### 33.9.12 Sender adaptors [[exec.adapt]](exec.adapt#general)
|
||||
|
||||
#### 33.9.12.1 General [exec.adapt.general]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3002)
|
||||
|
||||
Subclause [[exec.adapt]](exec.adapt "33.9.12 Sender adaptors") specifies a set of sender adaptors[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3005)
|
||||
|
||||
The bitwise inclusive or operator is overloaded
|
||||
for the purpose of creating sender chains[.](#2.sentence-1)
|
||||
|
||||
The adaptors also support function call syntax with equivalent semantics[.](#2.sentence-2)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3010)
|
||||
|
||||
Unless otherwise specified:
|
||||
|
||||
- [(3.1)](#3.1)
|
||||
|
||||
A sender adaptor is prohibited from causing observable effects,
|
||||
apart from moving and copying its arguments,
|
||||
before the returned sender is connected with a receiver using connect,
|
||||
and start is called on the resulting operation state[.](#3.1.sentence-1)
|
||||
|
||||
- [(3.2)](#3.2)
|
||||
|
||||
A parent sender ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations")) with a single child sender sndr has
|
||||
an associated attribute object equal to*FWD-ENV*(get_env(sndr)) ([[exec.fwd.env]](exec.fwd.env "33.5.1 forwarding_query"))[.](#3.2.sentence-1)
|
||||
|
||||
- [(3.3)](#3.3)
|
||||
|
||||
A parent sender with more than one child sender has
|
||||
an associated attributes object equal to env<>{}[.](#3.3.sentence-1)
|
||||
|
||||
- [(3.4)](#3.4)
|
||||
|
||||
When a parent sender is connected to a receiver rcvr,
|
||||
any receiver used to connect a child sender has
|
||||
an associated environment equal to *FWD-ENV*(get_env(rcvr))[.](#3.4.sentence-1)
|
||||
|
||||
- [(3.5)](#3.5)
|
||||
|
||||
An adaptor whose child senders are all non-dependent ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations"))
|
||||
is itself non-dependent[.](#3.5.sentence-1)
|
||||
|
||||
- [(3.6)](#3.6)
|
||||
|
||||
These requirements apply to any function
|
||||
that is selected by the implementation of the sender adaptor[.](#3.6.sentence-1)
|
||||
|
||||
- [(3.7)](#3.7)
|
||||
|
||||
*Recommended practice*: Implementations should use
|
||||
the completion signatures of the adaptors
|
||||
to communicate type errors to users and
|
||||
to propagate any such type errors from child senders[.](#3.7.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3043)
|
||||
|
||||
If a sender returned from a sender adaptor specified in [[exec.adapt]](exec.adapt "33.9.12 Sender adaptors") is specified to include set_error_t(Err) among its set of completion signatures
|
||||
where decay_t<Err> denotes the type exception_ptr,
|
||||
but the implementation does not potentially evaluate
|
||||
an error completion operation with an exception_ptr argument,
|
||||
the implementation is allowed to omit
|
||||
the exception_ptr error completion signature from the set[.](#4.sentence-1)
|
||||
112
cppdraft/exec/adapt/obj.md
Normal file
112
cppdraft/exec/adapt/obj.md
Normal file
@@ -0,0 +1,112 @@
|
||||
[exec.adapt.obj]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#exec.adapt.obj)
|
||||
|
||||
### 33.9.12 Sender adaptors [[exec.adapt]](exec.adapt#obj)
|
||||
|
||||
#### 33.9.12.2 Closure objects [exec.adapt.obj]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3055)
|
||||
|
||||
A [*pipeable sender adaptor closure object*](#def:sender_adaptor_closure_object,pipeable "33.9.12.2 Closure objects [exec.adapt.obj]") is a function object
|
||||
that accepts one or more [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") arguments and returns a [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]")[.](#1.sentence-1)
|
||||
|
||||
For a pipeable sender adaptor closure object c and
|
||||
an expression sndr such that decltype((sndr)) models [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"),
|
||||
the following expressions are equivalent and yield a [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"):c(sndr) sndr | c
|
||||
|
||||
Given an additional pipeable sender adaptor closure object d,
|
||||
the expression c | d produces
|
||||
another pipeable sender adaptor closure object e:
|
||||
|
||||
e is a perfect forwarding call wrapper ([[func.require]](func.require "22.10.4 Requirements"))
|
||||
with the following properties:
|
||||
|
||||
- [(1.1)](#1.1)
|
||||
|
||||
Its target object is an object d2 of type decltype(auto(d)) direct-non-list-initialized with d[.](#1.1.sentence-1)
|
||||
|
||||
- [(1.2)](#1.2)
|
||||
|
||||
It has one bound argument entity,
|
||||
an object c2 of type decltype(auto(c)) direct-non-list-initialized with c[.](#1.2.sentence-1)
|
||||
|
||||
- [(1.3)](#1.3)
|
||||
|
||||
Its call pattern is d2(c2(arg)),
|
||||
where arg is the argument used in a function call expression of e[.](#1.3.sentence-1)
|
||||
|
||||
The expression c | d is well-formed if and only if
|
||||
the initializations of the state entities ([[func.def]](func.def "22.10.3 Definitions")) of e are all well-formed[.](#1.sentence-5)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3088)
|
||||
|
||||
An object t of type T is
|
||||
a pipeable sender adaptor closure object
|
||||
if T models [derived_from](concept.derived#concept:derived_from "18.4.3 Concept derived_from [concept.derived]")<sender_adaptor_closure<T>>,T has no other base classes
|
||||
of type sender_adaptor_closure<U> for any other type U, andT does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]")[.](#2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3096)
|
||||
|
||||
The template parameter D for sender_adaptor_closure can be
|
||||
an incomplete type[.](#3.sentence-1)
|
||||
|
||||
Before any expression of type cv D appears as
|
||||
an operand to the | operator,D shall be complete and
|
||||
model [derived_from](concept.derived#concept:derived_from "18.4.3 Concept derived_from [concept.derived]")<sender_adaptor_closure<D>>[.](#3.sentence-2)
|
||||
|
||||
The behavior of an expression involving an object of type cv D as an operand to the | operator is undefined
|
||||
if overload resolution selects a program-defined operator| function[.](#3.sentence-3)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3107)
|
||||
|
||||
A [*pipeable sender adaptor object*](#def:sender_adaptor_object,pipeable "33.9.12.2 Closure objects [exec.adapt.obj]") is a customization point object
|
||||
that accepts a [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") as its first argument and
|
||||
returns a [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]")[.](#4.sentence-1)
|
||||
|
||||
If a pipeable sender adaptor object accepts only one argument,
|
||||
then it is a pipeable sender adaptor closure object[.](#4.sentence-2)
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3114)
|
||||
|
||||
If a pipeable sender adaptor object adaptor accepts more than one argument,
|
||||
then let sndr be an expression
|
||||
such that decltype((sndr)) models [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"),
|
||||
let args... be arguments
|
||||
such that adaptor(sndr, args...) is a well-formed expression
|
||||
as specified below, and
|
||||
let BoundArgs be a pack that denotes decltype(auto(args))...[.](#5.sentence-1)
|
||||
|
||||
The expression adaptor(args...) produces
|
||||
a pipeable sender adaptor closure object f that is a perfect forwarding call wrapper with the following properties:
|
||||
|
||||
- [(5.1)](#5.1)
|
||||
|
||||
Its target object is a copy of adaptor[.](#5.1.sentence-1)
|
||||
|
||||
- [(5.2)](#5.2)
|
||||
|
||||
Its bound argument entities bound_args consist of
|
||||
objects of types BoundArgs... direct-non-list-initialized withstd::forward<decltype((args))>(args)..., respectively[.](#5.2.sentence-1)
|
||||
|
||||
- [(5.3)](#5.3)
|
||||
|
||||
Its call pattern is adaptor(rcvr, bound_args...),
|
||||
where rcvr is
|
||||
the argument used in a function call expression of f[.](#5.3.sentence-1)
|
||||
|
||||
The expression adaptor(args...) is well-formed if and only if
|
||||
the initializations of the bound argument entities of the result,
|
||||
as specified above, are all well-formed[.](#5.sentence-3)
|
||||
65
cppdraft/exec/affine/on.md
Normal file
65
cppdraft/exec/affine/on.md
Normal file
@@ -0,0 +1,65 @@
|
||||
[exec.affine.on]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.13 Coroutine utilities [[exec.coro.util]](exec.coro.util#exec.affine.on)
|
||||
|
||||
### 33.13.3 execution::affine_on [exec.affine.on]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6877)
|
||||
|
||||
affine_on adapts a sender into one that completes on
|
||||
the specified scheduler[.](#1.sentence-1)
|
||||
|
||||
If the algorithm determines that the adapted sender already completes
|
||||
on the correct scheduler it can avoid any scheduling operation[.](#1.sentence-2)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6883)
|
||||
|
||||
The name affine_on denotes a pipeable sender adaptor
|
||||
object[.](#2.sentence-1)
|
||||
|
||||
For subexpressions sch and sndr, if decltype((sch)) does not satisfy [scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]"), or decltype((sndr)) does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"), affine_on(sndr, sch) is ill-formed[.](#2.sentence-2)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6891)
|
||||
|
||||
Otherwise, the expression affine_on(sndr, sch) is
|
||||
expression-equivalent to:transform_sender(*get-domain-early*(sndr), *make-sender*(affine_on, sch, sndr)) except that sndr is evaluated only once[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6899)
|
||||
|
||||
The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
|
||||
is specialized for affine_on_t as follows:
|
||||
|
||||
namespace std::execution {template<>struct *impls-for*<affine_on_t> : *default-impls* {static constexpr auto *get-attrs* =[](const auto& data, const auto& child) noexcept -> decltype(auto) {return *JOIN-ENV*(*SCHED-ATTRS*(data), *FWD-ENV*(get_env(child))); }; };}
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6915)
|
||||
|
||||
Let *out_sndr* be a subexpression denoting a sender
|
||||
returned from affine_on(sndr, sch) or one equal to such,
|
||||
and let *OutSndr* be the type decltype((*out_sndr*))[.](#5.sentence-1)
|
||||
|
||||
Let *out_rcvr* be a subexpression denoting a receiver that
|
||||
has an environment of type Env such that [sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<*OutSndr*, Env> is true[.](#5.sentence-2)
|
||||
|
||||
Let *op* be an lvalue referring to the operation state that
|
||||
results from connecting *out_sndr* to *out_rcvr*[.](#5.sentence-3)
|
||||
|
||||
Calling start(*op*) will start sndr on the current
|
||||
execution agent and execute completion operations on *out_rcvr* on an execution agent of the execution resource associated withsch[.](#5.sentence-4)
|
||||
|
||||
If the current execution resource is the same as the execution
|
||||
resource associated with sch, the completion operation on*out_rcvr* may be called before start(*op*) completes[.](#5.sentence-5)
|
||||
|
||||
If scheduling onto sch fails, an error completion on*out_rcvr* shall be executed on an unspecified execution
|
||||
agent[.](#5.sentence-6)
|
||||
123
cppdraft/exec/as/awaitable.md
Normal file
123
cppdraft/exec/as/awaitable.md
Normal file
@@ -0,0 +1,123 @@
|
||||
[exec.as.awaitable]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.13 Coroutine utilities [[exec.coro.util]](exec.coro.util#exec.as.awaitable)
|
||||
|
||||
### 33.13.1 execution::as_awaitable [exec.as.awaitable]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6609)
|
||||
|
||||
as_awaitable transforms an object into one
|
||||
that is awaitable within a particular coroutine[.](#1.sentence-1)
|
||||
|
||||
Subclause [[exec.coro.util]](exec.coro.util "33.13 Coroutine utilities") makes use of
|
||||
the following exposition-only entities:namespace std::execution {template<class Sndr, class Promise>concept [*awaitable-sender*](#concept:awaitable-sender "33.13.1 execution::as_awaitable [exec.as.awaitable]") =[*single-sender*](execution.syn#concept:single-sender "33.4 Header <execution> synopsis [execution.syn]")<Sndr, env_of_t<Promise>> &&[sender_to](exec.snd.concepts#concept:sender_to "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr, *awaitable-receiver*> && // *see below*requires (Promise& p) {{ p.unhandled_stopped() } -> [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<coroutine_handle<>>; }; template<class Sndr>concept [*has-queryable-await-completion-adaptor*](#concept:has-queryable-await-completion-adaptor "33.13.1 execution::as_awaitable [exec.as.awaitable]") = // *exposition only*[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr> &&requires(Sndr&& sender) { get_await_completion_adaptor(get_env(sender)); }; template<class Sndr, class Promise>class *sender-awaitable*; // *exposition only*}
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6636)
|
||||
|
||||
The type *sender-awaitable*<Sndr, Promise> is equivalent to:
|
||||
|
||||
namespace std::execution {template<class Sndr, class Promise>class *sender-awaitable* {struct *unit* {}; // *exposition only*using *value-type* = // *exposition only**single-sender-value-type*<Sndr, env_of_t<Promise>>; using *result-type* = // *exposition only* conditional_t<is_void_v<*value-type*>, unit, *value-type*>; struct *awaitable-receiver*; // *exposition only* variant<monostate, *result-type*, exception_ptr> *result*{}; // *exposition only* connect_result_t<Sndr, *awaitable-receiver*> *state*; // *exposition only*public:*sender-awaitable*(Sndr&& sndr, Promise& p); static constexpr bool await_ready() noexcept { return false; }void await_suspend(coroutine_handle<Promise>) noexcept { start(*state*); }*value-type* await_resume(); };}
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6662)
|
||||
|
||||
*awaitable-receiver* is equivalent to:struct *awaitable-receiver* {using receiver_concept = receiver_t;
|
||||
variant<monostate, *result-type*, exception_ptr>* *result-ptr*; // *exposition only* coroutine_handle<Promise> *continuation*; // *exposition only*// *see below*};
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6673)
|
||||
|
||||
Let rcvr be an rvalue expression of type *awaitable-receiver*,
|
||||
let crcvr be a const lvalue that refers to rcvr,
|
||||
let vs be a pack of subexpressions, and
|
||||
let err be an expression of type Err[.](#4.sentence-1)
|
||||
|
||||
Then:
|
||||
|
||||
- [(4.1)](#4.1)
|
||||
|
||||
If [constructible_from](concept.constructible#concept:constructible_from "18.4.11 Concept constructible_from [concept.constructible]")<*result-type*, decltype((vs))...> is satisfied,
|
||||
the expression set_value(
|
||||
rcvr, vs...) is equivalent to:try { rcvr.*result-ptr*->template emplace<1>(vs...);} catch(...) { rcvr.*result-ptr*->template emplace<2>(current_exception());} rcvr.*continuation*.resume();
|
||||
Otherwise, set_value(rcvr, vs...) is ill-formed[.](#4.1.sentence-2)
|
||||
|
||||
- [(4.2)](#4.2)
|
||||
|
||||
The expression set_error(rcvr, err) is equivalent to:rcvr.*result-ptr*->template emplace<2>(*AS-EXCEPT-PTR*(err)); // see [[exec.general]](exec.general "33.1 General") rcvr.*continuation*.resume();
|
||||
|
||||
- [(4.3)](#4.3)
|
||||
|
||||
The expression set_stopped(rcvr) is equivalent to:static_cast<coroutine_handle<>>(rcvr.*continuation*.promise().unhandled_stopped()).resume();
|
||||
|
||||
- [(4.4)](#4.4)
|
||||
|
||||
For any expression tag whose type satisfies [*forwarding-query*](execution.syn#concept:forwarding-query "33.4 Header <execution> synopsis [execution.syn]") and
|
||||
for any pack of subexpressions as,get_env(crcvr).query(tag, as...) is expression-equivalent to:tag(get_env(as_const(crcvr.*continuation*.promise())), as...)
|
||||
|
||||
[ð](#itemdecl:1)
|
||||
|
||||
`sender-awaitable(Sndr&& sndr, Promise& p);
|
||||
`
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6718)
|
||||
|
||||
*Effects*: Initializes *state* withconnect(std::forward<Sndr>(sndr), *awaitable-receiver*{addressof(result), coroutine_handle<Promise>::from_promise(p)})
|
||||
|
||||
[ð](#itemdecl:2)
|
||||
|
||||
`value-type await_resume();
|
||||
`
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6732)
|
||||
|
||||
*Effects*: Equivalent to:if (*result*.index() == 2) rethrow_exception(get<2>(*result*));if constexpr (!is_void_v<*value-type*>)return std::forward<*value-type*>(get<1>(*result*));
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6743)
|
||||
|
||||
as_awaitable is a customization point object[.](#7.sentence-1)
|
||||
|
||||
For subexpressions expr and p where p is an lvalue,Expr names the type decltype((expr)) andPromise names the type decay_t<decltype((p))>,as_awaitable(expr, p) is expression-equivalent to,
|
||||
except that the evaluations of expr and p are indeterminately sequenced:
|
||||
|
||||
- [(7.1)](#7.1)
|
||||
|
||||
expr.as_awaitable(p) if that expression is well-formed[.](#7.1.sentence-1)
|
||||
*Mandates*: [*is-awaitable*](exec.awaitable#concept:is-awaitable "33.9.4 Awaitable helpers [exec.awaitable]")<A, Promise> is true,
|
||||
where A is the type of the expression above[.](#7.1.sentence-2)
|
||||
|
||||
- [(7.2)](#7.2)
|
||||
|
||||
Otherwise, (void(p), expr) if [*is-awaitable*](exec.awaitable#concept:is-awaitable "33.9.4 Awaitable helpers [exec.awaitable]")<Expr, U> is true,
|
||||
where U is an unspecified class type
|
||||
that is not Promise and
|
||||
that lacks a member named await_transform[.](#7.2.sentence-1)
|
||||
*Preconditions*: [*is-awaitable*](exec.awaitable#concept:is-awaitable "33.9.4 Awaitable helpers [exec.awaitable]")<Expr, Promise> is true and
|
||||
the expression co_await expr in a coroutine with promise type U is expression-equivalent to
|
||||
the same expression in a coroutine with promise type Promise[.](#7.2.sentence-2)
|
||||
|
||||
- [(7.3)](#7.3)
|
||||
|
||||
Otherwise, *sender-awaitable*{*adapted-expr*, p} if*has-queryable-await-completion-adaptor*<Expr> and*awaitable-sender*<decltype((*adapted-expr*)), Promise> are both satisfied, where *adapted-expr* isget_await_completion_adaptor(get_env(expr))(expr),
|
||||
except that expr is evaluated only once[.](#7.3.sentence-1)
|
||||
|
||||
- [(7.4)](#7.4)
|
||||
|
||||
Otherwise, *sender-awaitable*{expr, p} if [*awaitable-sender*](#concept:awaitable-sender "33.13.1 execution::as_awaitable [exec.as.awaitable]")<Expr, Promise> is true[.](#7.4.sentence-1)
|
||||
|
||||
- [(7.5)](#7.5)
|
||||
|
||||
Otherwise, (void(p), expr)[.](#7.5.sentence-1)
|
||||
167
cppdraft/exec/associate.md
Normal file
167
cppdraft/exec/associate.md
Normal file
@@ -0,0 +1,167 @@
|
||||
[exec.associate]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#exec.associate)
|
||||
|
||||
### 33.9.12 Sender adaptors [[exec.adapt]](exec.adapt#exec.associate)
|
||||
|
||||
#### 33.9.12.16 execution::associate [exec.associate]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4897)
|
||||
|
||||
associate tries to associate
|
||||
a sender with an async scope such that
|
||||
the scope can track the lifetime of any asynchronous operations
|
||||
created with the sender[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4903)
|
||||
|
||||
Let *associate-data* be the following exposition-only class template:
|
||||
|
||||
[ð](#lib:execution::associate-data)
|
||||
|
||||
namespace std::execution {template<[scope_token](exec.scope.concepts#concept:scope_token "33.14.1 Execution scope concepts [exec.scope.concepts]") Token, [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sender>struct *associate-data* { // *exposition only*using *wrap-sender* = // *exposition only* remove_cvref_t<decltype(declval<Token&>().wrap(declval<Sender>()))>; explicit *associate-data*(Token t, Sender&& s): *sndr*(t.wrap(std::forward<Sender>(s))), *token*(t) {if (!*token*.try_associate())*sndr*.reset(); }*associate-data*(const *associate-data*& other)noexcept(is_nothrow_copy_constructible_v<*wrap-sender*> &&noexcept(other.*token*.try_associate())); *associate-data*(*associate-data*&& other)noexcept(is_nothrow_move_constructible_v<*wrap-sender*>); ~*associate-data*();
|
||||
|
||||
optional<pair<Token, *wrap-sender*>> release() && noexcept(is_nothrow_move_constructible_v<*wrap-sender*>); private: optional<*wrap-sender*> *sndr*; // *exposition only* Token *token*; // *exposition only*}; template<[scope_token](exec.scope.concepts#concept:scope_token "33.14.1 Execution scope concepts [exec.scope.concepts]") Token, [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sender>*associate-data*(Token, Sender&&) -> *associate-data*<Token, Sender>;}
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4943)
|
||||
|
||||
For an *associate-data* object a,a.*sndr*.has_value() is true if and only if
|
||||
an association was successfully made and is owned by a[.](#3.sentence-1)
|
||||
|
||||
[ð](#lib:execution::associate-data,constructor)
|
||||
|
||||
`associate-data(const associate-data& other)
|
||||
noexcept(is_nothrow_copy_constructible_v<wrap-sender> &&
|
||||
noexcept(other.token.try_associate()));
|
||||
`
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4957)
|
||||
|
||||
*Constraints*: [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14 Concept copy_constructible [concept.copyconstructible]")<*wrap-sender*> is true[.](#4.sentence-1)
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4961)
|
||||
|
||||
*Effects*: Value-initializes *sndr* and
|
||||
initializes *token* with other.*token*[.](#5.sentence-1)
|
||||
|
||||
If other.*sndr*.has_value() is false,
|
||||
no further effects;
|
||||
otherwise,
|
||||
calls *token*.try_associate() and,
|
||||
if that returns true,
|
||||
calls *sndr*.emplace(*other.*sndr*) and,
|
||||
if that exits with an exception,
|
||||
calls *token*.disassociate() before propagating the exception[.](#5.sentence-2)
|
||||
|
||||
[ð](#lib:execution::associate-data,constructor_)
|
||||
|
||||
`associate-data(associate-data&& other)
|
||||
noexcept(is_nothrow_move_constructible_v<wrap-sender>);
|
||||
`
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4982)
|
||||
|
||||
*Effects*: Initializes *sndr* with std::move(other.*sndr*) and
|
||||
initializes *token* with std::move(other.*token*) and
|
||||
then calls other.*sndr*.reset()[.](#6.sentence-1)
|
||||
|
||||
[ð](#lib:execution::associate-data,destructor)
|
||||
|
||||
`~associate-data();
|
||||
`
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4995)
|
||||
|
||||
*Effects*: If *sndr*.has_value() returns false then no effect;
|
||||
otherwise, invokes *sndr*.reset() before invoking *token*.disassociate()[.](#7.sentence-1)
|
||||
|
||||
[ð](#lib:release,execution::associate-data)
|
||||
|
||||
`optional<pair<Token, wrap-sender>>
|
||||
release() && noexcept(is_nothrow_move_constructible_v<wrap-sender>);
|
||||
`
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5009)
|
||||
|
||||
*Effects*: If *sndr*.has_value() returns false then
|
||||
returns an optional that does not contain a value;
|
||||
otherwise returns an optional containing a value of type pair<Token, *wrap-sender*> as if by:return optional(pair(*token*, std::move(**sndr*)));
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5020)
|
||||
|
||||
*Postconditions*: *sndr* does not contain a value[.](#9.sentence-1)
|
||||
|
||||
[10](#10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5025)
|
||||
|
||||
The name associate denotes a pipeable sender adaptor object[.](#10.sentence-1)
|
||||
|
||||
For subexpressions sndr and token:
|
||||
|
||||
- [(10.1)](#10.1)
|
||||
|
||||
If decltype((sndr)) does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"), orremove_cvref_t<decltype((token))> does not satisfy [scope_token](exec.scope.concepts#concept:scope_token "33.14.1 Execution scope concepts [exec.scope.concepts]"), thenassociate(sndr, token) is ill-formed.
|
||||
|
||||
- [(10.2)](#10.2)
|
||||
|
||||
Otherwise,
|
||||
the expression associate(sndr, token) is expression-equivalent to:transform_sender(*get-domain-early*(sndr), *make-sender*(associate, *associate-data*(token, sndr))) except that sndr is evaluated only once.
|
||||
|
||||
[11](#11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5045)
|
||||
|
||||
The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
|
||||
is specialized for associate_t as follows:
|
||||
|
||||
[ð](#lib:execution::impls-for%3cassociate_t%3e)
|
||||
|
||||
namespace std::execution {template<>struct *impls-for*<associate_t> : *default-impls* {static constexpr auto *get-state* = *see below*; // *exposition only*static constexpr auto *start* = *see below*; // *exposition only*template<class Sndr, class... Env>static consteval void *check-types*() { // *exposition only*using associate_data_t = remove_cvref_t<*data-type*<Sndr>>; using child_type_t = typename associate_data_t::*wrap-sender*; (void)get_completion_signatures<child_type_t, *FWD-ENV-T*(Env)...>(); }};}
|
||||
|
||||
[12](#12)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5066)
|
||||
|
||||
The member *impls-for*<associate_t>::*get-state* is initialized with a callable object equivalent to the following lambda:
|
||||
|
||||
[]<class Sndr, class Rcvr>(Sndr&& sndr, Rcvr& rcvr) noexcept(*see below*) {auto [_, data] = std::forward<Sndr>(sndr); auto dataParts = std::move(data).release(); using scope_tkn = decltype(dataParts->first); using wrap_sender = decltype(dataParts->second); using op_t = connect_result_t<wrap_sender, Rcvr>; struct op_state {bool *associated* = false; // *exposition only*union { Rcvr* *rcvr*; // *exposition only*struct { scope_tkn *token*; // *exposition only* op_t *op*; // *exposition only*} *assoc*; // *exposition only*}; explicit op_state(Rcvr& r) noexcept: *rcvr*(addressof(r)) {}explicit op_state(scope_tkn tkn, wrap_sender&& sndr, Rcvr& r) try: *associated*(true), *assoc*(tkn, connect(std::move(sndr), std::move(r))) {}catch (...) { tkn.disassociate(); throw; } op_state(op_state&&) = delete; ~op_state() {if (*associated*) {*assoc*.*op*.~op_t(); *assoc*.*token*.disassociate(); *assoc*.*token*.~scope_tkn(); }}void *run*() noexcept { // *exposition only*if (*associated*) start(*assoc*.*op*); else set_stopped(std::move(**rcvr*)); }}; if (dataParts)return op_state{std::move(dataParts->first), std::move(dataParts->second), rcvr}; elsereturn op_state{rcvr};}
|
||||
|
||||
[13](#13)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5126)
|
||||
|
||||
The expression in the noexcept clause of*impls-for*<associate_t>::*get-state* isis_nothrow_constructible_v<remove_cvref_t<Sndr>, Sndr> && is_nothrow_move_constructible_v<*wrap-sender*> &&[*nothrow-callable*](functional.syn#concept:nothrow-callable "22.10.2 Header <functional> synopsis [functional.syn]")<connect_t, *wrap-sender*, Rcvr> where *wrap-sender* is the typeremove_cvref_t<*data-type*<Sndr>>::*wrap-sender*[.](#13.sentence-1)
|
||||
|
||||
[14](#14)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5137)
|
||||
|
||||
The member *impls-for*<associate_t>::*start* is initialized with a callable object equivalent to the following lambda:[](auto& state, auto&) noexcept -> void { state.*run*();}
|
||||
|
||||
[15](#15)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5146)
|
||||
|
||||
The evaluation of associate(sndr, token) may cause side effects observable
|
||||
via token's associated async scope object[.](#15.sentence-1)
|
||||
343
cppdraft/exec/async/ops.md
Normal file
343
cppdraft/exec/async/ops.md
Normal file
@@ -0,0 +1,343 @@
|
||||
[exec.async.ops]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.3 Asynchronous operations [exec.async.ops]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L172)
|
||||
|
||||
An [*execution resource*](#def:resource,execution "33.3 Asynchronous operations [exec.async.ops]") is a program entity that manages
|
||||
a (possibly dynamic) set of execution agents ([[thread.req.lockable.general]](thread.req.lockable.general "32.2.5.1 General")),
|
||||
which it uses to execute parallel work on behalf of callers[.](#1.sentence-1)
|
||||
|
||||
[*Example [1](#example-1)*:
|
||||
|
||||
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[.](#1.sentence-2)
|
||||
|
||||
â *end example*]
|
||||
|
||||
Execution resources execute asynchronous operations[.](#1.sentence-3)
|
||||
|
||||
An execution resource is either valid or invalid[.](#1.sentence-4)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L185)
|
||||
|
||||
An [*asynchronous operation*](#def:operation,asynchronous "33.3 Asynchronous operations [exec.async.ops]") is
|
||||
a distinct unit of program execution that
|
||||
|
||||
- [(2.1)](#2.1)
|
||||
|
||||
is explicitly created;
|
||||
|
||||
- [(2.2)](#2.2)
|
||||
|
||||
can be explicitly started once at most;
|
||||
|
||||
- [(2.3)](#2.3)
|
||||
|
||||
once started, eventually completes exactly once
|
||||
with a (possibly empty) set of result datums and
|
||||
in exactly one of three [*dispositions*](#def:disposition "33.3 Asynchronous operations [exec.async.ops]"):
|
||||
success, failure, or cancellation;
|
||||
* [(2.3.1)](#2.3.1)
|
||||
|
||||
A successful completion, also known as a [*value completion*](#def:completion,value "33.3 Asynchronous operations [exec.async.ops]"),
|
||||
can have an arbitrary number of result datums[.](#2.3.1.sentence-1)
|
||||
|
||||
* [(2.3.2)](#2.3.2)
|
||||
|
||||
A failure completion, also known as an [*error completion*](#def:completion,error "33.3 Asynchronous operations [exec.async.ops]"),
|
||||
has a single result datum[.](#2.3.2.sentence-1)
|
||||
|
||||
* [(2.3.3)](#2.3.3)
|
||||
|
||||
A cancellation completion, also known as a [*stopped completion*](#def:completion,stopped "33.3 Asynchronous operations [exec.async.ops]"),
|
||||
has no result datum[.](#2.3.3.sentence-1)
|
||||
|
||||
An asynchronous operation's [*async result*](#def:result,async "33.3 Asynchronous operations [exec.async.ops]") is its disposition and its (possibly empty) set of result datums[.](#2.3.sentence-2)
|
||||
|
||||
- [(2.4)](#2.4)
|
||||
|
||||
can complete on a different execution resource
|
||||
than the execution resource on which it started; and
|
||||
|
||||
- [(2.5)](#2.5)
|
||||
|
||||
can create and start other asynchronous operations
|
||||
called [*child operations*](#def:operations,child "33.3 Asynchronous operations [exec.async.ops]")[.](#2.5.sentence-1)
|
||||
A child operation is an asynchronous operation
|
||||
that is created by the parent operation and,
|
||||
if started, completes before the parent operation completes[.](#2.5.sentence-2)
|
||||
A [*parent operation*](#def:operation,parent "33.3 Asynchronous operations [exec.async.ops]") is the asynchronous operation
|
||||
that created a particular child operation[.](#2.5.sentence-3)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
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[.](#2.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L229)
|
||||
|
||||
An asynchronous operation has associated state
|
||||
known as its [*operation state*](#def:state,operation "33.3 Asynchronous operations [exec.async.ops]")[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L233)
|
||||
|
||||
An asynchronous operation has an associated environment[.](#4.sentence-1)
|
||||
|
||||
An [*environment*](#def:environment "33.3 Asynchronous operations [exec.async.ops]") is a queryable object ([[exec.queryable]](exec.queryable "33.2 Queries and queryables"))
|
||||
representing the execution-time properties of the operation's caller[.](#4.sentence-2)
|
||||
|
||||
The caller of an asynchronous operation is
|
||||
its parent operation or the function that created it[.](#4.sentence-3)
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L240)
|
||||
|
||||
An asynchronous operation has an associated receiver[.](#5.sentence-1)
|
||||
|
||||
A [*receiver*](#def:receiver "33.3 Asynchronous operations [exec.async.ops]") is an aggregation of three handlers
|
||||
for the three asynchronous completion dispositions:
|
||||
|
||||
- [(5.1)](#5.1)
|
||||
|
||||
a value completion handler for a value completion,
|
||||
|
||||
- [(5.2)](#5.2)
|
||||
|
||||
an error completion handler for an error completion, and
|
||||
|
||||
- [(5.3)](#5.3)
|
||||
|
||||
a stopped completion handler for a stopped completion[.](#5.sentence-2)
|
||||
|
||||
A receiver has an associated environment[.](#5.sentence-3)
|
||||
|
||||
An asynchronous operation's operation state owns the operation's receiver[.](#5.sentence-4)
|
||||
|
||||
The environment of an asynchronous operation
|
||||
is equal to its receiver's environment[.](#5.sentence-5)
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L254)
|
||||
|
||||
For each completion disposition, there is a [*completion function*](#def:function,completion "33.3 Asynchronous operations [exec.async.ops]")[.](#6.sentence-1)
|
||||
|
||||
A completion function is
|
||||
a customization point object ([[customization.point.object]](customization.point.object "16.3.3.3.5 Customization Point Object types"))
|
||||
that accepts an asynchronous operation's receiver as the first argument and
|
||||
the result datums of the asynchronous operation as additional arguments[.](#6.sentence-2)
|
||||
|
||||
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[.](#6.sentence-3)
|
||||
|
||||
A completion function has
|
||||
an associated type known as its [*completion tag*](#def:tag,completion "33.3 Asynchronous operations [exec.async.ops]") that is the unqualified type of the completion function[.](#6.sentence-4)
|
||||
|
||||
A valid invocation of a completion function is called
|
||||
a [*completion operation*](#def:operation,completion "33.3 Asynchronous operations [exec.async.ops]")[.](#6.sentence-5)
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L269)
|
||||
|
||||
The [*lifetime of an asynchronous operation*](#def:lifetime_of_an_asynchronous_operation "33.3 Asynchronous operations [exec.async.ops]"),
|
||||
also known as the operation's [*async lifetime*](#def:async_lifetime "33.3 Asynchronous operations [exec.async.ops]"),
|
||||
begins when its start operation begins executing and
|
||||
ends when its completion operation begins executing[.](#7.sentence-1)
|
||||
|
||||
If the lifetime of an asynchronous operation's associated operation state
|
||||
ends before the lifetime of the asynchronous operation,
|
||||
the behavior is undefined[.](#7.sentence-2)
|
||||
|
||||
After an asynchronous operation executes a completion operation,
|
||||
its associated operation state is invalid[.](#7.sentence-3)
|
||||
|
||||
Accessing any part of an invalid operation state is undefined behavior[.](#7.sentence-4)
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L281)
|
||||
|
||||
An asynchronous operation shall not execute a completion operation
|
||||
before its start operation has begun executing[.](#8.sentence-1)
|
||||
|
||||
After its start operation has begun executing,
|
||||
exactly one completion operation shall execute[.](#8.sentence-2)
|
||||
|
||||
The lifetime of an asynchronous operation's operation state can end
|
||||
during the execution of the completion operation[.](#8.sentence-3)
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L289)
|
||||
|
||||
A [*sender*](#def:sender "33.3 Asynchronous operations [exec.async.ops]") is a factory for one or more asynchronous operations[.](#9.sentence-1)
|
||||
|
||||
[*Connecting*](#def:connect "33.3 Asynchronous operations [exec.async.ops]") a sender and a receiver creates
|
||||
an asynchronous operation[.](#9.sentence-2)
|
||||
|
||||
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[.](#9.sentence-3)
|
||||
|
||||
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[.](#9.sentence-4)
|
||||
|
||||
A sender is started when it is connected to a receiver and
|
||||
the resulting asynchronous operation is started[.](#9.sentence-5)
|
||||
|
||||
A sender's async result is the async result of the asynchronous operation
|
||||
created by connecting it to a receiver[.](#9.sentence-6)
|
||||
|
||||
A sender sends its results by way of the asynchronous operation(s) it produces,
|
||||
and a receiver receives those results[.](#9.sentence-7)
|
||||
|
||||
A sender is either valid or invalid;
|
||||
it becomes invalid when its parent sender (see below) becomes invalid[.](#9.sentence-8)
|
||||
|
||||
[10](#10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L309)
|
||||
|
||||
A [*scheduler*](#def:scheduler "33.3 Asynchronous operations [exec.async.ops]") is an abstraction of an execution resource
|
||||
with a uniform, generic interface for scheduling work onto that resource[.](#10.sentence-1)
|
||||
|
||||
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[.](#10.sentence-2)
|
||||
|
||||
A [*schedule-expression*](#def:schedule-expression "33.3 Asynchronous operations [exec.async.ops]") obtains such a sender from a scheduler[.](#10.sentence-3)
|
||||
|
||||
A [*schedule sender*](#def:schedule_sender "33.3 Asynchronous operations [exec.async.ops]") is the result of a schedule expression[.](#10.sentence-4)
|
||||
|
||||
On success, an asynchronous operation produced by a schedule sender executes
|
||||
a value completion operation with an empty set of result datums[.](#10.sentence-5)
|
||||
|
||||
Multiple schedulers can refer to the same execution resource[.](#10.sentence-6)
|
||||
|
||||
A scheduler can be valid or invalid[.](#10.sentence-7)
|
||||
|
||||
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[.](#10.sentence-8)
|
||||
|
||||
[11](#11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L327)
|
||||
|
||||
An asynchronous operation has one or more associated completion schedulers
|
||||
for each of its possible dispositions[.](#11.sentence-1)
|
||||
|
||||
A [*completion scheduler*](#def:completion_scheduler "33.3 Asynchronous operations [exec.async.ops]") is a scheduler
|
||||
whose associated execution resource is used to execute
|
||||
a completion operation for an asynchronous operation[.](#11.sentence-2)
|
||||
|
||||
A value completion scheduler is a scheduler
|
||||
on which an asynchronous operation's value completion operation can execute[.](#11.sentence-3)
|
||||
|
||||
Likewise for error completion schedulers and stopped completion schedulers[.](#11.sentence-4)
|
||||
|
||||
[12](#12)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L337)
|
||||
|
||||
A sender has an associated queryable object ([[exec.queryable]](exec.queryable "33.2 Queries and queryables"))
|
||||
known as its [*attributes*](#def:attribute "33.3 Asynchronous operations [exec.async.ops]") that describes various characteristics of the sender and
|
||||
of the asynchronous operation(s) it produces[.](#12.sentence-1)
|
||||
|
||||
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[.](#12.sentence-2)
|
||||
|
||||
If a completion scheduler query is well-formed,
|
||||
the returned completion scheduler is unique
|
||||
for that disposition for any asynchronous operation the sender creates[.](#12.sentence-3)
|
||||
|
||||
A schedule sender is required to have a value completion scheduler attribute
|
||||
whose value is equal to the scheduler that produced the schedule sender[.](#12.sentence-4)
|
||||
|
||||
[13](#13)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L353)
|
||||
|
||||
A [*completion signature*](#def:completion_signature "33.3 Asynchronous operations [exec.async.ops]") is a function type
|
||||
that describes a completion operation[.](#13.sentence-1)
|
||||
|
||||
An asynchronous operation has a finite set of possible completion signatures
|
||||
corresponding to the completion operations
|
||||
that the asynchronous operation potentially evaluates ([[basic.def.odr]](basic.def.odr "6.3 One-definition rule"))[.](#13.sentence-2)
|
||||
|
||||
For a completion function set,
|
||||
receiver rcvr, and
|
||||
pack of arguments args,
|
||||
let c be the completion operation set(rcvr, args...), and
|
||||
let F be
|
||||
the function type decltype(auto(set))(decltype((args))...)[.](#13.sentence-3)
|
||||
|
||||
A completion signature Sig is associated with c if and only if*MATCHING-SIG*(Sig, F) is true ([[exec.general]](exec.general "33.1 General"))[.](#13.sentence-4)
|
||||
|
||||
Together, a sender type and an environment type 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 Env[.](#13.sentence-5)
|
||||
|
||||
The type of the receiver does not affect
|
||||
an asynchronous operation's completion signatures,
|
||||
only the type of the receiver's environment[.](#13.sentence-6)
|
||||
|
||||
A [*non-dependent sender*](#def:sender,non-dependent "33.3 Asynchronous operations [exec.async.ops]") is a sender type
|
||||
whose completion signatures are knowable
|
||||
independent of an execution environment[.](#13.sentence-7)
|
||||
|
||||
[14](#14)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L379)
|
||||
|
||||
A sender algorithm is a function that takes and/or returns a sender[.](#14.sentence-1)
|
||||
|
||||
There are three categories of sender algorithms:
|
||||
|
||||
- [(14.1)](#14.1)
|
||||
|
||||
A [*sender factory*](#def:sender_factory "33.3 Asynchronous operations [exec.async.ops]") is a function
|
||||
that takes non-senders as arguments and that returns a sender[.](#14.1.sentence-1)
|
||||
|
||||
- [(14.2)](#14.2)
|
||||
|
||||
A [*sender adaptor*](#def:sender_adaptor "33.3 Asynchronous operations [exec.async.ops]") 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[.](#14.2.sentence-1)
|
||||
An asynchronous operation created by a parent sender is
|
||||
a parent operation to the child operations created by the child senders[.](#14.2.sentence-2)
|
||||
|
||||
- [(14.3)](#14.3)
|
||||
|
||||
A [*sender consumer*](#def:sender_consumer "33.3 Asynchronous operations [exec.async.ops]") 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[.](#14.3.sentence-1)
|
||||
94
cppdraft/exec/awaitable.md
Normal file
94
cppdraft/exec/awaitable.md
Normal file
@@ -0,0 +1,94 @@
|
||||
[exec.awaitable]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#exec.awaitable)
|
||||
|
||||
### 33.9.4 Awaitable helpers [exec.awaitable]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2304)
|
||||
|
||||
The sender concepts recognize awaitables as senders[.](#1.sentence-1)
|
||||
|
||||
For [[exec]](exec "33 Execution control library"), an [*awaitable*](#def:awaitable "33.9.4 Awaitable helpers [exec.awaitable]") is an expression
|
||||
that would be well-formed as the operand of a co_await expression
|
||||
within a given context[.](#1.sentence-2)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2310)
|
||||
|
||||
For a subexpression c,
|
||||
let *GET-AWAITER*(c, p) be expression-equivalent to
|
||||
the series of transformations and conversions applied to c as the operand of an [*await-expression*](expr.await#nt:await-expression "7.6.2.4 Await [expr.await]") in a coroutine,
|
||||
resulting in lvalue e as described by [[expr.await]](expr.await "7.6.2.4 Await"),
|
||||
where p is an lvalue referring to the coroutine's promise,
|
||||
which has type Promise[.](#2.sentence-1)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
This includes the invocation of
|
||||
the promise type's await_transform member if any,
|
||||
the invocation of the operator co_await picked by overload resolution if any, and
|
||||
any necessary implicit conversions and materializations[.](#2.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
Let *GET-AWAITER*(c) be
|
||||
expression-equivalent to *GET-AWAITER*(c, q) where q is an lvalue of
|
||||
an unspecified empty class type *none-such* that
|
||||
lacks an await_transform member, and
|
||||
where coroutine_handle<*none-such*> behaves ascoroutine_handle<void>[.](#2.sentence-3)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2334)
|
||||
|
||||
Let [*is-awaitable*](#concept:is-awaitable "33.9.4 Awaitable helpers [exec.awaitable]") be the following exposition-only concept:namespace std {template<class T>concept [*await-suspend-result*](#concept:await-suspend-result "33.9.4 Awaitable helpers [exec.awaitable]") = *see below*; // *exposition only*template<class A, class... Promise>concept [*is-awaiter*](#concept:is-awaiter "33.9.4 Awaitable helpers [exec.awaitable]") = // *exposition only*requires (A& a, coroutine_handle<Promise...> h) { a.await_ready() ? 1 : 0; { a.await_suspend(h) } -> [*await-suspend-result*](#concept:await-suspend-result "33.9.4 Awaitable helpers [exec.awaitable]");
|
||||
a.await_resume(); }; template<class C, class... Promise>concept [*is-awaitable*](#concept:is-awaitable "33.9.4 Awaitable helpers [exec.awaitable]") = // *exposition only*requires (C (*fc)() noexcept, Promise&... p) {{ *GET-AWAITER*(fc(), p...) } -> [*is-awaiter*](#concept:is-awaiter "33.9.4 Awaitable helpers [exec.awaitable]")<Promise...>; };}
|
||||
|
||||
[*await-suspend-result*](#concept:await-suspend-result "33.9.4 Awaitable helpers [exec.awaitable]")<T> is true if and only if one of the following is true:
|
||||
|
||||
- [(3.1)](#3.1)
|
||||
|
||||
T is void, or
|
||||
|
||||
- [(3.2)](#3.2)
|
||||
|
||||
T is bool, or
|
||||
|
||||
- [(3.3)](#3.3)
|
||||
|
||||
T is a specialization of coroutine_handle[.](#3.sentence-2)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2365)
|
||||
|
||||
For a subexpression c such that decltype((c)) is type C, and
|
||||
an lvalue p of type Promise,*await-result-
|
||||
type*<C, Promise> denotes
|
||||
the type decltype(*GET-AWAITER*(c, p).await_resume()) and*await-result-type*<C> denotes
|
||||
the type decltype(*GET-AWAITER*(c).await_resume())[.](#4.sentence-1)
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2374)
|
||||
|
||||
Let *with-await-transform* be the exposition-only class template:namespace std::execution {template<class T, class Promise>concept [*has-as-awaitable*](#concept:has-as-awaitable "33.9.4 Awaitable helpers [exec.awaitable]") = // *exposition only*requires (T&& t, Promise& p) {{ std::forward<T>(t).as_awaitable(p) } -> [*is-awaitable*](#concept:is-awaitable "33.9.4 Awaitable helpers [exec.awaitable]")<Promise&>; }; template<class Derived>struct *with-await-transform* { // *exposition only*template<class T> T&& await_transform(T&& value) noexcept {return std::forward<T>(value); }template<[*has-as-awaitable*](#concept:has-as-awaitable "33.9.4 Awaitable helpers [exec.awaitable]")<Derived> T>auto await_transform(T&& value)noexcept(noexcept(std::forward<T>(value).as_awaitable(declval<Derived&>())))-> decltype(std::forward<T>(value).as_awaitable(declval<Derived&>())) {return std::forward<T>(value).as_awaitable(static_cast<Derived&>(*this)); }};}
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2401)
|
||||
|
||||
Let *env-promise* be the exposition-only class template:namespace std::execution {template<class Env>struct *env-promise* : *with-await-transform*<*env-promise*<Env>> { // *exposition only**unspecified* get_return_object() noexcept; *unspecified* initial_suspend() noexcept; *unspecified* final_suspend() noexcept; void unhandled_exception() noexcept; void return_void() noexcept;
|
||||
coroutine_handle<> unhandled_stopped() noexcept; const Env& get_env() const noexcept; };}
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
Specializations of *env-promise* are used only for the purpose of type computation;
|
||||
its members need not be defined[.](#6.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
222
cppdraft/exec/bulk.md
Normal file
222
cppdraft/exec/bulk.md
Normal file
@@ -0,0 +1,222 @@
|
||||
[exec.bulk]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#exec.bulk)
|
||||
|
||||
### 33.9.12 Sender adaptors [[exec.adapt]](exec.adapt#exec.bulk)
|
||||
|
||||
#### 33.9.12.11 execution::bulk, execution::bulk_chunked, and execution::bulk_unchunked [exec.bulk]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4109)
|
||||
|
||||
bulk, bulk_chunked, and bulk_unchunked run a task repeatedly for every index in an index space[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4113)
|
||||
|
||||
The names bulk, bulk_chunked, and bulk_unchunked denote pipeable sender adaptor objects[.](#2.sentence-1)
|
||||
|
||||
Let *bulk-algo* be eitherbulk, bulk_chunked, or bulk_unchunked[.](#2.sentence-2)
|
||||
|
||||
For subexpressions sndr, policy, shape, and f,
|
||||
letPolicy be remove_cvref_t<decltype(policy)>,Shape be decltype(auto(shape)), andFunc be decay_t<decltype((f))>[.](#2.sentence-3)
|
||||
|
||||
If
|
||||
|
||||
- [(2.1)](#2.1)
|
||||
|
||||
decltype((sndr)) does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"), or
|
||||
|
||||
- [(2.2)](#2.2)
|
||||
|
||||
is_execution_policy_v<Policy> is false, or
|
||||
|
||||
- [(2.3)](#2.3)
|
||||
|
||||
Shape does not satisfy [integral](concepts.arithmetic#concept:integral "18.4.7 Arithmetic concepts [concepts.arithmetic]"), or
|
||||
|
||||
- [(2.4)](#2.4)
|
||||
|
||||
Func does not model [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14 Concept copy_constructible [concept.copyconstructible]"),
|
||||
|
||||
*bulk-algo*(sndr, policy, shape, f) is ill-formed[.](#2.sentence-4)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4136)
|
||||
|
||||
Otherwise,
|
||||
the expression *bulk-algo*(sndr, policy, shape, f) is expression-equivalent to:
|
||||
|
||||
transform_sender(*get-domain-early*(sndr), *make-sender*(*bulk-algo*, *product-type*<*see below*, Shape, Func>{policy, shape, f}, sndr)) except that sndr is evaluated only once[.](#3.sentence-2)
|
||||
|
||||
The first template argument of *product-type* is Policy if Policy models [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14 Concept copy_constructible [concept.copyconstructible]"), andconst Policy& otherwise[.](#3.sentence-3)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4150)
|
||||
|
||||
Let sndr and env be subexpressions such thatSndr is decltype((sndr))[.](#4.sentence-1)
|
||||
|
||||
If [*sender-for*](exec.snd.concepts#concept:sender-for "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr, bulk_t> is false, then
|
||||
the expression bulk.transform_sender(sndr, env) is ill-formed;
|
||||
otherwise, it is equivalent to:auto [_, data, child] = sndr;auto& [policy, shape, f] = data;auto new_f = [func = std::move(f)](Shape begin, Shape end, auto&&... vs)noexcept(noexcept(f(begin, vs...))) {while (begin != end) func(begin++, vs...);}return bulk_chunked(std::move(child), policy, shape, std::move(new_f));
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
This causes the bulk(sndr, policy, shape, f) sender to be
|
||||
expressed in terms of bulk_chunked(sndr, policy, shape, f) when
|
||||
it is connected to a receiver whose
|
||||
execution domain does not customize bulk[.](#4.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4172)
|
||||
|
||||
The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
|
||||
is specialized for bulk_chunked_t as follows:
|
||||
|
||||
[ð](#lib:impls-for%3cbulk_chunked_t%3e)
|
||||
|
||||
namespace std::execution {template<>struct *impls-for*<bulk_chunked_t> : *default-impls* {static constexpr auto *complete* = *see below*; template<class Sndr, class... Env>static consteval void *check-types*(); };}
|
||||
|
||||
The member *impls-for*<bulk_chunked_t>::*complete* is initialized with a callable object equivalent to the following lambda:[]<class Index, class State, class Rcvr, class Tag, class... Args>(Index, State& state, Rcvr& rcvr, Tag, Args&&... args) noexcept-> void requires *see below* {if constexpr ([same_as](concept.same#concept:same_as "18.4.2 Concept same_as [concept.same]")<Tag, set_value_t>) {auto& [policy, shape, f] = state; constexpr bool nothrow = noexcept(f(auto(shape), auto(shape), args...)); *TRY-EVAL*(rcvr, [&]() noexcept(nothrow) { f(static_cast<decltype(auto(shape))>(0), auto(shape), args...);
|
||||
Tag()(std::move(rcvr), std::forward<Args>(args)...); }()); } else { Tag()(std::move(rcvr), std::forward<Args>(args)...); }}
|
||||
|
||||
The expression in the [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]") of the lambda above istrue if and only
|
||||
if Tag denotes a type other than set_value_t or
|
||||
if the expression f(auto(shape), auto(shape), args...) is well-formed[.](#5.sentence-3)
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4210)
|
||||
|
||||
The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
|
||||
is specialized for bulk_unchunked_t as follows:namespace std::execution {template<>struct *impls-for*<bulk_unchunked_t> : *default-impls* {static constexpr auto *complete* = *see below*; };}
|
||||
|
||||
The member *impls-for*<bulk_unchunked_t>::*complete* is initialized with a callable object equivalent to the following lambda:[]<class Index, class State, class Rcvr, class Tag, class... Args>(Index, State& state, Rcvr& rcvr, Tag, Args&&... args) noexcept-> void requires *see below* {if constexpr ([same_as](concept.same#concept:same_as "18.4.2 Concept same_as [concept.same]")<Tag, set_value_t>) {auto& [shape, f] = state; constexpr bool nothrow = noexcept(f(auto(shape), args...)); *TRY-EVAL*(rcvr, [&]() noexcept(nothrow) {for (decltype(auto(shape)) i = 0; i < shape; ++i) { f(auto(i), args...); } Tag()(std::move(rcvr), std::forward<Args>(args)...); }()); } else { Tag()(std::move(rcvr), std::forward<Args>(args)...); }}
|
||||
|
||||
The expression in the [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]") of the lambda above
|
||||
is true if and only
|
||||
if Tag denotes a type other than set_value_t or
|
||||
if the expression f(auto(shape), args...) is well-formed[.](#6.sentence-3)
|
||||
|
||||
[ð](#lib:check-types,impls-for%3cbulk_t%3e)
|
||||
|
||||
`template<class Sndr, class... Env>
|
||||
static consteval void check-types();
|
||||
`
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4253)
|
||||
|
||||
*Effects*: Equivalent to:auto cs = get_completion_signatures<*child-type*<Sndr>, *FWD-ENV-T*(Env)...>();auto fn = []<class... Ts>(set_value_t(*)(Ts...)) {if constexpr (<remove_cvref_t<*data-type*<Sndr>>, Ts&...>)throw *unspecified-exception*();};
|
||||
cs.*for-each*(*overload-set*(fn, [](auto){})); where *unspecified-exception* is
|
||||
a type derived from exception[.](#7.sentence-1)
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4268)
|
||||
|
||||
Let the subexpression out_sndr denote
|
||||
the result of the invocation*bulk-algo*(sndr, policy, shape, f) or
|
||||
an object equal to such, and
|
||||
let the subexpression rcvr denote a receiver
|
||||
such that the expression connect(out_sndr, rcvr) is well-formed[.](#8.sentence-1)
|
||||
|
||||
The expression connect(out_sndr, rcvr) has undefined behavior
|
||||
unless it creates an asynchronous operation ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations")) that,
|
||||
when started:
|
||||
|
||||
- [(8.1)](#8.1)
|
||||
|
||||
If sndr has a successful completion, whereargs is a pack of lvalue subexpressions
|
||||
referring to the value completion result datums of sndr, or
|
||||
decayed copies of those values if they model [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14 Concept copy_constructible [concept.copyconstructible]"),
|
||||
then:
|
||||
|
||||
* [(8.1.1)](#8.1.1)
|
||||
|
||||
If out_sndr also completes successfully, then:
|
||||
|
||||
+
|
||||
[(8.1.1.1)](#8.1.1.1)
|
||||
for bulk,
|
||||
invokes f(i, args...) for every i of type Shape from 0 to shape;
|
||||
|
||||
+
|
||||
[(8.1.1.2)](#8.1.1.2)
|
||||
for bulk_unchunked,
|
||||
invokes f(i, args...) for every i of type Shape from 0 to shape;
|
||||
*Recommended practice*: The underlying scheduler should execute each iteration
|
||||
on a distinct execution agent[.](#8.1.1.2.sentence-2)
|
||||
|
||||
+
|
||||
[(8.1.1.3)](#8.1.1.3)
|
||||
for bulk_chunked,
|
||||
invokes f(b, e, args...) zero or more times
|
||||
with pairs of b and e of type Shape in range [0, shape],
|
||||
such that b<e and
|
||||
for every i of type Shape from 0 to shape,
|
||||
there is exactly one invocation with a pair b and e,
|
||||
such that i is in the range [b, e)[.](#8.1.1.3.sentence-1)
|
||||
|
||||
* [(8.1.2)](#8.1.2)
|
||||
|
||||
If out_sndr completes with set_error(rcvr, eptr), then
|
||||
the asynchronous operation may invoke a subset of
|
||||
the invocations of f before the error completion handler is called, and eptr is an exception_ptr containing either:
|
||||
+
|
||||
[(8.1.2.1)](#8.1.2.1)
|
||||
an exception thrown by an invocation of f, or
|
||||
|
||||
+
|
||||
[(8.1.2.2)](#8.1.2.2)
|
||||
a bad_alloc exception if
|
||||
the implementation fails to allocate required resources, or
|
||||
|
||||
+
|
||||
[(8.1.2.3)](#8.1.2.3)
|
||||
an exception derived from runtime_error[.](#8.1.2.sentence-1)
|
||||
|
||||
* [(8.1.3)](#8.1.3)
|
||||
|
||||
If out_sndr completes with set_stopped(rcvr), then
|
||||
the asynchronous operation may invoke a subset of
|
||||
the invocations of f before the stopped completion handler[.](#8.1.3.sentence-1)
|
||||
|
||||
- [(8.2)](#8.2)
|
||||
|
||||
If sndr does not complete with set_value, then
|
||||
the completion is forwarded to recv[.](#8.2.sentence-1)
|
||||
|
||||
- [(8.3)](#8.3)
|
||||
|
||||
For *bulk-algo*,
|
||||
the parameter policy describes
|
||||
the manner in which
|
||||
the execution of the asynchronous operations corresponding to these algorithms
|
||||
may be parallelized and
|
||||
the manner in which
|
||||
they apply f[.](#8.3.sentence-1)
|
||||
Permissions and requirements
|
||||
on parallel algorithm element access functions ([[algorithms.parallel.exec]](algorithms.parallel.exec "26.3.3 Effect of execution policies on algorithm execution"))
|
||||
apply to f[.](#8.3.sentence-2)
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4358)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
The asynchronous operation corresponding to*bulk-algo*(sndr, policy, shape, f) can complete with set_stopped if cancellation is requested or
|
||||
ignore cancellation requests[.](#9.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
128
cppdraft/exec/cmplsig.md
Normal file
128
cppdraft/exec/cmplsig.md
Normal file
@@ -0,0 +1,128 @@
|
||||
[exec.cmplsig]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.10 Completion signatures [exec.cmplsig]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6027)
|
||||
|
||||
completion_signatures is a type
|
||||
that encodes a set of completion signatures ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations"))[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6031)
|
||||
|
||||
[*Example [1](#example-1)*: struct my_sender {using sender_concept = sender_t; using completion_signatures = execution::completion_signatures< set_value_t(),
|
||||
set_value_t(int, float),
|
||||
set_error_t(exception_ptr),
|
||||
set_error_t(error_code),
|
||||
set_stopped_t()>;};
|
||||
|
||||
Declares my_sender to be a sender
|
||||
that can complete by calling one of the following
|
||||
for a receiver expression rcvr:
|
||||
|
||||
- [(2.1)](#2.1)
|
||||
|
||||
set_value(rcvr)
|
||||
|
||||
- [(2.2)](#2.2)
|
||||
|
||||
set_value(rcvr, int{...}, float{...})
|
||||
|
||||
- [(2.3)](#2.3)
|
||||
|
||||
set_error(rcvr, exception_ptr{...})
|
||||
|
||||
- [(2.4)](#2.4)
|
||||
|
||||
set_error(rcvr, error_code{...})
|
||||
|
||||
- [(2.5)](#2.5)
|
||||
|
||||
set_stopped(rcvr)
|
||||
|
||||
â *end example*]
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6057)
|
||||
|
||||
This subclause makes use of the following exposition-only entities:template<class Fn>concept [*completion-signature*](#concept:completion-signature "33.10 Completion signatures [exec.cmplsig]") = *see below*;
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6064)
|
||||
|
||||
A type Fn satisfies [*completion-signature*](#concept:completion-signature "33.10 Completion signatures [exec.cmplsig]") if and only if it is a function type with one of the following forms:
|
||||
|
||||
- [(4.1)](#4.1)
|
||||
|
||||
set_value_t(Vs...),
|
||||
where Vs is a pack of object or reference types[.](#4.1.sentence-1)
|
||||
|
||||
- [(4.2)](#4.2)
|
||||
|
||||
set_error_t(Err),
|
||||
where Err is an object or reference type[.](#4.2.sentence-1)
|
||||
|
||||
- [(4.3)](#4.3)
|
||||
|
||||
set_stopped_t()
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6078)
|
||||
|
||||
template<bool>struct *indirect-meta-apply* {template<template<class...> class T, class... As>using *meta-apply* = T<As...>; // *exposition only*};
|
||||
|
||||
template<class...>concept [*always-true*](#concept:always-true "33.10 Completion signatures [exec.cmplsig]") = true; // *exposition only*template<class Tag, [*valid-completion-signatures*](execution.syn#concept:valid-completion-signatures "33.4 Header <execution> synopsis [execution.syn]") Completions, template<class...> class Tuple, template<class...> class Variant>using *gather-signatures* = *see below*;
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6096)
|
||||
|
||||
Let Fns be a pack of the arguments of
|
||||
the completion_signatures specialization named by Completions,
|
||||
let TagFns be a pack of the function types in Fns whose return types are Tag, and
|
||||
let Tsn be a pack of the function argument types
|
||||
in the n-th type in TagFns[.](#6.sentence-1)
|
||||
|
||||
Then, given two variadic templates Tuple and Variant,
|
||||
the type *gather-signatures*<Tag, Completions, Tuple, Variant> names the type*META-APPLY*(Variant, *META-APPLY*(Tuple, Ts0...), *META-APPLY*(Tuple, Ts1...),
|
||||
…, *META-APPLY*(Tuple, Tsmâ1...)) where m is the size of the pack TagFns andMETA-APPLY(T, As...) is equivalent to:typename *indirect-meta-apply*<*always-true*<As...>>::template *meta-apply*<T, As...>
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6118)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
The purpose of *META-APPLY* is to make it valid
|
||||
to use non-variadic templates as Variant and Tuple arguments
|
||||
to *gather-signatures*[.](#7.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6125)
|
||||
|
||||
[ð](#lib:execution::completion_signatures)
|
||||
|
||||
namespace std::execution {template<[*completion-signature*](#concept:completion-signature "33.10 Completion signatures [exec.cmplsig]")... Fns>struct completion_signatures {template<class Tag>static constexpr size_t *count-of*(Tag) { return *see below*; }template<class Fn>static constexpr void *for-each*(Fn&& fn) { // *exposition only*(std::forward<Fn>(fn)(static_cast<Fns*>(nullptr)), ...); }}; template<class Sndr, class Env = env<>, template<class...> class Tuple = *decayed-tuple*, template<class...> class Variant = *variant-or-empty*>requires [sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr, Env>using value_types_of_t =*gather-signatures*<set_value_t, completion_signatures_of_t<Sndr, Env>, Tuple, Variant>; template<class Sndr, class Env = env<>, template<class...> class Variant = *variant-or-empty*>requires [sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr, Env>using error_types_of_t =*gather-signatures*<set_error_t, completion_signatures_of_t<Sndr, Env>,
|
||||
type_identity_t, Variant>; template<class Sndr, class Env = env<>>requires [sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr, Env>constexpr bool sends_stopped =<*type-list*<>, *gather-signatures*<set_stopped_t, completion_signatures_of_t<Sndr, Env>, *type-list*, *type-list*>>;}
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6165)
|
||||
|
||||
For a subexpression tag,
|
||||
let Tag be the decayed type of tag[.](#9.sentence-1)
|
||||
|
||||
completion_signatures<Fns...>::*count-of*(
|
||||
tag) returns the count of function types in Fns... that
|
||||
are of the form Tag(Ts...) where Ts is a pack of types[.](#9.sentence-2)
|
||||
73
cppdraft/exec/connect.md
Normal file
73
cppdraft/exec/connect.md
Normal file
@@ -0,0 +1,73 @@
|
||||
[exec.connect]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#exec.connect)
|
||||
|
||||
### 33.9.10 execution::connect [exec.connect]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2734)
|
||||
|
||||
connect connects ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations")) a sender with a receiver[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2737)
|
||||
|
||||
The name connect denotes a customization point object[.](#2.sentence-1)
|
||||
|
||||
For subexpressions sndr and rcvr,
|
||||
let Sndr be decltype((sndr)) andRcvr be decltype((rcvr)),
|
||||
let new_sndr be the expressiontransform_sender(decltype(*get-domain-late*(sndr, get_env(rcvr))){}, sndr, get_env(rcvr)) and let DS and DR bedecay_t<decltype((new_sndr))> and decay_t<Rcvr>, respectively[.](#2.sentence-2)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2749)
|
||||
|
||||
Let *connect-awaitable-promise* be the following exposition-only class:
|
||||
|
||||
namespace std::execution {struct *connect-awaitable-promise* : *with-await-transform*<*connect-awaitable-promise*> {*connect-awaitable-promise*(DS&, DR& rcvr) noexcept : *rcvr*(rcvr) {} suspend_always initial_suspend() noexcept { return {}; }[[noreturn]] suspend_always final_suspend() noexcept { terminate(); }[[noreturn]] void unhandled_exception() noexcept { terminate(); }[[noreturn]] void return_void() noexcept { terminate(); } coroutine_handle<> unhandled_stopped() noexcept { set_stopped(std::move(*rcvr*)); return noop_coroutine(); }*operation-state-task* get_return_object() noexcept {return *operation-state-task*{ coroutine_handle<*connect-awaitable-promise*>::from_promise(*this)}; } env_of_t<DR> get_env() const noexcept {return execution::get_env(*rcvr*); }private: DR& *rcvr*; // *exposition only*};}
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2783)
|
||||
|
||||
Let *operation-state-task* be the following exposition-only class:namespace std::execution {struct *operation-state-task* { // *exposition only*using operation_state_concept = operation_state_t; using promise_type = *connect-awaitable-promise*; explicit *operation-state-task*(coroutine_handle<> h) noexcept : coro(h) {}*operation-state-task*(*operation-state-task*&&) = delete; ~*operation-state-task*() { *coro*.destroy(); }void start() & noexcept {*coro*.resume(); }private: coroutine_handle<> *coro*; // *exposition only*};}
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2805)
|
||||
|
||||
Let V name the type*await-result-type*<DS, *connect-awaitable-promise*>,
|
||||
let Sigs name the typecompletion_signatures<*SET-VALUE-SIG*(V), // see [[exec.snd.concepts]](exec.snd.concepts "33.9.3 Sender concepts") set_error_t(exception_ptr),
|
||||
set_stopped_t()> and let *connect-awaitable* be an exposition-only coroutine
|
||||
defined as follows:namespace std::execution {template<class Fun, class... Ts>auto *suspend-complete*(Fun fun, Ts&&... as) noexcept { // *exposition only*auto fn = [&, fun]() noexcept { fun(std::forward<Ts>(as)...); }; struct awaiter {decltype(fn) *fn*; // *exposition only*static constexpr bool await_ready() noexcept { return false; }void await_suspend(coroutine_handle<>) noexcept { *fn*(); }[[noreturn]] void await_resume() noexcept { unreachable(); }}; return awaiter{fn}; }*operation-state-task* *connect-awaitable*(DS sndr, DR rcvr) requires [receiver_of](exec.recv.concepts#concept:receiver_of "33.7.1 Receiver concepts [exec.recv.concepts]")<DR, Sigs> { exception_ptr ep; try {if constexpr ([same_as](concept.same#concept:same_as "18.4.2 Concept same_as [concept.same]")<V, void>) {co_await std::move(sndr); co_await *suspend-complete*(set_value, std::move(rcvr)); } else {co_await *suspend-complete*(set_value, std::move(rcvr), co_await std::move(sndr)); }} catch(...) { ep = current_exception(); }co_await *suspend-complete*(set_error, std::move(rcvr), std::move(ep)); }}
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2850)
|
||||
|
||||
The expression connect(sndr, rcvr) is expression-equivalent to:
|
||||
|
||||
- [(6.1)](#6.1)
|
||||
|
||||
new_sndr.connect(rcvr) if that expression is well-formed[.](#6.1.sentence-1)
|
||||
*Mandates*: The type of the expression above satisfies [operation_state](exec.opstate.general#concept:operation_state "33.8.1 General [exec.opstate.general]")[.](#6.1.sentence-2)
|
||||
|
||||
- [(6.2)](#6.2)
|
||||
|
||||
Otherwise, *connect-awaitable*(new_sndr, rcvr)[.](#6.2.sentence-1)
|
||||
|
||||
Except that rcvr is evaluated only once[.](#6.sentence-2)
|
||||
|
||||
*Mandates*: The following are true:
|
||||
|
||||
- [(6.3)](#6.3)
|
||||
|
||||
[sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr, env_of_t<Rcvr>>
|
||||
|
||||
- [(6.4)](#6.4)
|
||||
|
||||
[receiver_of](exec.recv.concepts#concept:receiver_of "33.7.1 Receiver concepts [exec.recv.concepts]")<Rcvr, completion_signatures_of_t<Sndr, env_of_t<Rcvr>>>
|
||||
368
cppdraft/exec/consumers.md
Normal file
368
cppdraft/exec/consumers.md
Normal file
@@ -0,0 +1,368 @@
|
||||
[exec.consumers]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#exec.consumers)
|
||||
|
||||
### 33.9.13 Sender consumers [exec.consumers]
|
||||
|
||||
#### [33.9.13.1](#exec.sync.wait) this_thread::sync_wait [[exec.sync.wait]](exec.sync.wait)
|
||||
|
||||
[1](#exec.sync.wait-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5595)
|
||||
|
||||
this_thread::sync_wait and this_thread::sync_wait_with_variant are used
|
||||
to block the current thread of execution
|
||||
until the specified sender completes and
|
||||
to return its async result[.](#exec.sync.wait-1.sentence-1)
|
||||
|
||||
sync_wait mandates
|
||||
that the input sender has exactly one value completion signature[.](#exec.sync.wait-1.sentence-2)
|
||||
|
||||
[2](#exec.sync.wait-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5604)
|
||||
|
||||
Let *sync-wait-env* be the following exposition-only class type:namespace std::this_thread {struct *sync-wait-env* { execution::run_loop* *loop*; // *exposition only*auto query(execution::get_scheduler_t) const noexcept {return *loop*->get_scheduler(); }auto query(execution::get_delegation_scheduler_t) const noexcept {return *loop*->get_scheduler(); }};}
|
||||
|
||||
[3](#exec.sync.wait-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5622)
|
||||
|
||||
Let *sync-wait-result-type* and*sync-wait-with-variant-result-type* be exposition-only alias templates defined as follows:namespace std::this_thread {template<execution::[sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<*sync-wait-env*> Sndr>using *sync-wait-result-type* = optional<execution::value_types_of_t<Sndr, *sync-wait-env*, *decayed-tuple*,
|
||||
type_identity_t>>; template<execution::[sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<*sync-wait-env*> Sndr>using *sync-wait-with-variant-result-type* = optional<execution::value_types_of_t<Sndr, *sync-wait-env*>>;}
|
||||
|
||||
[4](#exec.sync.wait-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5639)
|
||||
|
||||
The name this_thread::sync_wait denotes a customization point object[.](#exec.sync.wait-4.sentence-1)
|
||||
|
||||
For a subexpression sndr, let Sndr be decltype((sndr))[.](#exec.sync.wait-4.sentence-2)
|
||||
|
||||
The expression this_thread::sync_wait(sndr) is expression-equivalent to the following,
|
||||
except that sndr is evaluated only once:apply_sender(*get-domain-early*(sndr), sync_wait, sndr)*Mandates*:
|
||||
|
||||
- [(4.1)](#exec.sync.wait-4.1)
|
||||
|
||||
[sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr, *sync-wait-env*> is true[.](#exec.sync.wait-4.1.sentence-1)
|
||||
|
||||
- [(4.2)](#exec.sync.wait-4.2)
|
||||
|
||||
The type *sync-wait-result-type*<Sndr> is well-formed[.](#exec.sync.wait-4.2.sentence-1)
|
||||
|
||||
- [(4.3)](#exec.sync.wait-4.3)
|
||||
|
||||
[same_as](concept.same#concept:same_as "18.4.2 Concept same_as [concept.same]")<decltype(e), *sync-wait-result-type*<Sndr>> is true, where e is the apply_sender expression above[.](#exec.sync.wait-4.3.sentence-1)
|
||||
|
||||
[5](#exec.sync.wait-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5659)
|
||||
|
||||
Let *sync-wait-state* and *sync-wait-receiver* be the following exposition-only class templates:namespace std::this_thread {template<class Sndr>struct *sync-wait-state* { // *exposition only* execution::run_loop *loop*; // *exposition only* exception_ptr *error*; // *exposition only**sync-wait-result-type*<Sndr> *result*; // *exposition only*}; template<class Sndr>struct *sync-wait-receiver* { // *exposition only*using receiver_concept = execution::receiver_t; *sync-wait-state*<Sndr>* *state*; // *exposition only*template<class... Args>void set_value(Args&&... args) && noexcept; template<class Error>void set_error(Error&& err) && noexcept; void set_stopped() && noexcept; *sync-wait-env* get_env() const noexcept { return {&*state*->*loop*}; }};}
|
||||
|
||||
[ð](#exec.sync.wait-itemdecl:1)
|
||||
|
||||
`template<class... Args>
|
||||
void set_value(Args&&... args) && noexcept;
|
||||
`
|
||||
|
||||
[6](#exec.sync.wait-6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5695)
|
||||
|
||||
*Effects*: Equivalent to:try {*state*->*result*.emplace(std::forward<Args>(args)...);} catch (...) {*state*->*error* = current_exception();}*state*->*loop*.finish();
|
||||
|
||||
[ð](#exec.sync.wait-itemdecl:2)
|
||||
|
||||
`template<class Error>
|
||||
void set_error(Error&& err) && noexcept;
|
||||
`
|
||||
|
||||
[7](#exec.sync.wait-7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5714)
|
||||
|
||||
*Effects*: Equivalent to:*state*->*error* = *AS-EXCEPT-PTR*(std::forward<Error>(err)); // see [[exec.general]](exec.general "33.1 General")*state*->*loop*.finish();
|
||||
|
||||
[ð](#exec.sync.wait-itemdecl:3)
|
||||
|
||||
`void set_stopped() && noexcept;
|
||||
`
|
||||
|
||||
[8](#exec.sync.wait-8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5728)
|
||||
|
||||
*Effects*: Equivalent to *state*->*loop*.finish()[.](#exec.sync.wait-8.sentence-1)
|
||||
|
||||
[9](#exec.sync.wait-9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5733)
|
||||
|
||||
For a subexpression sndr, let Sndr be decltype((sndr))[.](#exec.sync.wait-9.sentence-1)
|
||||
|
||||
If [sender_to](exec.snd.concepts#concept:sender_to "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr, *sync-wait-receiver*<Sndr>> is false,
|
||||
the expression sync_wait.apply_sender(sndr) is ill-formed;
|
||||
otherwise, it is equivalent to:*sync-wait-state*<Sndr> state;auto op = connect(sndr, *sync-wait-receiver*<Sndr>{&state});
|
||||
start(op);
|
||||
|
||||
state.*loop*.run();if (state.*error*) { rethrow_exception(std::move(state.*error*));}return std::move(state.*result*);
|
||||
|
||||
[10](#exec.sync.wait-10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5751)
|
||||
|
||||
The behavior of this_thread::sync_wait(sndr) is undefined unless:
|
||||
|
||||
- [(10.1)](#exec.sync.wait-10.1)
|
||||
|
||||
It blocks the current thread of execution ([[defns.block]](defns.block "3.6 block"))
|
||||
with forward progress guarantee delegation ([[intro.progress]](intro.progress "6.10.2.3 Forward progress"))
|
||||
until the specified sender completes[.](#exec.sync.wait-10.1.sentence-1)
|
||||
[*Note [1](#exec.sync.wait-note-1)*:
|
||||
The default implementation of sync_wait achieves
|
||||
forward progress guarantee delegation by providing a run_loop scheduler
|
||||
via the get_delegation_scheduler query
|
||||
on the *sync-wait-receiver*'s environment[.](#exec.sync.wait-10.1.sentence-2)
|
||||
The run_loop is driven by the current thread of execution[.](#exec.sync.wait-10.1.sentence-3)
|
||||
â *end note*]
|
||||
|
||||
- [(10.2)](#exec.sync.wait-10.2)
|
||||
|
||||
It returns the specified sender's async results as follows:
|
||||
* [(10.2.1)](#exec.sync.wait-10.2.1)
|
||||
|
||||
For a value completion,
|
||||
the result datums are returned in
|
||||
a tuple in an engaged optional object[.](#exec.sync.wait-10.2.1.sentence-1)
|
||||
|
||||
* [(10.2.2)](#exec.sync.wait-10.2.2)
|
||||
|
||||
For an error completion, an exception is thrown[.](#exec.sync.wait-10.2.2.sentence-1)
|
||||
|
||||
* [(10.2.3)](#exec.sync.wait-10.2.3)
|
||||
|
||||
For a stopped completion, a disengaged optional object is returned[.](#exec.sync.wait-10.2.3.sentence-1)
|
||||
|
||||
#### [33.9.13.2](#exec.sync.wait.var) this_thread::sync_wait_with_variant [[exec.sync.wait.var]](exec.sync.wait.var)
|
||||
|
||||
[1](#exec.sync.wait.var-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5781)
|
||||
|
||||
The name this_thread::sync_wait_with_variant denotes
|
||||
a customization point object[.](#exec.sync.wait.var-1.sentence-1)
|
||||
|
||||
For a subexpression sndr,
|
||||
let Sndr be decltype(into_variant(sndr))[.](#exec.sync.wait.var-1.sentence-2)
|
||||
|
||||
The expression this_thread::sync_wait_with_variant(sndr) is expression-equivalent to the following,
|
||||
except sndr is evaluated only once:apply_sender(*get-domain-early*(sndr), sync_wait_with_variant, sndr)*Mandates*:
|
||||
|
||||
- [(1.1)](#exec.sync.wait.var-1.1)
|
||||
|
||||
[sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr, *sync-wait-env*> is true[.](#exec.sync.wait.var-1.1.sentence-1)
|
||||
|
||||
- [(1.2)](#exec.sync.wait.var-1.2)
|
||||
|
||||
The type *sync-wait-with-variant-result-type*<Sndr> is well-formed[.](#exec.sync.wait.var-1.2.sentence-1)
|
||||
|
||||
- [(1.3)](#exec.sync.wait.var-1.3)
|
||||
|
||||
[same_as](concept.same#concept:same_as "18.4.2 Concept same_as [concept.same]")<decltype(e), *sync-wait-with-variant-result-type*<Sndr>> is true, where e is the apply_sender expression above[.](#exec.sync.wait.var-1.3.sentence-1)
|
||||
|
||||
[2](#exec.sync.wait.var-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5804)
|
||||
|
||||
The expression sync_wait_with_variant.apply_sender(sndr) is equivalent to:using result_type = *sync-wait-with-variant-result-type*<Sndr>;if (auto opt_value = sync_wait(into_variant(sndr))) {return result_type(std::move(get<0>(*opt_value)));}return result_type(nullopt);
|
||||
|
||||
[3](#exec.sync.wait.var-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5814)
|
||||
|
||||
The behavior of this_thread::sync_wait_with_variant(sndr) is undefined unless:
|
||||
|
||||
- [(3.1)](#exec.sync.wait.var-3.1)
|
||||
|
||||
It blocks the current thread of execution ([[defns.block]](defns.block "3.6 block"))
|
||||
with forward progress guarantee delegation ([[intro.progress]](intro.progress "6.10.2.3 Forward progress"))
|
||||
until the specified sender completes[.](#exec.sync.wait.var-3.1.sentence-1)
|
||||
[*Note [1](#exec.sync.wait.var-note-1)*:
|
||||
The default implementation of sync_wait_with_variant achieves
|
||||
forward progress guarantee delegation by relying on
|
||||
the forward progress guarantee delegation provided by sync_wait[.](#exec.sync.wait.var-3.1.sentence-2)
|
||||
â *end note*]
|
||||
|
||||
- [(3.2)](#exec.sync.wait.var-3.2)
|
||||
|
||||
It returns the specified sender's async results as follows:
|
||||
* [(3.2.1)](#exec.sync.wait.var-3.2.1)
|
||||
|
||||
For a value completion,
|
||||
the result datums are returned in an engaged optional object
|
||||
that contains a variant of tuples[.](#exec.sync.wait.var-3.2.1.sentence-1)
|
||||
|
||||
* [(3.2.2)](#exec.sync.wait.var-3.2.2)
|
||||
|
||||
For an error completion, an exception is thrown[.](#exec.sync.wait.var-3.2.2.sentence-1)
|
||||
|
||||
* [(3.2.3)](#exec.sync.wait.var-3.2.3)
|
||||
|
||||
For a stopped completion, a disengaged optional object is returned[.](#exec.sync.wait.var-3.2.3.sentence-1)
|
||||
|
||||
#### [33.9.13.3](#exec.spawn) execution::spawn [[exec.spawn]](exec.spawn)
|
||||
|
||||
[1](#exec.spawn-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5843)
|
||||
|
||||
spawn attempts to associate the given input sender with
|
||||
the given token's async scope and, on success,
|
||||
eagerly starts the input sender[.](#exec.spawn-1.sentence-1)
|
||||
|
||||
[2](#exec.spawn-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5848)
|
||||
|
||||
The name spawn denotes a customization point object[.](#exec.spawn-2.sentence-1)
|
||||
|
||||
For subexpressions sndr, token, and env,
|
||||
|
||||
- [(2.1)](#exec.spawn-2.1)
|
||||
|
||||
let Sndr be decltype((sndr)),
|
||||
|
||||
- [(2.2)](#exec.spawn-2.2)
|
||||
|
||||
let Token be remove_cvref_t<decltype((token))>, and
|
||||
|
||||
- [(2.3)](#exec.spawn-2.3)
|
||||
|
||||
let Env be remove_cvref_t<decltype((env))>[.](#exec.spawn-2.sentence-2)
|
||||
|
||||
If any of[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr>,[scope_token](exec.scope.concepts#concept:scope_token "33.14.1 Execution scope concepts [exec.scope.concepts]")<Token>, or[*queryable*](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]")<Env> are not satisfied,
|
||||
the expression spawn(sndr, token, env) is ill-formed[.](#exec.spawn-2.sentence-3)
|
||||
|
||||
[3](#exec.spawn-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5863)
|
||||
|
||||
Let *spawn-state-base* be the exposition-only class:
|
||||
|
||||
[ð](#lib:execution::spawn-state-base)
|
||||
|
||||
namespace std::execution {struct *spawn-state-base* { // *exposition only*virtual void *complete*() noexcept = 0; // *exposition only*};}
|
||||
|
||||
[4](#exec.spawn-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5875)
|
||||
|
||||
Let *spawn-receiver* be the exposition-only class:
|
||||
|
||||
[ð](#lib:execution::spawn-receiver)
|
||||
|
||||
namespace std::execution {struct *spawn-receiver* { // *exposition only*using receiver_concept = receiver_t; *spawn-state-base** *state*; // *exposition only*void set_value() && noexcept { *state*->*complete*(); }void set_stopped() && noexcept { *state*->*complete*(); }};}
|
||||
|
||||
[5](#exec.spawn-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5891)
|
||||
|
||||
Let *spawn-state* be the exposition-only class template:
|
||||
|
||||
[ð](#lib:execution::spawn-state)
|
||||
|
||||
namespace std::execution {template<class Alloc, [scope_token](exec.scope.concepts#concept:scope_token "33.14.1 Execution scope concepts [exec.scope.concepts]") Token, [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sender>struct *spawn-state* : *spawn-state-base* { // *exposition only*using *op-t* = connect_result_t<Sender, *spawn-receiver*>; // *exposition only**spawn-state*(Alloc alloc, Sender&& sndr, Token token); // *exposition only*void *complete*() noexcept override; // *exposition only*void *run*(); // *exposition only*private:using *alloc-t* = // *exposition only*typename allocator_traits<Alloc>::template rebind_alloc<*spawn-state*>; *alloc-t* *alloc*; // *exposition only**op-t* *op*; // *exposition only* Token *token*; // *exposition only*void *destroy*() noexcept; // *exposition only*};}
|
||||
|
||||
[ð](#lib:execution::spawn-state,constructor)
|
||||
|
||||
`spawn-state(Alloc alloc, Sender&& sndr, Token token);
|
||||
`
|
||||
|
||||
[6](#exec.spawn-6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5924)
|
||||
|
||||
*Effects*: Initializes*alloc* with alloc,*token* with token, and*op* with:connect(std::move(sndr), *spawn-receiver*(this))
|
||||
|
||||
[ð](#lib:run,execution::spawn-state)
|
||||
|
||||
`void run();
|
||||
`
|
||||
|
||||
[7](#exec.spawn-7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5941)
|
||||
|
||||
*Effects*: Equivalent to:if (*token*.try_associate()) start(*op*);else*destroy*();
|
||||
|
||||
[ð](#lib:complete,execution::spawn-state)
|
||||
|
||||
`void complete() noexcept override;
|
||||
`
|
||||
|
||||
[8](#exec.spawn-8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5958)
|
||||
|
||||
*Effects*: Equivalent to:auto token = std::move(this->*token*);
|
||||
|
||||
*destroy*();
|
||||
token.disassociate();
|
||||
|
||||
[ð](#lib:destroy,execution::spawn-state)
|
||||
|
||||
`void destroy() noexcept;
|
||||
`
|
||||
|
||||
[9](#exec.spawn-9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5975)
|
||||
|
||||
*Effects*: Equivalent to:auto alloc = std::move(this->*alloc*);
|
||||
|
||||
allocator_traits<*alloc-t*>::destroy(alloc, this);
|
||||
allocator_traits<*alloc-t*>::deallocate(alloc, this, 1);
|
||||
|
||||
[10](#exec.spawn-10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5986)
|
||||
|
||||
For the expression spawn(sndr, token, env) let new_sender be the expression token.wrap(sndr) and
|
||||
let alloc and senv be defined as follows:
|
||||
|
||||
- [(10.1)](#exec.spawn-10.1)
|
||||
|
||||
if the expression get_allocator(env) is well-formed, thenalloc is the result of get_allocator(env) andsenv is the expression env,
|
||||
|
||||
- [(10.2)](#exec.spawn-10.2)
|
||||
|
||||
otherwise
|
||||
if the expression get_allocator(get_env(new_sender)) is well-formed, thenalloc is the result of get_allocator(get_env(new_sender)) andsenv is the expression *JOIN-ENV*(prop(get_allocator, alloc), env),
|
||||
|
||||
- [(10.3)](#exec.spawn-10.3)
|
||||
|
||||
otherwisealloc is allocator<void>() andsenv is the expression env[.](#exec.spawn-10.sentence-1)
|
||||
|
||||
[11](#exec.spawn-11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6006)
|
||||
|
||||
The expression spawn(sndr, token, env) is of type void and
|
||||
has the following effects:
|
||||
|
||||
- [(11.1)](#exec.spawn-11.1)
|
||||
|
||||
Uses alloc to allocate and construct an object o of
|
||||
type that is a specialization of *spawn-state* fromalloc, write_env(token.wrap(sndr), senv), and token and then
|
||||
invokes o.*run*()[.](#exec.spawn-11.sentence-1)
|
||||
If an exception is thrown then
|
||||
any constructed objects are destroyed and any allocated memory is deallocated[.](#exec.spawn-11.1.sentence-2)
|
||||
|
||||
[12](#exec.spawn-12)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6021)
|
||||
|
||||
The expression spawn(sndr, token) is expression-equivalent tospawn(sndr, token, execution::env<>())[.](#exec.spawn-12.sentence-1)
|
||||
80
cppdraft/exec/continues/on.md
Normal file
80
cppdraft/exec/continues/on.md
Normal file
@@ -0,0 +1,80 @@
|
||||
[exec.continues.on]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#exec.continues.on)
|
||||
|
||||
### 33.9.12 Sender adaptors [[exec.adapt]](exec.adapt#exec.continues.on)
|
||||
|
||||
#### 33.9.12.6 execution::continues_on [exec.continues.on]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3289)
|
||||
|
||||
continues_on adapts a sender into one
|
||||
that completes on the specified scheduler[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3293)
|
||||
|
||||
The name continues_on denotes a pipeable sender adaptor object[.](#2.sentence-1)
|
||||
|
||||
For subexpressions sch and sndr,
|
||||
if decltype((sch)) does not satisfy [scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]"), ordecltype((sndr)) does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"),continues_on(sndr, sch) is ill-formed[.](#2.sentence-2)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3300)
|
||||
|
||||
Otherwise,
|
||||
the expression continues_on(sndr, sch) is expression-equivalent to:transform_sender(*get-domain-early*(sndr), *make-sender*(continues_on, sch, sndr)) except that sndr is evaluated only once[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3308)
|
||||
|
||||
The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
|
||||
is specialized for continues_on_t as follows:namespace std::execution {template<>struct *impls-for*<continues_on_t> : *default-impls* {static constexpr auto *get-attrs* =[](const auto& data, const auto& child) noexcept -> decltype(auto) {return *JOIN-ENV*(*SCHED-ATTRS*(data), *FWD-ENV*(get_env(child))); }; };}
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3323)
|
||||
|
||||
Let sndr and env be subexpressions
|
||||
such that Sndr is decltype((sndr))[.](#5.sentence-1)
|
||||
|
||||
If [*sender-for*](exec.snd.concepts#concept:sender-for "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr, continues_on_t> is false,
|
||||
then
|
||||
the expression continues_on.transform_sender(sndr, env) is ill-formed;
|
||||
otherwise, it is equal to:auto [_, data, child] = sndr;return schedule_from(std::move(data), std::move(child));
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
This causes the continues_on(sndr, sch) sender to becomeschedule_from(sch, sndr) when it is connected with a receiver
|
||||
whose execution domain does not customize continues_on[.](#5.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3340)
|
||||
|
||||
Let out_sndr be a subexpression denoting
|
||||
a sender returned from continues_on(sndr, sch) or one equal to such, and
|
||||
let OutSndr be the type decltype((out_sndr))[.](#6.sentence-1)
|
||||
|
||||
Let out_rcvr be a subexpression denoting a receiver
|
||||
that has an environment of type Env such that [sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<OutSndr, Env> is true[.](#6.sentence-2)
|
||||
|
||||
Let op be an lvalue referring to the operation state
|
||||
that results from connecting out_sndr with out_rcvr[.](#6.sentence-3)
|
||||
|
||||
Calling start(op) shall
|
||||
start sndr on the current execution agent and
|
||||
execute completion operations on out_rcvr on an execution agent of the execution resource associated with sch[.](#6.sentence-4)
|
||||
|
||||
If scheduling onto sch fails,
|
||||
an error completion on out_rcvr shall be executed
|
||||
on an unspecified execution agent[.](#6.sentence-5)
|
||||
948
cppdraft/exec/coro/util.md
Normal file
948
cppdraft/exec/coro/util.md
Normal file
@@ -0,0 +1,948 @@
|
||||
[exec.coro.util]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.13 Coroutine utilities [exec.coro.util]
|
||||
|
||||
### [33.13.1](#exec.as.awaitable) execution::as_awaitable [[exec.as.awaitable]](exec.as.awaitable)
|
||||
|
||||
[1](#exec.as.awaitable-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6609)
|
||||
|
||||
as_awaitable transforms an object into one
|
||||
that is awaitable within a particular coroutine[.](#exec.as.awaitable-1.sentence-1)
|
||||
|
||||
Subclause [exec.coro.util] makes use of
|
||||
the following exposition-only entities:namespace std::execution {template<class Sndr, class Promise>concept [*awaitable-sender*](#concept:awaitable-sender "33.13.1 execution::as_awaitable [exec.as.awaitable]") =[*single-sender*](execution.syn#concept:single-sender "33.4 Header <execution> synopsis [execution.syn]")<Sndr, env_of_t<Promise>> &&[sender_to](exec.snd.concepts#concept:sender_to "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr, *awaitable-receiver*> && // *see below*requires (Promise& p) {{ p.unhandled_stopped() } -> [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<coroutine_handle<>>; }; template<class Sndr>concept [*has-queryable-await-completion-adaptor*](#concept:has-queryable-await-completion-adaptor "33.13.1 execution::as_awaitable [exec.as.awaitable]") = // *exposition only*[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr> &&requires(Sndr&& sender) { get_await_completion_adaptor(get_env(sender)); }; template<class Sndr, class Promise>class *sender-awaitable*; // *exposition only*}
|
||||
|
||||
[2](#exec.as.awaitable-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6636)
|
||||
|
||||
The type *sender-awaitable*<Sndr, Promise> is equivalent to:
|
||||
|
||||
namespace std::execution {template<class Sndr, class Promise>class *sender-awaitable* {struct *unit* {}; // *exposition only*using *value-type* = // *exposition only**single-sender-value-type*<Sndr, env_of_t<Promise>>; using *result-type* = // *exposition only* conditional_t<is_void_v<*value-type*>, unit, *value-type*>; struct *awaitable-receiver*; // *exposition only* variant<monostate, *result-type*, exception_ptr> *result*{}; // *exposition only* connect_result_t<Sndr, *awaitable-receiver*> *state*; // *exposition only*public:*sender-awaitable*(Sndr&& sndr, Promise& p); static constexpr bool await_ready() noexcept { return false; }void await_suspend(coroutine_handle<Promise>) noexcept { start(*state*); }*value-type* await_resume(); };}
|
||||
|
||||
[3](#exec.as.awaitable-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6662)
|
||||
|
||||
*awaitable-receiver* is equivalent to:struct *awaitable-receiver* {using receiver_concept = receiver_t;
|
||||
variant<monostate, *result-type*, exception_ptr>* *result-ptr*; // *exposition only* coroutine_handle<Promise> *continuation*; // *exposition only*// *see below*};
|
||||
|
||||
[4](#exec.as.awaitable-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6673)
|
||||
|
||||
Let rcvr be an rvalue expression of type *awaitable-receiver*,
|
||||
let crcvr be a const lvalue that refers to rcvr,
|
||||
let vs be a pack of subexpressions, and
|
||||
let err be an expression of type Err[.](#exec.as.awaitable-4.sentence-1)
|
||||
|
||||
Then:
|
||||
|
||||
- [(4.1)](#exec.as.awaitable-4.1)
|
||||
|
||||
If [constructible_from](concept.constructible#concept:constructible_from "18.4.11 Concept constructible_from [concept.constructible]")<*result-type*, decltype((vs))...> is satisfied,
|
||||
the expression set_value(
|
||||
rcvr, vs...) is equivalent to:try { rcvr.*result-ptr*->template emplace<1>(vs...);} catch(...) { rcvr.*result-ptr*->template emplace<2>(current_exception());} rcvr.*continuation*.resume();
|
||||
Otherwise, set_value(rcvr, vs...) is ill-formed[.](#exec.as.awaitable-4.1.sentence-2)
|
||||
|
||||
- [(4.2)](#exec.as.awaitable-4.2)
|
||||
|
||||
The expression set_error(rcvr, err) is equivalent to:rcvr.*result-ptr*->template emplace<2>(*AS-EXCEPT-PTR*(err)); // see [[exec.general]](exec.general "33.1 General") rcvr.*continuation*.resume();
|
||||
|
||||
- [(4.3)](#exec.as.awaitable-4.3)
|
||||
|
||||
The expression set_stopped(rcvr) is equivalent to:static_cast<coroutine_handle<>>(rcvr.*continuation*.promise().unhandled_stopped()).resume();
|
||||
|
||||
- [(4.4)](#exec.as.awaitable-4.4)
|
||||
|
||||
For any expression tag whose type satisfies [*forwarding-query*](execution.syn#concept:forwarding-query "33.4 Header <execution> synopsis [execution.syn]") and
|
||||
for any pack of subexpressions as,get_env(crcvr).query(tag, as...) is expression-equivalent to:tag(get_env(as_const(crcvr.*continuation*.promise())), as...)
|
||||
|
||||
[ð](#exec.as.awaitable-itemdecl:1)
|
||||
|
||||
`sender-awaitable(Sndr&& sndr, Promise& p);
|
||||
`
|
||||
|
||||
[5](#exec.as.awaitable-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6718)
|
||||
|
||||
*Effects*: Initializes *state* withconnect(std::forward<Sndr>(sndr), *awaitable-receiver*{addressof(result), coroutine_handle<Promise>::from_promise(p)})
|
||||
|
||||
[ð](#exec.as.awaitable-itemdecl:2)
|
||||
|
||||
`value-type await_resume();
|
||||
`
|
||||
|
||||
[6](#exec.as.awaitable-6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6732)
|
||||
|
||||
*Effects*: Equivalent to:if (*result*.index() == 2) rethrow_exception(get<2>(*result*));if constexpr (!is_void_v<*value-type*>)return std::forward<*value-type*>(get<1>(*result*));
|
||||
|
||||
[7](#exec.as.awaitable-7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6743)
|
||||
|
||||
as_awaitable is a customization point object[.](#exec.as.awaitable-7.sentence-1)
|
||||
|
||||
For subexpressions expr and p where p is an lvalue,Expr names the type decltype((expr)) andPromise names the type decay_t<decltype((p))>,as_awaitable(expr, p) is expression-equivalent to,
|
||||
except that the evaluations of expr and p are indeterminately sequenced:
|
||||
|
||||
- [(7.1)](#exec.as.awaitable-7.1)
|
||||
|
||||
expr.as_awaitable(p) if that expression is well-formed[.](#exec.as.awaitable-7.1.sentence-1)
|
||||
*Mandates*: [*is-awaitable*](exec.awaitable#concept:is-awaitable "33.9.4 Awaitable helpers [exec.awaitable]")<A, Promise> is true,
|
||||
where A is the type of the expression above[.](#exec.as.awaitable-7.1.sentence-2)
|
||||
|
||||
- [(7.2)](#exec.as.awaitable-7.2)
|
||||
|
||||
Otherwise, (void(p), expr) if [*is-awaitable*](exec.awaitable#concept:is-awaitable "33.9.4 Awaitable helpers [exec.awaitable]")<Expr, U> is true,
|
||||
where U is an unspecified class type
|
||||
that is not Promise and
|
||||
that lacks a member named await_transform[.](#exec.as.awaitable-7.2.sentence-1)
|
||||
*Preconditions*: [*is-awaitable*](exec.awaitable#concept:is-awaitable "33.9.4 Awaitable helpers [exec.awaitable]")<Expr, Promise> is true and
|
||||
the expression co_await expr in a coroutine with promise type U is expression-equivalent to
|
||||
the same expression in a coroutine with promise type Promise[.](#exec.as.awaitable-7.2.sentence-2)
|
||||
|
||||
- [(7.3)](#exec.as.awaitable-7.3)
|
||||
|
||||
Otherwise, *sender-awaitable*{*adapted-expr*, p} if*has-queryable-await-completion-adaptor*<Expr> and*awaitable-sender*<decltype((*adapted-expr*)), Promise> are both satisfied, where *adapted-expr* isget_await_completion_adaptor(get_env(expr))(expr),
|
||||
except that expr is evaluated only once[.](#exec.as.awaitable-7.3.sentence-1)
|
||||
|
||||
- [(7.4)](#exec.as.awaitable-7.4)
|
||||
|
||||
Otherwise, *sender-awaitable*{expr, p} if [*awaitable-sender*](#concept:awaitable-sender "33.13.1 execution::as_awaitable [exec.as.awaitable]")<Expr, Promise> is true[.](#exec.as.awaitable-7.4.sentence-1)
|
||||
|
||||
- [(7.5)](#exec.as.awaitable-7.5)
|
||||
|
||||
Otherwise, (void(p), expr)[.](#exec.as.awaitable-7.5.sentence-1)
|
||||
|
||||
### [33.13.2](#exec.with.awaitable.senders) execution::with_awaitable_senders [[exec.with.awaitable.senders]](exec.with.awaitable.senders)
|
||||
|
||||
[1](#exec.with.awaitable.senders-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6793)
|
||||
|
||||
with_awaitable_senders,
|
||||
when used as the base class of a coroutine promise type,
|
||||
makes senders awaitable in that coroutine type[.](#exec.with.awaitable.senders-1.sentence-1)
|
||||
|
||||
In addition, it provides a default implementation of unhandled_stopped such that if a sender completes by calling set_stopped,
|
||||
it is treated as if an uncatchable "stopped" exception were thrown
|
||||
from the [*await-expression*](expr.await#nt:await-expression "7.6.2.4 Await [expr.await]")[.](#exec.with.awaitable.senders-1.sentence-2)
|
||||
|
||||
[*Note [1](#exec.with.awaitable.senders-note-1)*:
|
||||
|
||||
The coroutine is never resumed, and
|
||||
the unhandled_stopped of the coroutine caller's promise type is called[.](#exec.with.awaitable.senders-1.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
namespace std::execution {template<[*class-type*](execution.syn#concept:class-type "33.4 Header <execution> synopsis [execution.syn]") Promise>struct [with_awaitable_senders](#lib:with_awaitable_senders "33.13.2 execution::with_awaitable_senders [exec.with.awaitable.senders]") {template<class OtherPromise>requires (<OtherPromise, void>)void set_continuation(coroutine_handle<OtherPromise> h) noexcept;
|
||||
|
||||
coroutine_handle<> [continuation](#lib:with_awaitable_senders,continuation "33.13.2 execution::with_awaitable_senders [exec.with.awaitable.senders]")() const noexcept { return *continuation*; } coroutine_handle<> [unhandled_stopped](#lib:with_awaitable_senders,unhandled_stopped "33.13.2 execution::with_awaitable_senders [exec.with.awaitable.senders]")() noexcept {return *stopped-handler*(*continuation*.address()); }template<class Value>*see below* await_transform(Value&& value); private:[[noreturn]] static coroutine_handle<>*default-unhandled-stopped*(void*) noexcept { // *exposition only* terminate(); } coroutine_handle<> *continuation*{}; // *exposition only* coroutine_handle<> (**stopped-handler*)(void*) noexcept = // *exposition only*&*default-unhandled-stopped*; };}
|
||||
|
||||
[ð](#lib:set_continuation,with_awaitable_senders)
|
||||
|
||||
`template<class OtherPromise>
|
||||
requires (<OtherPromise, void>)
|
||||
void set_continuation(coroutine_handle<OtherPromise> h) noexcept;
|
||||
`
|
||||
|
||||
[2](#exec.with.awaitable.senders-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6844)
|
||||
|
||||
*Effects*: Equivalent to:*continuation* = h;if constexpr ( requires(OtherPromise& other) { other.unhandled_stopped(); } ) {*stopped-handler* = [](void* p) noexcept -> coroutine_handle<> {return coroutine_handle<OtherPromise>::from_address(p).promise().unhandled_stopped(); };} else {*stopped-handler* = &*default-unhandled-stopped*;}
|
||||
|
||||
[ð](#lib:await_transform,with_awaitable_senders)
|
||||
|
||||
`template<class Value>
|
||||
call-result-t<as_awaitable_t, Value, Promise&> await_transform(Value&& value);
|
||||
`
|
||||
|
||||
[3](#exec.with.awaitable.senders-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6867)
|
||||
|
||||
*Effects*: Equivalent to:return as_awaitable(std::forward<Value>(value), static_cast<Promise&>(*this));
|
||||
|
||||
### [33.13.3](#exec.affine.on) execution::affine_on [[exec.affine.on]](exec.affine.on)
|
||||
|
||||
[1](#exec.affine.on-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6877)
|
||||
|
||||
affine_on adapts a sender into one that completes on
|
||||
the specified scheduler[.](#exec.affine.on-1.sentence-1)
|
||||
|
||||
If the algorithm determines that the adapted sender already completes
|
||||
on the correct scheduler it can avoid any scheduling operation[.](#exec.affine.on-1.sentence-2)
|
||||
|
||||
[2](#exec.affine.on-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6883)
|
||||
|
||||
The name affine_on denotes a pipeable sender adaptor
|
||||
object[.](#exec.affine.on-2.sentence-1)
|
||||
|
||||
For subexpressions sch and sndr, if decltype((sch)) does not satisfy [scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]"), or decltype((sndr)) does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"), affine_on(sndr, sch) is ill-formed[.](#exec.affine.on-2.sentence-2)
|
||||
|
||||
[3](#exec.affine.on-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6891)
|
||||
|
||||
Otherwise, the expression affine_on(sndr, sch) is
|
||||
expression-equivalent to:transform_sender(*get-domain-early*(sndr), *make-sender*(affine_on, sch, sndr)) except that sndr is evaluated only once[.](#exec.affine.on-3.sentence-1)
|
||||
|
||||
[4](#exec.affine.on-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6899)
|
||||
|
||||
The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
|
||||
is specialized for affine_on_t as follows:
|
||||
|
||||
namespace std::execution {template<>struct *impls-for*<affine_on_t> : *default-impls* {static constexpr auto *get-attrs* =[](const auto& data, const auto& child) noexcept -> decltype(auto) {return *JOIN-ENV*(*SCHED-ATTRS*(data), *FWD-ENV*(get_env(child))); }; };}
|
||||
|
||||
[5](#exec.affine.on-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6915)
|
||||
|
||||
Let *out_sndr* be a subexpression denoting a sender
|
||||
returned from affine_on(sndr, sch) or one equal to such,
|
||||
and let *OutSndr* be the type decltype((*out_sndr*))[.](#exec.affine.on-5.sentence-1)
|
||||
|
||||
Let *out_rcvr* be a subexpression denoting a receiver that
|
||||
has an environment of type Env such that [sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<*OutSndr*, Env> is true[.](#exec.affine.on-5.sentence-2)
|
||||
|
||||
Let *op* be an lvalue referring to the operation state that
|
||||
results from connecting *out_sndr* to *out_rcvr*[.](#exec.affine.on-5.sentence-3)
|
||||
|
||||
Calling start(*op*) will start sndr on the current
|
||||
execution agent and execute completion operations on *out_rcvr* on an execution agent of the execution resource associated withsch[.](#exec.affine.on-5.sentence-4)
|
||||
|
||||
If the current execution resource is the same as the execution
|
||||
resource associated with sch, the completion operation on*out_rcvr* may be called before start(*op*) completes[.](#exec.affine.on-5.sentence-5)
|
||||
|
||||
If scheduling onto sch fails, an error completion on*out_rcvr* shall be executed on an unspecified execution
|
||||
agent[.](#exec.affine.on-5.sentence-6)
|
||||
|
||||
### [33.13.4](#exec.inline.scheduler) execution::inline_scheduler [[exec.inline.scheduler]](exec.inline.scheduler)
|
||||
|
||||
namespace std::execution {class [inline_scheduler](#lib:inline_scheduler "33.13.4 execution::inline_scheduler [exec.inline.scheduler]") {class *inline-sender*; // *exposition only*template<[receiver](exec.recv.concepts#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]") R>class *inline-state*; // *exposition only*public:using scheduler_concept = scheduler_t; constexpr *inline-sender* schedule() noexcept { return {}; }constexpr bool operator==(const inline_scheduler&) const noexcept = default; };}
|
||||
|
||||
[1](#exec.inline.scheduler-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6954)
|
||||
|
||||
inline_scheduler is a class that models[scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]") ([[exec.sched]](exec.sched "33.6 Schedulers"))[.](#exec.inline.scheduler-1.sentence-1)
|
||||
|
||||
All objects of type inline_scheduler are equal[.](#exec.inline.scheduler-1.sentence-2)
|
||||
|
||||
[2](#exec.inline.scheduler-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6959)
|
||||
|
||||
*inline-sender* is an exposition-only type that satisfies[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]")[.](#exec.inline.scheduler-2.sentence-1)
|
||||
|
||||
The type completion_signatures_of_t<*inline-sender*> is completion_signatures<set_value_t()>[.](#exec.inline.scheduler-2.sentence-2)
|
||||
|
||||
[3](#exec.inline.scheduler-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6965)
|
||||
|
||||
Let sndr be an expression of type *inline-sender*,
|
||||
let rcvr be an expression such that[receiver_of](exec.recv.concepts#concept:receiver_of "33.7.1 Receiver concepts [exec.recv.concepts]")<decltype((rcvr)), CS> is true where CS is completion_signatures<set_value_t()>,
|
||||
then:
|
||||
|
||||
- [(3.1)](#exec.inline.scheduler-3.1)
|
||||
|
||||
the expression connect(sndr, rcvr) has
|
||||
type *inline-state*<remove_cvref_t<decltype((rcvr))>> and is potentially-throwing if and only if((void)sndr, auto(rcvr)) is potentially-throwing, and
|
||||
|
||||
- [(3.2)](#exec.inline.scheduler-3.2)
|
||||
|
||||
the expressionget_completion_scheduler<set_value_t>(get_env(sndr)) has
|
||||
type inline_scheduler and is potentially-throwing
|
||||
if and only if get_env(sndr) is potentially-throwing[.](#exec.inline.scheduler-3.sentence-1)
|
||||
|
||||
[4](#exec.inline.scheduler-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6982)
|
||||
|
||||
Let *o* be a non-const lvalue of type*inline-state*<Rcvr>, and let REC(*o*) be
|
||||
a non-const lvalue reference to an object of type Rcvr that
|
||||
was initialized with the expression rcvr passed to an
|
||||
invocation of connect that returned *o*, then:
|
||||
|
||||
- [(4.1)](#exec.inline.scheduler-4.1)
|
||||
|
||||
the object to which REC(*o*) refers remains valid for
|
||||
the lifetime of the object to which *o* refers, and
|
||||
|
||||
- [(4.2)](#exec.inline.scheduler-4.2)
|
||||
|
||||
the expression start(*o*) is equivalent toset_value(std::move(REC(*o*)))[.](#exec.inline.scheduler-4.sentence-1)
|
||||
|
||||
### [33.13.5](#exec.task.scheduler) execution::task_scheduler [[exec.task.scheduler]](exec.task.scheduler)
|
||||
|
||||
namespace std::execution {class [task_scheduler](#lib:task_scheduler "33.13.5 execution::task_scheduler [exec.task.scheduler]") {class *ts-sender*; // *exposition only*template<[receiver](exec.recv.concepts#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]") R>class *state*; // *exposition only*public:using scheduler_concept = scheduler_t; template<class Sch, class Allocator = allocator<void>>requires (<task_scheduler, remove_cvref_t<Sch>>)&& [scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]")<Sch>explicit task_scheduler(Sch&& sch, Allocator alloc = {}); *ts-sender* schedule(); friend bool operator==(const task_scheduler& lhs, const task_scheduler& rhs)noexcept; template<class Sch>requires (<task_scheduler, Sch>)&& [scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]")<Sch>friend bool operator==(const task_scheduler& lhs, const Sch& rhs) noexcept; private: shared_ptr<void> *sch_*; // *exposition only*};}
|
||||
|
||||
[1](#exec.task.scheduler-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7028)
|
||||
|
||||
task_scheduler is a class that models[scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]") ([[exec.sched]](exec.sched "33.6 Schedulers"))[.](#exec.task.scheduler-1.sentence-1)
|
||||
|
||||
Given an object s of type task_scheduler, let*SCHED*(s) be the object owned by s.*sch_*[.](#exec.task.scheduler-1.sentence-2)
|
||||
|
||||
[ð](#lib:task_scheduler,constructor)
|
||||
|
||||
`template<class Sch, class Allocator = allocator<void>>
|
||||
requires(<task_scheduler, remove_cvref_t<Sch>>) && [scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]")<Sch>
|
||||
explicit task_scheduler(Sch&& sch, Allocator alloc = {});
|
||||
`
|
||||
|
||||
[2](#exec.task.scheduler-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7041)
|
||||
|
||||
*Effects*: Initialize *sch_* withallocate_shared<remove_cvref_t<Sch>>(alloc, std::forward<Sch>(sch))[.](#exec.task.scheduler-2.sentence-1)
|
||||
|
||||
[3](#exec.task.scheduler-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7046)
|
||||
|
||||
*Recommended practice*: Implementations should avoid the use of dynamically
|
||||
allocated memory for small scheduler objects[.](#exec.task.scheduler-3.sentence-1)
|
||||
|
||||
[4](#exec.task.scheduler-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7051)
|
||||
|
||||
*Remarks*: Any allocations performed by construction of *ts-sender* or*state* objects resulting from calls on *this are
|
||||
performed using a copy of alloc[.](#exec.task.scheduler-4.sentence-1)
|
||||
|
||||
[ð](#lib:scheduler,task_scheduler)
|
||||
|
||||
`ts-sender schedule();
|
||||
`
|
||||
|
||||
[5](#exec.task.scheduler-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7063)
|
||||
|
||||
*Effects*: Returns an object of type *ts-sender* containing a sender
|
||||
initialized with schedule(*SCHED*(*this))[.](#exec.task.scheduler-5.sentence-1)
|
||||
|
||||
[ð](#lib:operator==,task_scheduler)
|
||||
|
||||
`bool operator==(const task_scheduler& lhs, const task_scheduler& rhs) noexcept;
|
||||
`
|
||||
|
||||
[6](#exec.task.scheduler-6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7074)
|
||||
|
||||
*Effects*: Equivalent to: return lhs == *SCHED*(rhs);
|
||||
|
||||
[ð](#lib:operator==,task_scheduler_)
|
||||
|
||||
`template<class Sch>
|
||||
requires (<task_scheduler, Sch>)
|
||||
&& [scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]")<Sch>
|
||||
bool operator==(const task_scheduler& lhs, const Sch& rhs) noexcept;
|
||||
`
|
||||
|
||||
[7](#exec.task.scheduler-7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7087)
|
||||
|
||||
*Returns*: false if the type of *SCHED*(lhs) is not Sch,
|
||||
otherwise *SCHED*(lhs) == rhs[.](#exec.task.scheduler-7.sentence-1)
|
||||
|
||||
[8](#exec.task.scheduler-8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7093)
|
||||
|
||||
namespace std::execution {class task_scheduler::*ts-sender* { // *exposition only*public:using sender_concept = sender_t; template<[receiver](exec.recv.concepts#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]") Rcvr>*state*<Rcvr> connect(Rcvr&& rcvr); };}*ts-sender* is an exposition-only class that models[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") ([[exec.snd]](exec.snd "33.9 Senders")) and for whichcompletion_signatures_of_t<*ts-sender*> denotes:completion_signatures< set_value_t(),
|
||||
set_error_t(error_code),
|
||||
set_error_t(exception_ptr),
|
||||
set_stopped_t()>
|
||||
|
||||
[9](#exec.task.scheduler-9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7116)
|
||||
|
||||
Let *sch* be an object of type task_scheduler and let sndr be an object of type *ts-sender* obtained
|
||||
from schedule(*sch*)[.](#exec.task.scheduler-9.sentence-1)
|
||||
|
||||
Then get_completion_scheduler<set_value_t>(get_env(sndr)) == *sch* is true[.](#exec.task.scheduler-9.sentence-2)
|
||||
|
||||
The object *SENDER*(sndr) is the sender object contained bysndr or an object move constructed from it[.](#exec.task.scheduler-9.sentence-3)
|
||||
|
||||
[ð](#lib:connect,task_scheduler::ts-sender)
|
||||
|
||||
`template<[receiver](exec.recv.concepts#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]") Rcvr>
|
||||
state<Rcvr> connect(Rcvr&& rcvr);
|
||||
`
|
||||
|
||||
[10](#exec.task.scheduler-10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7131)
|
||||
|
||||
*Effects*: Let *r* be an object of a type that models [receiver](exec.recv.concepts#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]") and whose completion handlers result in invoking the corresponding
|
||||
completion handlers of rcvr or copy thereof[.](#exec.task.scheduler-10.sentence-1)
|
||||
|
||||
Returns an object of type *state*<Rcvr> containing
|
||||
an operation state object initialized with connect(*SENDER*(*this),
|
||||
std::move(*r*))[.](#exec.task.scheduler-10.sentence-2)
|
||||
|
||||
[11](#exec.task.scheduler-11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7141)
|
||||
|
||||
namespace std::execution {template<[receiver](exec.recv.concepts#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]") R>class task_scheduler::*state* { // *exposition only*public:using operation_state_concept = operation_state_t; void start() & noexcept; };}*state* is an exposition-only class template whose
|
||||
specializations model [operation_state](exec.opstate.general#concept:operation_state "33.8.1 General [exec.opstate.general]") ([[exec.opstate]](exec.opstate "33.8 Operation states"))[.](#exec.task.scheduler-11.sentence-1)
|
||||
|
||||
[ð](#lib:start,task_scheduler::state)
|
||||
|
||||
`void start() & noexcept;
|
||||
`
|
||||
|
||||
[12](#exec.task.scheduler-12)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7161)
|
||||
|
||||
*Effects*: Equivalent to start(st) where st is the operation
|
||||
state object contained by *this[.](#exec.task.scheduler-12.sentence-1)
|
||||
|
||||
### [33.13.6](#exec.task) execution::task [[exec.task]](exec.task)
|
||||
|
||||
#### [33.13.6.1](#task.overview) task overview [[task.overview]](task.overview)
|
||||
|
||||
[1](#task.overview-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7171)
|
||||
|
||||
The task class template represents a sender that can
|
||||
be used as the return type of coroutines[.](#task.overview-1.sentence-1)
|
||||
|
||||
The first template parameter T defines the type of the value
|
||||
completion datum ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations")) if T is not void[.](#task.overview-1.sentence-2)
|
||||
|
||||
Otherwise, there are no value completion datums[.](#task.overview-1.sentence-3)
|
||||
|
||||
Inside coroutines returning task<T, E> the operand ofco_return (if any) becomes the argument of set_value[.](#task.overview-1.sentence-4)
|
||||
|
||||
The second template parameter Environment is used to customize
|
||||
the behavior of task[.](#task.overview-1.sentence-5)
|
||||
|
||||
#### [33.13.6.2](#task.class) Class template task [[task.class]](task.class)
|
||||
|
||||
namespace std::execution {template<class T, class Environment>class [task](#lib:task "33.13.6.2 Class template task [task.class]") {// [[task.state]](#task.state "33.13.6.4 Class template task::state")template<[receiver](exec.recv.concepts#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]") Rcvr>class *state*; // *exposition only*public:using sender_concept = sender_t; using completion_signatures = *see below*; using allocator_type = *see below*; using scheduler_type = *see below*; using stop_source_type = *see below*; using stop_token_type = decltype(declval<stop_source_type>().get_token()); using error_types = *see below*; // [[task.promise]](#task.promise "33.13.6.5 Class task::promise_type")class promise_type;
|
||||
|
||||
task(task&&) noexcept; ~task(); template<[receiver](exec.recv.concepts#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]") Rcvr>*state*<Rcvr> connect(Rcvr&& rcvr); private: coroutine_handle<promise_type> *handle*; // *exposition only*};}
|
||||
|
||||
[1](#task.class-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7216)
|
||||
|
||||
task<T, E> models [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") ([[exec.snd]](exec.snd "33.9 Senders"))
|
||||
if T is void, a reference type, or a cv-unqualified
|
||||
non-array object type and E is a class type[.](#task.class-1.sentence-1)
|
||||
|
||||
Otherwise a program that instantiates the definition of task<T, E> is ill-formed[.](#task.class-1.sentence-2)
|
||||
|
||||
[2](#task.class-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7223)
|
||||
|
||||
The nested types of task template specializations
|
||||
are determined based on the Environment parameter:
|
||||
|
||||
- [(2.1)](#task.class-2.1)
|
||||
|
||||
allocator_type is Environment::allocator_type if that [*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") is valid and denotes a type,allocator<byte> otherwise[.](#task.class-2.1.sentence-1)
|
||||
|
||||
- [(2.2)](#task.class-2.2)
|
||||
|
||||
scheduler_type is Environment::scheduler_type if that [*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") is valid and denotes a type,task_scheduler otherwise[.](#task.class-2.2.sentence-1)
|
||||
|
||||
- [(2.3)](#task.class-2.3)
|
||||
|
||||
stop_source_type is Environment::stop_source_type if that [*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") is valid and denotes a type,inplace_stop_source otherwise[.](#task.class-2.3.sentence-1)
|
||||
|
||||
- [(2.4)](#task.class-2.4)
|
||||
|
||||
error_types is Environment::error_types if
|
||||
that [*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") is valid and denotes a type,completion_signatures<set_error_t(exception_ptr)> otherwise[.](#task.class-2.4.sentence-1)
|
||||
|
||||
[3](#task.class-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7241)
|
||||
|
||||
A program is ill-formed if error_types is not a
|
||||
specialization of completion_signatures<ErrorSigs...> orErrorSigs contains an element which is not of the formset_error_t(E) for some type E[.](#task.class-3.sentence-1)
|
||||
|
||||
[4](#task.class-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7247)
|
||||
|
||||
The type alias completion_signatures is a specialization
|
||||
of execution::completion_signatures with the template
|
||||
arguments (in unspecified order):
|
||||
|
||||
- [(4.1)](#task.class-4.1)
|
||||
|
||||
set_value_t() if T is void,
|
||||
and set_value_t(T) otherwise;
|
||||
|
||||
- [(4.2)](#task.class-4.2)
|
||||
|
||||
template arguments of the specialization ofexecution::completion_signatures denoted by error_types;
|
||||
and
|
||||
|
||||
- [(4.3)](#task.class-4.3)
|
||||
|
||||
set_stopped_t()[.](#task.class-4.sentence-1)
|
||||
|
||||
[5](#task.class-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7260)
|
||||
|
||||
allocator_type shall meet the *Cpp17Allocator* requirements[.](#task.class-5.sentence-1)
|
||||
|
||||
#### [33.13.6.3](#task.members) task members [[task.members]](task.members)
|
||||
|
||||
[ð](#lib:task,constructor)
|
||||
|
||||
`task(task&& other) noexcept;
|
||||
`
|
||||
|
||||
[1](#task.members-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7271)
|
||||
|
||||
*Effects*: Initializes *handle* with exchange(other.*handle*,{})[.](#task.members-1.sentence-1)
|
||||
|
||||
[ð](#lib:task,destructor)
|
||||
|
||||
`~task();
|
||||
`
|
||||
|
||||
[2](#task.members-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7282)
|
||||
|
||||
*Effects*: Equivalent to:if (*handle*)*handle*.destroy();
|
||||
|
||||
[ð](#lib:connect,task)
|
||||
|
||||
`template<[receiver](exec.recv.concepts#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]") Rcvr>
|
||||
state<Rcvr> connect(Rcvr&& recv);
|
||||
`
|
||||
|
||||
[3](#task.members-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7297)
|
||||
|
||||
*Preconditions*: bool(*handle*) is true[.](#task.members-3.sentence-1)
|
||||
|
||||
[4](#task.members-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7301)
|
||||
|
||||
*Effects*: Equivalent to:return *state*<Rcvr>(exchange(*handle*, {}), std::forward<Rcvr>(recv));
|
||||
|
||||
#### [33.13.6.4](#task.state) Class template task::*state* [[task.state]](task.state)
|
||||
|
||||
namespace std::execution {template<class T, class Environment>template<[receiver](exec.recv.concepts#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]") Rcvr>class task<T, Environment>::*state* { // *exposition only*public:using operation_state_concept = operation_state_t; template<class R>*state*(coroutine_handle<promise_type> h, R&& rr); ~*state*(); void start() & noexcept; private:using *own-env-t* = *see below*; // *exposition only* coroutine_handle<promise_type> *handle*; // *exposition only* remove_cvref_t<Rcvr> *rcvr*; // *exposition only**own-env-t* *own-env*; // *exposition only* Environment *environment*; // *exposition only*};}
|
||||
|
||||
[1](#task.state-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7336)
|
||||
|
||||
The type *own-env-t* is Environment::template env_type<decltype(get_env(declval<Rcvr>()))> if that[*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") is valid and denotes a type, env<> otherwise[.](#task.state-1.sentence-1)
|
||||
|
||||
[ð](#lib:task::state,constructor)
|
||||
|
||||
`template<class R>
|
||||
state(coroutine_handle<promise_type> h, R&& rr);
|
||||
`
|
||||
|
||||
[2](#task.state-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7347)
|
||||
|
||||
*Effects*: Initializes
|
||||
|
||||
- [(2.1)](#task.state-2.1)
|
||||
|
||||
*handle* with std::move(h);
|
||||
|
||||
- [(2.2)](#task.state-2.2)
|
||||
|
||||
*rcvr* with std::forward<R>(rr);
|
||||
|
||||
- [(2.3)](#task.state-2.3)
|
||||
|
||||
*own-env* with *own-env-t*(get_env(*rcvr*)) if that expression
|
||||
is valid and *own-env-t*() otherwise[.](#task.state-2.3.sentence-1)
|
||||
If neither of these expressions is valid, the program is ill-formed[.](#task.state-2.3.sentence-2)
|
||||
|
||||
- [(2.4)](#task.state-2.4)
|
||||
|
||||
*environment* withEnvironment(*own-env*) if that expression is
|
||||
valid, otherwise Environment(get_env(*rcvr*)) if this expression is valid, otherwise Environment()[.](#task.state-2.4.sentence-1)
|
||||
If neither of these expressions is valid, the program is ill-formed[.](#task.state-2.4.sentence-2)
|
||||
|
||||
[ð](#lib:task::state,destructor)
|
||||
|
||||
`~state();
|
||||
`
|
||||
|
||||
[3](#task.state-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7370)
|
||||
|
||||
*Effects*: Equivalent to:if (*handle*)*handle*.destroy();
|
||||
|
||||
[ð](#lib:start,task::state)
|
||||
|
||||
`void start() & noexcept;
|
||||
`
|
||||
|
||||
[4](#task.state-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7384)
|
||||
|
||||
*Effects*: Let *prom* be the object *handle*.promise()[.](#task.state-4.sentence-1)
|
||||
|
||||
Associates *STATE*(*prom*), *RCVR*(*prom*), and *SCHED*(*prom*) with *this as follows:
|
||||
|
||||
- [(4.1)](#task.state-4.1)
|
||||
|
||||
*STATE*(*prom*) is *this[.](#task.state-4.1.sentence-1)
|
||||
|
||||
- [(4.2)](#task.state-4.2)
|
||||
|
||||
*RCVR*(*prom*) is *rcvr*[.](#task.state-4.2.sentence-1)
|
||||
|
||||
- [(4.3)](#task.state-4.3)
|
||||
|
||||
*SCHED*(*prom*) is the object initialized
|
||||
with scheduler_type(get_scheduler(get_env(*rcvr*))) if that expression is valid and scheduler_type() otherwise[.](#task.state-4.3.sentence-1)
|
||||
If neither of these expressions is valid, the program is ill-formed[.](#task.state-4.3.sentence-2)
|
||||
|
||||
Let *st* be get_stop_token(get_env(*rcvr*))[.](#task.state-4.sentence-3)
|
||||
|
||||
Initializes *prom*.*token* and*prom*.*source* such that
|
||||
|
||||
- [(4.4)](#task.state-4.4)
|
||||
|
||||
*prom*.*token*.stop_requested() returns*st*.stop_requested();
|
||||
|
||||
- [(4.5)](#task.state-4.5)
|
||||
|
||||
*prom*.*token*.stop_possible() returns*st*.stop_possible(); and
|
||||
|
||||
- [(4.6)](#task.state-4.6)
|
||||
|
||||
for types Fn and Init such that both[invocable](concept.invocable#concept:invocable "18.7.2 Concept invocable [concept.invocable]")<Fn> and[constructible_from](concept.constructible#concept:constructible_from "18.4.11 Concept constructible_from [concept.constructible]")<Fn, Init> are modeled,stop_token_type::callback_type<Fn> models[*stoppable-callback-for*](stoptoken.concepts#concept:stoppable-callback-for "32.3.3 Stop token concepts [stoptoken.concepts]")<Fn, stop_token_type, Init>[.](#task.state-4.sentence-4)
|
||||
|
||||
After that invokes *handle*.resume()[.](#task.state-4.sentence-5)
|
||||
|
||||
#### [33.13.6.5](#task.promise) Class task::promise_type [[task.promise]](task.promise)
|
||||
|
||||
namespace std::execution {template<class T, class Environment>class task<T, Environment>::promise_type {public:template<class... Args> promise_type(const Args&... args);
|
||||
|
||||
task get_return_object() noexcept; auto initial_suspend() noexcept; auto final_suspend() noexcept; void uncaught_exception();
|
||||
coroutine_handle<> unhandled_stopped(); void return_void(); // present only if is_void_v<T> is truetemplate<class V>void return_value(V&& value); // present only if is_void_v<T> is falsetemplate<class E>*unspecified* yield_value(with_error<E> error); template<class A>auto await_transform(A&& a); template<class Sch>auto await_transform(change_coroutine_scheduler<Sch> sch); *unspecified* get_env() const noexcept; template<class... Args>void* operator new(size_t size, Args&&... args); void operator delete(void* pointer, size_t size) noexcept; private:using *error-variant* = *see below*; // *exposition only* allocator_type *alloc*; // *exposition only* stop_source_type *source*; // *exposition only* stop_token_type *token*; // *exposition only* optional<T> *result*; // *exposition only*; present only if is_void_v<T> is false*error-variant* *errors*; // *exposition only*};}
|
||||
|
||||
[1](#task.promise-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7466)
|
||||
|
||||
Let *prom* be an object of promise_type and let *tsk* be the task object
|
||||
created by *prom*.get_return_object()[.](#task.promise-1.sentence-1)
|
||||
|
||||
The description below
|
||||
refers to objects *STATE*(*prom*),*RCVR*(*prom*),
|
||||
and *SCHED*(*prom*) associated with *tsk* during evaluation of task::*state*<Rcvr>::start for some receiver Rcvr[.](#task.promise-1.sentence-2)
|
||||
|
||||
[2](#task.promise-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7478)
|
||||
|
||||
*error-variant* is a variant<monostate,
|
||||
remove_cvref_t<E>...>, with duplicate types removed, where E... are the parameter types of the template arguments of the specialization ofexecution::completion_signatures denoted byerror_types[.](#task.promise-2.sentence-1)
|
||||
|
||||
[ð](#lib:task::promise_type,constructor)
|
||||
|
||||
`template<class... Args>
|
||||
promise_type(const Args&... args);
|
||||
`
|
||||
|
||||
[3](#task.promise-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7491)
|
||||
|
||||
*Mandates*: The first parameter of type allocator_arg_t (if any) is not
|
||||
the last parameter[.](#task.promise-3.sentence-1)
|
||||
|
||||
[4](#task.promise-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7496)
|
||||
|
||||
*Effects*: If Args contains an element of type allocator_arg_t then *alloc* is initialized with the corresponding next
|
||||
element of args[.](#task.promise-4.sentence-1)
|
||||
|
||||
Otherwise, *alloc* is initialized with allocator_type()[.](#task.promise-4.sentence-2)
|
||||
|
||||
[ð](#lib:get_return_object,task::promise_type)
|
||||
|
||||
`task get_return_object() noexcept;
|
||||
`
|
||||
|
||||
[5](#task.promise-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7509)
|
||||
|
||||
*Returns*: A task object whose member *handle* iscoroutine_handle<promise_type>::from_promise(*this)[.](#task.promise-5.sentence-1)
|
||||
|
||||
[ð](#lib:initial_suspend,task::promise_type)
|
||||
|
||||
`auto initial_suspend() noexcept;
|
||||
`
|
||||
|
||||
[6](#task.promise-6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7520)
|
||||
|
||||
*Returns*: An awaitable object of unspecified type ([[expr.await]](expr.await "7.6.2.4 Await")) whose
|
||||
member functions arrange for
|
||||
|
||||
- [(6.1)](#task.promise-6.1)
|
||||
|
||||
the calling coroutine to be suspended,
|
||||
|
||||
- [(6.2)](#task.promise-6.2)
|
||||
|
||||
the coroutine to be resumed on an execution agent of the
|
||||
execution resource associated with *SCHED*(*this)[.](#task.promise-6.sentence-1)
|
||||
|
||||
[ð](#lib:final_suspend,task::promise_type)
|
||||
|
||||
`auto final_suspend() noexcept;
|
||||
`
|
||||
|
||||
[7](#task.promise-7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7536)
|
||||
|
||||
*Returns*: An awaitable object of unspecified type ([[expr.await]](expr.await "7.6.2.4 Await")) whose
|
||||
member functions arrange for the completion of the asynchronous
|
||||
operation associated with *STATE*(*this) by invoking:
|
||||
|
||||
- [(7.1)](#task.promise-7.1)
|
||||
|
||||
set_error(std::move(*RCVR*(*this)), std::move(e)) if *errors*.index() is greater than zero ande is the value held by *errors*, otherwise
|
||||
|
||||
- [(7.2)](#task.promise-7.2)
|
||||
|
||||
set_value(std::move(*RCVR*(*this))) if is_void<T> is true,
|
||||
and otherwise
|
||||
|
||||
- [(7.3)](#task.promise-7.3)
|
||||
|
||||
set_value(std::move(*RCVR*(*this)), **result*)[.](#task.promise-7.sentence-1)
|
||||
|
||||
[ð](#lib:yield_value,task::promise_type)
|
||||
|
||||
`template<class Err>
|
||||
auto yield_value(with_error<Err> err);
|
||||
`
|
||||
|
||||
[8](#task.promise-8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7560)
|
||||
|
||||
*Mandates*: std::move(err.error) is convertible to exactly one of theset_error_t argument types of error_types[.](#task.promise-8.sentence-1)
|
||||
|
||||
Let *Cerr* be that type[.](#task.promise-8.sentence-2)
|
||||
|
||||
[9](#task.promise-9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7566)
|
||||
|
||||
*Returns*: An awaitable object of unspecified type ([[expr.await]](expr.await "7.6.2.4 Await")) whose
|
||||
member functions arrange for the calling coroutine to be suspended
|
||||
and then completes the asynchronous operation associated with*STATE*(*this) by invoking set_error(std::move(*RCVR*(*this)),*Cerr*(std::move(err.error)))[.](#task.promise-9.sentence-1)
|
||||
|
||||
[ð](#lib:await_transform,task::promise_type)
|
||||
|
||||
`template<[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sender>
|
||||
auto await_transform(Sender&& sndr) noexcept;
|
||||
`
|
||||
|
||||
[10](#task.promise-10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7581)
|
||||
|
||||
*Returns*: If [same_as](concept.same#concept:same_as "18.4.2 Concept same_as [concept.same]")<inline_scheduler, scheduler_type> is true returns as_awaitable(std::forward<Sender>(sndr), *this);
|
||||
otherwise returnsas_awaitable(affine_on(std::forward<Sender>(sndr), *SCHED*(*this)), *this)[.](#task.promise-10.sentence-1)
|
||||
|
||||
[ð](#lib:await_transform,task::promise_type_)
|
||||
|
||||
`template<class Sch>
|
||||
auto await_transform(change_coroutine_scheduler<Sch> sch) noexcept;
|
||||
`
|
||||
|
||||
[11](#task.promise-11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7595)
|
||||
|
||||
*Effects*: Equivalent to:return await_transform(just(exchange(*SCHED*(*this), scheduler_type(sch.scheduler))), *this);
|
||||
|
||||
[ð](#lib:uncaught_exception,task::promise_type)
|
||||
|
||||
`void uncaught_exception();
|
||||
`
|
||||
|
||||
[12](#task.promise-12)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7608)
|
||||
|
||||
*Effects*: If the signature set_error_t(exception_ptr) is not an element
|
||||
of error_types, calls terminate() ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#task.promise-12.sentence-1)
|
||||
|
||||
Otherwise, stores current_exception() into *errors*[.](#task.promise-12.sentence-2)
|
||||
|
||||
[ð](#lib:unhandled_stopped,task::promise_type)
|
||||
|
||||
`coroutine_handle<> unhandled_stopped();
|
||||
`
|
||||
|
||||
[13](#task.promise-13)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7620)
|
||||
|
||||
*Effects*: Completes the asynchronous operation associated with *STATE*(*this) by invoking set_stopped(std::move(*RCVR*(*this)))[.](#task.promise-13.sentence-1)
|
||||
|
||||
[14](#task.promise-14)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7626)
|
||||
|
||||
*Returns*: noop_coroutine()[.](#task.promise-14.sentence-1)
|
||||
|
||||
[ð](#lib:get_env,task::promise_type)
|
||||
|
||||
`unspecified get_env() const noexcept;
|
||||
`
|
||||
|
||||
[15](#task.promise-15)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7636)
|
||||
|
||||
*Returns*: An object env such that queries are forwarded as follows:
|
||||
|
||||
- [(15.1)](#task.promise-15.1)
|
||||
|
||||
env.query(get_scheduler) returns scheduler_type(*SCHED*(*this))[.](#task.promise-15.1.sentence-1)
|
||||
|
||||
- [(15.2)](#task.promise-15.2)
|
||||
|
||||
env.query(get_allocator) returns *alloc*[.](#task.promise-15.2.sentence-1)
|
||||
|
||||
- [(15.3)](#task.promise-15.3)
|
||||
|
||||
env.query(get_stop_token) returns *token*[.](#task.promise-15.3.sentence-1)
|
||||
|
||||
- [(15.4)](#task.promise-15.4)
|
||||
|
||||
For any other query q and arguments a... a
|
||||
call to env.query(q, a...) returns*STATE*(*this)[.](#task.promise-15.4.sentence-1)
|
||||
environment.query(q, a...) if this expression
|
||||
is well-formed and forwarding_query(q) is well-formed and is true[.](#task.promise-15.4.sentence-2)
|
||||
Otherwise env.query(q, a...) is ill-formed[.](#task.promise-15.4.sentence-3)
|
||||
|
||||
[ð](#lib:operator_new,task::promise_type)
|
||||
|
||||
`template<class... Args>
|
||||
void* operator new(size_t size, const Args&... args);
|
||||
`
|
||||
|
||||
[16](#task.promise-16)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7657)
|
||||
|
||||
If there is no parameter with type allocator_arg_t then letalloc be allocator_type()[.](#task.promise-16.sentence-1)
|
||||
|
||||
Otherwise, let arg_next be the parameter
|
||||
following the first allocator_arg_t parameter,
|
||||
and let alloc be allocator_type(arg_next)[.](#task.promise-16.sentence-2)
|
||||
|
||||
Let PAlloc be allocator_traits<allocator_type>::template rebind_alloc<U>, where U is an unspecified type
|
||||
whose size and alignment are both __STDCPP_DEFAULT_NEW_ALIGNMENT__[.](#task.promise-16.sentence-3)
|
||||
|
||||
[17](#task.promise-17)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7667)
|
||||
|
||||
*Mandates*:
|
||||
|
||||
- [(17.1)](#task.promise-17.1)
|
||||
|
||||
The first parameter of type allocator_arg_t (if any) is not the last parameter[.](#task.promise-17.1.sentence-1)
|
||||
|
||||
- [(17.2)](#task.promise-17.2)
|
||||
|
||||
allocator_type(arg_next) is a valid expression if there is a parameter
|
||||
of type allocator_arg_t[.](#task.promise-17.2.sentence-1)
|
||||
|
||||
- [(17.3)](#task.promise-17.3)
|
||||
|
||||
allocator_traits<PAlloc>::pointer is a pointer type[.](#task.promise-17.3.sentence-1)
|
||||
|
||||
[18](#task.promise-18)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7676)
|
||||
|
||||
*Effects*: Initializes an allocator palloc of type PAlloc withalloc[.](#task.promise-18.sentence-1)
|
||||
|
||||
Uses palloc to allocate storage for the
|
||||
smallest array of U sufficient to provide storage for a
|
||||
coroutine state of size size, and unspecified additional
|
||||
state necessary to ensure that operator delete can later
|
||||
deallocate this memory block with an allocator equal to palloc[.](#task.promise-18.sentence-2)
|
||||
|
||||
[19](#task.promise-19)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7686)
|
||||
|
||||
*Returns*: A pointer to the allocated storage[.](#task.promise-19.sentence-1)
|
||||
|
||||
[ð](#lib:operator_delete,task::promise_type)
|
||||
|
||||
`void operator delete(void* pointer, size_t size) noexcept;
|
||||
`
|
||||
|
||||
[20](#task.promise-20)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7696)
|
||||
|
||||
*Preconditions*: pointer was returned from an invocation of the above overload
|
||||
of operator new with a size argument equal to size[.](#task.promise-20.sentence-1)
|
||||
|
||||
[21](#task.promise-21)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7701)
|
||||
|
||||
*Effects*: Deallocates the storage pointed to by pointer using an
|
||||
allocator equal to that used to allocate it[.](#task.promise-21.sentence-1)
|
||||
410
cppdraft/exec/counting/scopes.md
Normal file
410
cppdraft/exec/counting/scopes.md
Normal file
@@ -0,0 +1,410 @@
|
||||
[exec.counting.scopes]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.14 Execution scope utilities [[exec.scope]](exec.scope#exec.counting.scopes)
|
||||
|
||||
### 33.14.2 Counting Scopes [exec.counting.scopes]
|
||||
|
||||
#### [33.14.2.1](#general) General [[exec.counting.scopes.general]](exec.counting.scopes.general)
|
||||
|
||||
[1](#general-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7769)
|
||||
|
||||
Scopes of type simple_counting_scope and counting_scope maintain counts of associations[.](#general-1.sentence-1)
|
||||
|
||||
Let:
|
||||
|
||||
- [(1.1)](#general-1.1)
|
||||
|
||||
Scope be either simple_counting_scope or counting_scope,
|
||||
|
||||
- [(1.2)](#general-1.2)
|
||||
|
||||
scope be an object of type Scope,
|
||||
|
||||
- [(1.3)](#general-1.3)
|
||||
|
||||
tkn be an object of type Scope::token obtained from scope.get_token(),
|
||||
|
||||
- [(1.4)](#general-1.4)
|
||||
|
||||
jsndr be a sender obtained from scope.join(), and
|
||||
|
||||
- [(1.5)](#general-1.5)
|
||||
|
||||
op be an operation state obtained from
|
||||
connecting jsndr to a receiver[.](#general-1.sentence-2)
|
||||
|
||||
During its lifetime scope goes through different states
|
||||
which govern what operations are allowed and the result of these operations:
|
||||
|
||||
- [(1.6)](#general-1.6)
|
||||
|
||||
*unused*:
|
||||
a newly constructed object starts in the *unused* state[.](#general-1.6.sentence-1)
|
||||
|
||||
- [(1.7)](#general-1.7)
|
||||
|
||||
*open*:
|
||||
when tkn.try_associate() is called
|
||||
while scope is in the *unused* state,scope moves to the *open* state[.](#general-1.7.sentence-1)
|
||||
|
||||
- [(1.8)](#general-1.8)
|
||||
|
||||
*open-and-joining*:
|
||||
when the operation state op is started
|
||||
while scope is in the *unused* or *open* state,scope moves to the *open-and-joining* state[.](#general-1.8.sentence-1)
|
||||
|
||||
- [(1.9)](#general-1.9)
|
||||
|
||||
*closed*:
|
||||
when scope.close() is called
|
||||
while scope is in the *open* state,scope moves to the *closed* state[.](#general-1.9.sentence-1)
|
||||
|
||||
- [(1.10)](#general-1.10)
|
||||
|
||||
*unused-and-closed*:
|
||||
when scope.close() is called
|
||||
while scope is in the *unused* state,scope moves to the *unused-and-closed* state[.](#general-1.10.sentence-1)
|
||||
|
||||
- [(1.11)](#general-1.11)
|
||||
|
||||
*closed-and-joining*:
|
||||
when scope.close() is called
|
||||
while scope is in the *open-and-joining* state or
|
||||
the operation state op is started
|
||||
while scope is in
|
||||
the *closed* or *unused-and-closed* state,scope moves to the *closed-and-joining* state[.](#general-1.11.sentence-1)
|
||||
|
||||
- [(1.12)](#general-1.12)
|
||||
|
||||
*joined*:
|
||||
when the count of associations drops to zero
|
||||
while scope is in
|
||||
the *open-and-joining* or *closed-and-joining* state,scope moves to the *joined* state[.](#general-1.12.sentence-1)
|
||||
|
||||
[2](#general-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7836)
|
||||
|
||||
*Recommended practice*: For simple_counting_scope and counting_scope,
|
||||
implementations should store the state and the count of associations
|
||||
in a single member of type size_t[.](#general-2.sentence-1)
|
||||
|
||||
[3](#general-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7842)
|
||||
|
||||
Subclause [exec.counting.scopes] makes use of
|
||||
the following exposition-only entities:
|
||||
|
||||
struct *scope-join-t* {}; // *exposition only*enum *scope-state-type* { // *exposition only**unused*, // *exposition only**open*, // *exposition only**closed*, // *exposition only**open-and-joining*, // *exposition only**closed-and-joining*, // *exposition only**unused-and-closed*, // *exposition only**joined*, // *exposition only*};
|
||||
|
||||
[4](#general-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7860)
|
||||
|
||||
The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
|
||||
is specialized for *scope-join-t* as follows:
|
||||
|
||||
namespace std::execution {template<>struct *impls-for*<*scope-join-t*> : *default-impls* {template<class Scope, class Rcvr>struct *state* { // *exposition only*struct *rcvr-t* { // *exposition only*using receiver_concept = receiver_t;
|
||||
|
||||
Rcvr& *rcvr*; // *exposition only*void set_value() && noexcept { execution::set_value(std::move(*rcvr*)); }template<class E>void set_error(E&& e) && noexcept { execution::set_error(std::move(*rcvr*), std::forward<E>(e)); }void set_stopped() && noexcept { execution::set_stopped(std::move(*rcvr*)); }decltype(auto) get_env() const noexcept {return execution::get_env(*rcvr*); }}; using *sched-sender* = // *exposition only*decltype(schedule(get_scheduler(get_env(declval<Rcvr&>())))); using *op-t* = // *exposition only* connect_result_t<*sched-sender*, *rcvr-t*>;
|
||||
|
||||
Scope* *scope*; // *exposition only* Rcvr& *receiver*; // *exposition only**op-t* *op*; // *exposition only**state*(Scope* scope, Rcvr& rcvr) // *exposition only*noexcept([*nothrow-callable*](functional.syn#concept:nothrow-callable "22.10.2 Header <functional> synopsis [functional.syn]")<connect_t, *sched-sender*, *rcvr-t*>): *scope*(scope), *receiver*(rcvr), *op*(connect(schedule(get_scheduler(get_env(rcvr))), *rcvr-t*(rcvr))) {}void *complete*() noexcept { // *exposition only* start(*op*); }void *complete-inline*() noexcept { // *exposition only* set_value(std::move(*receiver*)); }}; static constexpr auto *get-state* = // *exposition only*[]<class Rcvr>(auto&& sender, Rcvr& receiver)noexcept(is_nothrow_constructible_v<*state*<Rcvr>, *data-type*<decltype(sender)>, Rcvr&>) {auto[_, self] = sender; return *state*(self, receiver); }; static constexpr auto *start* = // *exposition only*[](auto& s, auto&) noexcept {if (s.*scope*->*start-join-sender*(s)) s.*complete-inline*(); }; };}
|
||||
|
||||
#### [33.14.2.2](#exec.scope.simple.counting) Simple Counting Scope [[exec.scope.simple.counting]](exec.scope.simple.counting)
|
||||
|
||||
#### [33.14.2.2.1](#exec.scope.simple.counting.general) General [[exec.scope.simple.counting.general]](exec.scope.simple.counting.general)
|
||||
|
||||
[ð](#lib:execution::simple_counting_scope)
|
||||
|
||||
namespace std::execution {class simple_counting_scope {public:// [[exec.simple.counting.token]](#exec.simple.counting.token "33.14.2.2.4 Token"), tokenstruct token; static constexpr size_t max_associations = *implementation-defined*; // [[exec.simple.counting.ctor]](#exec.simple.counting.ctor "33.14.2.2.2 Constructor and Destructor"), constructor and destructor simple_counting_scope() noexcept;
|
||||
simple_counting_scope(simple_counting_scope&&) = delete; ~simple_counting_scope(); // [[exec.simple.counting.mem]](#exec.simple.counting.mem "33.14.2.2.3 Members"), members token get_token() noexcept; void close() noexcept; [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") auto join() noexcept; private: size_t *count*; // *exposition only**scope-state-type* *state*; // *exposition only*bool *try-associate*() noexcept; // *exposition only*void *disassociate*() noexcept; // *exposition only*template<class State>bool *start-join-sender*(State& state) noexcept; // *exposition only*};}
|
||||
|
||||
[1](#exec.scope.simple.counting.general-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7971)
|
||||
|
||||
For purposes of determining the existence of a data race,get_token,close,join,*try-associate*,*disassociate*, and*start-join-sender* behave as atomic operations ([[intro.multithread]](intro.multithread "6.10.2 Multi-threaded executions and data races"))[.](#exec.scope.simple.counting.general-1.sentence-1)
|
||||
|
||||
These operations on a single object of
|
||||
type simple_counting_scope appear to occur in a single total order[.](#exec.scope.simple.counting.general-1.sentence-2)
|
||||
|
||||
#### [33.14.2.2.2](#exec.simple.counting.ctor) Constructor and Destructor [[exec.simple.counting.ctor]](exec.simple.counting.ctor)
|
||||
|
||||
[ð](#lib:execution::simple_counting_scope,constructor)
|
||||
|
||||
`simple_counting_scope() noexcept;
|
||||
`
|
||||
|
||||
[1](#exec.simple.counting.ctor-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7991)
|
||||
|
||||
*Postconditions*: *count* is 0 and *state* is *unused*[.](#exec.simple.counting.ctor-1.sentence-1)
|
||||
|
||||
[ð](#lib:execution::simple_counting_scope,destructor)
|
||||
|
||||
`~simple_counting_scope();
|
||||
`
|
||||
|
||||
[2](#exec.simple.counting.ctor-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8002)
|
||||
|
||||
*Effects*: If *state* is not one of*joined*, *unused*, or *unused-and-closed*,
|
||||
invokes terminate ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#exec.simple.counting.ctor-2.sentence-1)
|
||||
|
||||
Otherwise, has no effects[.](#exec.simple.counting.ctor-2.sentence-2)
|
||||
|
||||
#### [33.14.2.2.3](#exec.simple.counting.mem) Members [[exec.simple.counting.mem]](exec.simple.counting.mem)
|
||||
|
||||
[ð](#lib:get_token,execution::simple_counting_scope)
|
||||
|
||||
`token get_token() noexcept;
|
||||
`
|
||||
|
||||
[1](#exec.simple.counting.mem-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8018)
|
||||
|
||||
*Returns*: An object t of type simple_counting_scope::token such thatt.*scope* == this is true[.](#exec.simple.counting.mem-1.sentence-1)
|
||||
|
||||
[ð](#lib:close,execution::simple_counting_scope)
|
||||
|
||||
`void close() noexcept;
|
||||
`
|
||||
|
||||
[2](#exec.simple.counting.mem-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8030)
|
||||
|
||||
*Effects*: If *state* is
|
||||
|
||||
- [(2.1)](#exec.simple.counting.mem-2.1)
|
||||
|
||||
*unused*, then changes *state* to *unused-and-closed*;
|
||||
|
||||
- [(2.2)](#exec.simple.counting.mem-2.2)
|
||||
|
||||
*open*, then changes *state* to *closed*;
|
||||
|
||||
- [(2.3)](#exec.simple.counting.mem-2.3)
|
||||
|
||||
*open-and-joining*,
|
||||
then changes *state* to *closed-and-joining*;
|
||||
|
||||
- [(2.4)](#exec.simple.counting.mem-2.4)
|
||||
|
||||
otherwise, no effects[.](#exec.simple.counting.mem-2.sentence-1)
|
||||
|
||||
[3](#exec.simple.counting.mem-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8045)
|
||||
|
||||
*Postconditions*: Any subsequent call to *try-associate*() on *this returns false[.](#exec.simple.counting.mem-3.sentence-1)
|
||||
|
||||
[ð](#lib:join,execution::simple_counting_scope)
|
||||
|
||||
`[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") auto join() noexcept;
|
||||
`
|
||||
|
||||
[4](#exec.simple.counting.mem-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8057)
|
||||
|
||||
*Returns*: *make-sender*(*scope-join-t*(), this)[.](#exec.simple.counting.mem-4.sentence-1)
|
||||
|
||||
[ð](#lib:try-associate,execution::simple_counting_scope)
|
||||
|
||||
`bool try-associate() noexcept;
|
||||
`
|
||||
|
||||
[5](#exec.simple.counting.mem-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8068)
|
||||
|
||||
*Effects*: If *count* is equal to max_associations, then no effects[.](#exec.simple.counting.mem-5.sentence-1)
|
||||
|
||||
Otherwise, if *state* is
|
||||
|
||||
- [(5.1)](#exec.simple.counting.mem-5.1)
|
||||
|
||||
*unused*,
|
||||
then increments *count* and changes *state* to *open*;
|
||||
|
||||
- [(5.2)](#exec.simple.counting.mem-5.2)
|
||||
|
||||
*open* or *open-and-joining*,
|
||||
then increments *count*;
|
||||
|
||||
- [(5.3)](#exec.simple.counting.mem-5.3)
|
||||
|
||||
otherwise, no effects[.](#exec.simple.counting.mem-5.sentence-2)
|
||||
|
||||
[6](#exec.simple.counting.mem-6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8083)
|
||||
|
||||
*Returns*: true if *count* was incremented, false otherwise[.](#exec.simple.counting.mem-6.sentence-1)
|
||||
|
||||
[ð](#lib:disassociate,execution::simple_counting_scope)
|
||||
|
||||
`void disassociate() noexcept;
|
||||
`
|
||||
|
||||
[7](#exec.simple.counting.mem-7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8094)
|
||||
|
||||
*Preconditions*: *count* is greater than zero[.](#exec.simple.counting.mem-7.sentence-1)
|
||||
|
||||
[8](#exec.simple.counting.mem-8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8098)
|
||||
|
||||
*Effects*: Decrements *count*[.](#exec.simple.counting.mem-8.sentence-1)
|
||||
|
||||
If *count* is zero after decrementing and*state* is *open-and-joining* or *closed-and-joining*,
|
||||
changes *state* to *joined* and
|
||||
calls *complete*() on all objects registered with *this[.](#exec.simple.counting.mem-8.sentence-2)
|
||||
|
||||
[*Note [1](#exec.simple.counting.mem-note-1)*:
|
||||
|
||||
Calling *complete*() on any registered object
|
||||
can cause *this to be destroyed[.](#exec.simple.counting.mem-8.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[ð](#lib:start-join-sender,execution::simple_counting_scope)
|
||||
|
||||
`template<class State>
|
||||
bool start-join-sender(State& st) noexcept;
|
||||
`
|
||||
|
||||
[9](#exec.simple.counting.mem-9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8118)
|
||||
|
||||
*Effects*: If *state* is
|
||||
|
||||
- [(9.1)](#exec.simple.counting.mem-9.1)
|
||||
|
||||
*unused*, *unused-and-closed*, or *joined*, then
|
||||
changes *state* to *joined* and returns true;
|
||||
|
||||
- [(9.2)](#exec.simple.counting.mem-9.2)
|
||||
|
||||
*open* or *open-and-joining*, then
|
||||
changes *state* to *open-and-joining*,
|
||||
registers st with *this and returns false;
|
||||
|
||||
- [(9.3)](#exec.simple.counting.mem-9.3)
|
||||
|
||||
*closed* or *closed-and-joining*, then
|
||||
changes *state* to *closed-and-joining*,
|
||||
registers st with *this and returns false[.](#exec.simple.counting.mem-9.sentence-1)
|
||||
|
||||
#### [33.14.2.2.4](#exec.simple.counting.token) Token [[exec.simple.counting.token]](exec.simple.counting.token)
|
||||
|
||||
[ð](#lib:execution::simple_counting_scope::token)
|
||||
|
||||
namespace std::execution {struct simple_counting_scope::token {template<[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sender> Sender&& wrap(Sender&& snd) const noexcept; bool try_associate() const noexcept; void disassociate() const noexcept; private: simple_counting_scope* *scope*; // *exposition only*};}
|
||||
|
||||
[ð](#lib:wrap,execution::simple_counting_scope::token)
|
||||
|
||||
`template<[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sender>
|
||||
Sender&& wrap(Sender&& snd) const noexcept;
|
||||
`
|
||||
|
||||
[1](#exec.simple.counting.token-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8160)
|
||||
|
||||
*Returns*: std::forward<Sender>(snd)[.](#exec.simple.counting.token-1.sentence-1)
|
||||
|
||||
[ð](#lib:try_associate,execution::simple_counting_scope::token)
|
||||
|
||||
`bool try_associate() const noexcept;
|
||||
`
|
||||
|
||||
[2](#exec.simple.counting.token-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8171)
|
||||
|
||||
*Effects*: Equivalent to: return *scope*->*try-associate*();
|
||||
|
||||
[ð](#lib:disassociate,execution::simple_counting_scope::token)
|
||||
|
||||
`void disassociate() const noexcept;
|
||||
`
|
||||
|
||||
[3](#exec.simple.counting.token-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8182)
|
||||
|
||||
*Effects*: Equivalent to *scope*->*disassociate*()[.](#exec.simple.counting.token-3.sentence-1)
|
||||
|
||||
#### [33.14.2.3](#exec.scope.counting) Counting Scope [[exec.scope.counting]](exec.scope.counting)
|
||||
|
||||
[ð](#lib:execution::counting_scope)
|
||||
|
||||
namespace std::execution {class counting_scope {public:struct token {template<[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sender>[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") auto wrap(Sender&& snd) const noexcept(*see below*); bool try_associate() const noexcept; void disassociate() const noexcept; private: counting_scope* *scope*; // *exposition only*}; static constexpr size_t max_associations = *implementation-defined*;
|
||||
|
||||
counting_scope() noexcept;
|
||||
counting_scope(counting_scope&&) = delete; ~counting_scope();
|
||||
|
||||
token get_token() noexcept; void close() noexcept; [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") auto join() noexcept; void request_stop() noexcept; private: size_t *count*; // *exposition only**scope-state-type* *state*; // *exposition only* inplace_stop_source *s_source*; // *exposition only*bool *try-associate*() noexcept; // *exposition only*void *disassociate*() noexcept; // *exposition only*template<class State>bool *start-join-sender*(State& state) noexcept; // *exposition only*};}
|
||||
|
||||
[1](#exec.scope.counting-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8230)
|
||||
|
||||
counting_scope differs from simple_counting_scope by
|
||||
adding support for cancellation[.](#exec.scope.counting-1.sentence-1)
|
||||
|
||||
Unless specified below, the semantics of members of counting_scope are the same as the corresponding members of simple_counting_scope[.](#exec.scope.counting-1.sentence-2)
|
||||
|
||||
[ð](#lib:get_token,execution::counting_scope)
|
||||
|
||||
`token get_token() noexcept;
|
||||
`
|
||||
|
||||
[2](#exec.scope.counting-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8242)
|
||||
|
||||
*Returns*: An object t of type counting_scope::token such thatt.*scope* == this is true[.](#exec.scope.counting-2.sentence-1)
|
||||
|
||||
[ð](#lib:request_stop,execution::counting_scope)
|
||||
|
||||
`void request_stop() noexcept;
|
||||
`
|
||||
|
||||
[3](#exec.scope.counting-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8254)
|
||||
|
||||
*Effects*: Equivalent to *s_source*.request_stop()[.](#exec.scope.counting-3.sentence-1)
|
||||
|
||||
[4](#exec.scope.counting-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8258)
|
||||
|
||||
*Remarks*: Calls to request_stop do not introduce data races[.](#exec.scope.counting-4.sentence-1)
|
||||
|
||||
[ð](#lib:wrap,execution::counting_scope::token)
|
||||
|
||||
`template<[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sender>
|
||||
[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") auto counting_scope::token::wrap(Sender&& snd) const
|
||||
noexcept(is_nothrow_constructible_v<remove_cvref_t<Sender>, Sender>);
|
||||
`
|
||||
|
||||
[5](#exec.scope.counting-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8271)
|
||||
|
||||
*Effects*: Equivalent to:return *stop-when*(std::forward<Sender>(snd), *scope*->*s_source*.get_token());
|
||||
116
cppdraft/exec/counting/scopes/general.md
Normal file
116
cppdraft/exec/counting/scopes/general.md
Normal file
@@ -0,0 +1,116 @@
|
||||
[exec.counting.scopes.general]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.14 Execution scope utilities [[exec.scope]](exec.scope#exec.counting.scopes.general)
|
||||
|
||||
### 33.14.2 Counting Scopes [[exec.counting.scopes]](exec.counting.scopes#general)
|
||||
|
||||
#### 33.14.2.1 General [exec.counting.scopes.general]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7769)
|
||||
|
||||
Scopes of type simple_counting_scope and counting_scope maintain counts of associations[.](#1.sentence-1)
|
||||
|
||||
Let:
|
||||
|
||||
- [(1.1)](#1.1)
|
||||
|
||||
Scope be either simple_counting_scope or counting_scope,
|
||||
|
||||
- [(1.2)](#1.2)
|
||||
|
||||
scope be an object of type Scope,
|
||||
|
||||
- [(1.3)](#1.3)
|
||||
|
||||
tkn be an object of type Scope::token obtained from scope.get_token(),
|
||||
|
||||
- [(1.4)](#1.4)
|
||||
|
||||
jsndr be a sender obtained from scope.join(), and
|
||||
|
||||
- [(1.5)](#1.5)
|
||||
|
||||
op be an operation state obtained from
|
||||
connecting jsndr to a receiver[.](#1.sentence-2)
|
||||
|
||||
During its lifetime scope goes through different states
|
||||
which govern what operations are allowed and the result of these operations:
|
||||
|
||||
- [(1.6)](#1.6)
|
||||
|
||||
*unused*:
|
||||
a newly constructed object starts in the *unused* state[.](#1.6.sentence-1)
|
||||
|
||||
- [(1.7)](#1.7)
|
||||
|
||||
*open*:
|
||||
when tkn.try_associate() is called
|
||||
while scope is in the *unused* state,scope moves to the *open* state[.](#1.7.sentence-1)
|
||||
|
||||
- [(1.8)](#1.8)
|
||||
|
||||
*open-and-joining*:
|
||||
when the operation state op is started
|
||||
while scope is in the *unused* or *open* state,scope moves to the *open-and-joining* state[.](#1.8.sentence-1)
|
||||
|
||||
- [(1.9)](#1.9)
|
||||
|
||||
*closed*:
|
||||
when scope.close() is called
|
||||
while scope is in the *open* state,scope moves to the *closed* state[.](#1.9.sentence-1)
|
||||
|
||||
- [(1.10)](#1.10)
|
||||
|
||||
*unused-and-closed*:
|
||||
when scope.close() is called
|
||||
while scope is in the *unused* state,scope moves to the *unused-and-closed* state[.](#1.10.sentence-1)
|
||||
|
||||
- [(1.11)](#1.11)
|
||||
|
||||
*closed-and-joining*:
|
||||
when scope.close() is called
|
||||
while scope is in the *open-and-joining* state or
|
||||
the operation state op is started
|
||||
while scope is in
|
||||
the *closed* or *unused-and-closed* state,scope moves to the *closed-and-joining* state[.](#1.11.sentence-1)
|
||||
|
||||
- [(1.12)](#1.12)
|
||||
|
||||
*joined*:
|
||||
when the count of associations drops to zero
|
||||
while scope is in
|
||||
the *open-and-joining* or *closed-and-joining* state,scope moves to the *joined* state[.](#1.12.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7836)
|
||||
|
||||
*Recommended practice*: For simple_counting_scope and counting_scope,
|
||||
implementations should store the state and the count of associations
|
||||
in a single member of type size_t[.](#2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7842)
|
||||
|
||||
Subclause [[exec.counting.scopes]](exec.counting.scopes "33.14.2 Counting Scopes") makes use of
|
||||
the following exposition-only entities:
|
||||
|
||||
struct *scope-join-t* {}; // *exposition only*enum *scope-state-type* { // *exposition only**unused*, // *exposition only**open*, // *exposition only**closed*, // *exposition only**open-and-joining*, // *exposition only**closed-and-joining*, // *exposition only**unused-and-closed*, // *exposition only**joined*, // *exposition only*};
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7860)
|
||||
|
||||
The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
|
||||
is specialized for *scope-join-t* as follows:
|
||||
|
||||
namespace std::execution {template<>struct *impls-for*<*scope-join-t*> : *default-impls* {template<class Scope, class Rcvr>struct *state* { // *exposition only*struct *rcvr-t* { // *exposition only*using receiver_concept = receiver_t;
|
||||
|
||||
Rcvr& *rcvr*; // *exposition only*void set_value() && noexcept { execution::set_value(std::move(*rcvr*)); }template<class E>void set_error(E&& e) && noexcept { execution::set_error(std::move(*rcvr*), std::forward<E>(e)); }void set_stopped() && noexcept { execution::set_stopped(std::move(*rcvr*)); }decltype(auto) get_env() const noexcept {return execution::get_env(*rcvr*); }}; using *sched-sender* = // *exposition only*decltype(schedule(get_scheduler(get_env(declval<Rcvr&>())))); using *op-t* = // *exposition only* connect_result_t<*sched-sender*, *rcvr-t*>;
|
||||
|
||||
Scope* *scope*; // *exposition only* Rcvr& *receiver*; // *exposition only**op-t* *op*; // *exposition only**state*(Scope* scope, Rcvr& rcvr) // *exposition only*noexcept([*nothrow-callable*](functional.syn#concept:nothrow-callable "22.10.2 Header <functional> synopsis [functional.syn]")<connect_t, *sched-sender*, *rcvr-t*>): *scope*(scope), *receiver*(rcvr), *op*(connect(schedule(get_scheduler(get_env(rcvr))), *rcvr-t*(rcvr))) {}void *complete*() noexcept { // *exposition only* start(*op*); }void *complete-inline*() noexcept { // *exposition only* set_value(std::move(*receiver*)); }}; static constexpr auto *get-state* = // *exposition only*[]<class Rcvr>(auto&& sender, Rcvr& receiver)noexcept(is_nothrow_constructible_v<*state*<Rcvr>, *data-type*<decltype(sender)>, Rcvr&>) {auto[_, self] = sender; return *state*(self, receiver); }; static constexpr auto *start* = // *exposition only*[](auto& s, auto&) noexcept {if (s.*scope*->*start-join-sender*(s)) s.*complete-inline*(); }; };}
|
||||
298
cppdraft/exec/ctx.md
Normal file
298
cppdraft/exec/ctx.md
Normal file
@@ -0,0 +1,298 @@
|
||||
[exec.ctx]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.12 Execution contexts [exec.ctx]
|
||||
|
||||
### [33.12.1](#exec.run.loop) execution::run_loop [[exec.run.loop]](exec.run.loop)
|
||||
|
||||
#### [33.12.1.1](#exec.run.loop.general) General [[exec.run.loop.general]](exec.run.loop.general)
|
||||
|
||||
[1](#exec.run.loop.general-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6321)
|
||||
|
||||
A run_loop is an execution resource on which work can be scheduled[.](#exec.run.loop.general-1.sentence-1)
|
||||
|
||||
It maintains a thread-safe first-in-first-out queue of work[.](#exec.run.loop.general-1.sentence-2)
|
||||
|
||||
Its run member function removes elements from the queue and
|
||||
executes them in a loop on the thread of execution that calls run[.](#exec.run.loop.general-1.sentence-3)
|
||||
|
||||
[2](#exec.run.loop.general-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6327)
|
||||
|
||||
A run_loop instance has an associated [*count*](#def:count "33.12.1.1 General [exec.run.loop.general]") that corresponds to the number of work items that are in its queue[.](#exec.run.loop.general-2.sentence-1)
|
||||
|
||||
Additionally, a run_loop instance has an associated state
|
||||
that can be one of[*starting*](#def:starting "33.12.1.1 General [exec.run.loop.general]"), [*running*](#def:running "33.12.1.1 General [exec.run.loop.general]"), [*finishing*](#def:finishing "33.12.1.1 General [exec.run.loop.general]"), or [*finished*](#def:finished "33.12.1.1 General [exec.run.loop.general]")[.](#exec.run.loop.general-2.sentence-2)
|
||||
|
||||
[3](#exec.run.loop.general-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6334)
|
||||
|
||||
Concurrent invocations of the member functions of run_loop other than run and its destructor do not introduce data races[.](#exec.run.loop.general-3.sentence-1)
|
||||
|
||||
The member functions*pop-front*, *push-back*, and finish execute atomically[.](#exec.run.loop.general-3.sentence-2)
|
||||
|
||||
[4](#exec.run.loop.general-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6341)
|
||||
|
||||
*Recommended practice*: Implementations should use an intrusive queue of operation states
|
||||
to hold the work units to make scheduling allocation-free[.](#exec.run.loop.general-4.sentence-1)
|
||||
|
||||
namespace std::execution {class [run_loop](#lib:run_loop "33.12.1.1 General [exec.run.loop.general]") {// [[exec.run.loop.types]](#exec.run.loop.types "33.12.1.2 Associated types"), associated typesclass *run-loop-scheduler*; // *exposition only*class *run-loop-sender*; // *exposition only*struct *run-loop-opstate-base* { // *exposition only*virtual void *execute*() = 0; // *exposition only* run_loop* *loop*; // *exposition only**run-loop-opstate-base** *next*; // *exposition only*}; template<class Rcvr>using *run-loop-opstate* = *unspecified*; // *exposition only*// [[exec.run.loop.members]](#exec.run.loop.members "33.12.1.4 Member functions"), member functions*run-loop-opstate-base** *pop-front*(); // *exposition only*void *push-back*(*run-loop-opstate-base**); // *exposition only*public:// [[exec.run.loop.ctor]](#exec.run.loop.ctor "33.12.1.3 Constructor and destructor"), constructor and destructor run_loop() noexcept;
|
||||
run_loop(run_loop&&) = delete; ~run_loop(); // [[exec.run.loop.members]](#exec.run.loop.members "33.12.1.4 Member functions"), member functions*run-loop-scheduler* get_scheduler(); void run(); void finish(); };}
|
||||
|
||||
#### [33.12.1.2](#exec.run.loop.types) Associated types [[exec.run.loop.types]](exec.run.loop.types)
|
||||
|
||||
[ð](#exec.run.loop.types-itemdecl:1)
|
||||
|
||||
`class run-loop-scheduler;
|
||||
`
|
||||
|
||||
[1](#exec.run.loop.types-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6384)
|
||||
|
||||
*run-loop-scheduler* is an unspecified type
|
||||
that models [scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]")[.](#exec.run.loop.types-1.sentence-1)
|
||||
|
||||
[2](#exec.run.loop.types-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6388)
|
||||
|
||||
Instances of *run-loop-scheduler* remain valid
|
||||
until the end of the lifetime of the run_loop instance
|
||||
from which they were obtained[.](#exec.run.loop.types-2.sentence-1)
|
||||
|
||||
[3](#exec.run.loop.types-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6393)
|
||||
|
||||
Two instances of *run-loop-scheduler* compare equal
|
||||
if and only if they were obtained from the same run_loop instance[.](#exec.run.loop.types-3.sentence-1)
|
||||
|
||||
[4](#exec.run.loop.types-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6397)
|
||||
|
||||
Let *sch* be an expression of type *run-loop-scheduler*[.](#exec.run.loop.types-4.sentence-1)
|
||||
|
||||
The expression schedule(*sch*) has type *run-loop-
|
||||
sender* and
|
||||
is not potentially-throwing if *sch* is not potentially-throwing[.](#exec.run.loop.types-4.sentence-2)
|
||||
|
||||
[ð](#exec.run.loop.types-itemdecl:2)
|
||||
|
||||
`class run-loop-sender;
|
||||
`
|
||||
|
||||
[5](#exec.run.loop.types-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6407)
|
||||
|
||||
*run-loop-sender* is an exposition-only type
|
||||
that satisfies [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]")[.](#exec.run.loop.types-5.sentence-1)
|
||||
|
||||
completion_signatures_of_t<*run-
|
||||
loop-sender*> iscompletion_signatures<set_value_t(), set_error_t(exception_ptr), set_stopped_t()>
|
||||
|
||||
[6](#exec.run.loop.types-6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6415)
|
||||
|
||||
An instance of *run-loop-sender* remains valid
|
||||
until the end of the lifetime of its associated run_loop instance[.](#exec.run.loop.types-6.sentence-1)
|
||||
|
||||
[7](#exec.run.loop.types-7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6419)
|
||||
|
||||
Let *sndr* be an expression of type *run-loop-sender*,
|
||||
let *rcvr* be an expression
|
||||
such that [receiver_of](exec.recv.concepts#concept:receiver_of "33.7.1 Receiver concepts [exec.recv.concepts]")<decltype((*rcvr*)), CS> is true where CS is the completion_signatures specialization above[.](#exec.run.loop.types-7.sentence-1)
|
||||
|
||||
Let C be either set_value_t or set_stopped_t[.](#exec.run.loop.types-7.sentence-2)
|
||||
|
||||
Then:
|
||||
|
||||
- [(7.1)](#exec.run.loop.types-7.1)
|
||||
|
||||
The expression connect(*sndr*, *rcvr*) has type *run-loop-opstate*<decay_t<decltype((*rcvr*))>> and is potentially-throwing if and only if(void(*sndr*), auto(*rcvr*)) is potentially-throwing[.](#exec.run.loop.types-7.1.sentence-1)
|
||||
|
||||
- [(7.2)](#exec.run.loop.types-7.2)
|
||||
|
||||
The expression get_completion_scheduler<C>(get_env(*sndr*)) is potentially-throwing if and only if *sndr* is potentially-throwing,
|
||||
has type *run-loop-scheduler*, and
|
||||
compares equal to the *run-loop-
|
||||
scheduler* instance
|
||||
from which *sndr* was obtained[.](#exec.run.loop.types-7.2.sentence-1)
|
||||
|
||||
[ð](#exec.run.loop.types-itemdecl:3)
|
||||
|
||||
`template<class Rcvr>
|
||||
struct run-loop-opstate;
|
||||
`
|
||||
|
||||
[8](#exec.run.loop.types-8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6445)
|
||||
|
||||
*run-loop-opstate*<Rcvr> inherits privately and unambiguously from *run-loop-opstate-base*[.](#exec.run.loop.types-8.sentence-1)
|
||||
|
||||
[9](#exec.run.loop.types-9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6449)
|
||||
|
||||
Let o be a non-const lvalue of type *run-loop-opstate*<Rcvr>,
|
||||
and let REC(o) be a non-const lvalue reference to an instance of type Rcvr that was initialized with the expression *rcvr* passed to the invocation of connect that returned o[.](#exec.run.loop.types-9.sentence-1)
|
||||
|
||||
Then:
|
||||
|
||||
- [(9.1)](#exec.run.loop.types-9.1)
|
||||
|
||||
The object to which *REC*(o) refers
|
||||
remains valid for the lifetime of the object to which o refers.
|
||||
|
||||
- [(9.2)](#exec.run.loop.types-9.2)
|
||||
|
||||
The type *run-loop-opstate*<Rcvr> overrides*run-loop-opstate-base*::*execute*() such that o.*execute*() is equivalent to:if (get_stop_token(*REC*(o)).stop_requested()) { set_stopped(std::move(*REC*(o)));} else { set_value(std::move(*REC*(o)));}
|
||||
|
||||
- [(9.3)](#exec.run.loop.types-9.3)
|
||||
|
||||
The expression start(o) is equivalent to:try {o.*loop*->*push-back*(addressof(o));} catch(...) { set_error(std::move(*REC*(o)), current_exception());}
|
||||
|
||||
#### [33.12.1.3](#exec.run.loop.ctor) Constructor and destructor [[exec.run.loop.ctor]](exec.run.loop.ctor)
|
||||
|
||||
[ð](#lib:run_loop,constructor)
|
||||
|
||||
`run_loop() noexcept;
|
||||
`
|
||||
|
||||
[1](#exec.run.loop.ctor-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6489)
|
||||
|
||||
*Postconditions*: *count* is 0 and *state* is *starting*[.](#exec.run.loop.ctor-1.sentence-1)
|
||||
|
||||
[ð](#lib:run_loop,destructor)
|
||||
|
||||
`~run_loop();
|
||||
`
|
||||
|
||||
[2](#exec.run.loop.ctor-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6500)
|
||||
|
||||
*Effects*: If *count* is not 0 or if *state* is *running*,
|
||||
invokes terminate ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#exec.run.loop.ctor-2.sentence-1)
|
||||
|
||||
Otherwise, has no effects[.](#exec.run.loop.ctor-2.sentence-2)
|
||||
|
||||
#### [33.12.1.4](#exec.run.loop.members) Member functions [[exec.run.loop.members]](exec.run.loop.members)
|
||||
|
||||
[ð](#exec.run.loop.members-itemdecl:1)
|
||||
|
||||
`run-loop-opstate-base* pop-front();
|
||||
`
|
||||
|
||||
[1](#exec.run.loop.members-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6514)
|
||||
|
||||
*Effects*: Blocks ([[defns.block]](defns.block "3.6 block")) until one of the following conditions is true:
|
||||
|
||||
- [(1.1)](#exec.run.loop.members-1.1)
|
||||
|
||||
*count* is 0 and *state* is *finishing*,
|
||||
in which case *pop-front* sets *state* to *finished* and returns nullptr; or
|
||||
|
||||
- [(1.2)](#exec.run.loop.members-1.2)
|
||||
|
||||
*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[.](#exec.run.loop.members-1.sentence-1)
|
||||
|
||||
[ð](#exec.run.loop.members-itemdecl:2)
|
||||
|
||||
`void push-back(run-loop-opstate-base* item);
|
||||
`
|
||||
|
||||
[2](#exec.run.loop.members-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6535)
|
||||
|
||||
*Effects*: Adds item to the back of the queue and
|
||||
increments *count* by 1[.](#exec.run.loop.members-2.sentence-1)
|
||||
|
||||
[3](#exec.run.loop.members-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6540)
|
||||
|
||||
*Synchronization*: This operation synchronizes with
|
||||
the *pop-front* operation that obtains item[.](#exec.run.loop.members-3.sentence-1)
|
||||
|
||||
[ð](#lib:get_scheduler,run_loop)
|
||||
|
||||
`run-loop-scheduler get_scheduler();
|
||||
`
|
||||
|
||||
[4](#exec.run.loop.members-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6552)
|
||||
|
||||
*Returns*: An instance of *run-loop-scheduler* that can be used to schedule work onto this run_loop instance[.](#exec.run.loop.members-4.sentence-1)
|
||||
|
||||
[ð](#lib:run,run_loop)
|
||||
|
||||
`void run();
|
||||
`
|
||||
|
||||
[5](#exec.run.loop.members-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6564)
|
||||
|
||||
*Preconditions*: *state* is either *starting* or *finishing*[.](#exec.run.loop.members-5.sentence-1)
|
||||
|
||||
[6](#exec.run.loop.members-6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6568)
|
||||
|
||||
*Effects*: If *state* is *starting*,
|
||||
sets the *state* to *running*,
|
||||
otherwise leaves *state* unchanged[.](#exec.run.loop.members-6.sentence-1)
|
||||
|
||||
Then, equivalent to:while (auto* op = *pop-front*()) { op->*execute*();}
|
||||
|
||||
[7](#exec.run.loop.members-7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6580)
|
||||
|
||||
*Remarks*: When *state* changes, it does so without introducing data races[.](#exec.run.loop.members-7.sentence-1)
|
||||
|
||||
[ð](#lib:finish,run_loop)
|
||||
|
||||
`void finish();
|
||||
`
|
||||
|
||||
[8](#exec.run.loop.members-8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6591)
|
||||
|
||||
*Preconditions*: *state* is either *starting* or *running*[.](#exec.run.loop.members-8.sentence-1)
|
||||
|
||||
[9](#exec.run.loop.members-9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6595)
|
||||
|
||||
*Effects*: Changes *state* to *finishing*[.](#exec.run.loop.members-9.sentence-1)
|
||||
|
||||
[10](#exec.run.loop.members-10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6599)
|
||||
|
||||
*Synchronization*: finish synchronizes with the *pop-front* operation
|
||||
that returns nullptr[.](#exec.run.loop.members-10.sentence-1)
|
||||
96
cppdraft/exec/domain/default.md
Normal file
96
cppdraft/exec/domain/default.md
Normal file
@@ -0,0 +1,96 @@
|
||||
[exec.domain.default]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#exec.domain.default)
|
||||
|
||||
### 33.9.5 execution::default_domain [exec.domain.default]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2425)
|
||||
|
||||
namespace std::execution {struct [default_domain](#lib:default_domain "33.9.5 execution::default_domain [exec.domain.default]") {template<[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sndr, [*queryable*](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]")... Env>requires (sizeof...(Env) <= 1)static constexpr [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") decltype(auto) transform_sender(Sndr&& sndr, const Env&... env)noexcept(*see below*); template<[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sndr, [*queryable*](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]") Env>static constexpr [*queryable*](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]") decltype(auto) transform_env(Sndr&& sndr, Env&& env) noexcept; template<class Tag, [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sndr, class... Args>static constexpr decltype(auto) apply_sender(Tag, Sndr&& sndr, Args&&... args)noexcept(*see below*); };}
|
||||
|
||||
[ð](#lib:transform_sender,default_domain)
|
||||
|
||||
`template<[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sndr, [queryable](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]")... Env>
|
||||
requires (sizeof...(Env) <= 1)
|
||||
constexpr [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") decltype(auto) transform_sender(Sndr&& sndr, const Env&... env)
|
||||
noexcept(see below);
|
||||
`
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2453)
|
||||
|
||||
Let e be the expressiontag_of_t<Sndr>().transform_sender(std::forward<Sndr>(sndr), env...) if that expression is well-formed;
|
||||
otherwise, std::forward<Sndr>(sndr)[.](#2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2461)
|
||||
|
||||
*Returns*: e[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2465)
|
||||
|
||||
*Remarks*: The exception specification is equivalent to noexcept(e)[.](#4.sentence-1)
|
||||
|
||||
[ð](#lib:transform_env,default_domain)
|
||||
|
||||
`template<[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sndr, [queryable](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]") Env>
|
||||
constexpr [queryable](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]") decltype(auto) transform_env(Sndr&& sndr, Env&& env) noexcept;
|
||||
`
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2477)
|
||||
|
||||
Let e be the expressiontag_of_t<Sndr>().transform_env(std::forward<Sndr>(sndr), std::forward<Env>(env)) if that expression is well-formed;
|
||||
otherwise, *FWD-ENV*(std::forward<Env>(env))[.](#5.sentence-1)
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2485)
|
||||
|
||||
*Mandates*: noexcept(e) is true[.](#6.sentence-1)
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2489)
|
||||
|
||||
*Returns*: e[.](#7.sentence-1)
|
||||
|
||||
[ð](#lib:apply_sender,default_domain)
|
||||
|
||||
`template<class Tag, [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sndr, class... Args>
|
||||
constexpr decltype(auto) apply_sender(Tag, Sndr&& sndr, Args&&... args)
|
||||
noexcept(see below);
|
||||
`
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2502)
|
||||
|
||||
Let e be the expression Tag().apply_sender(std::forward<Sndr>(sndr), std::forward<Args>(args)...)
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2508)
|
||||
|
||||
*Constraints*: e is a well-formed expression[.](#9.sentence-1)
|
||||
|
||||
[10](#10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2512)
|
||||
|
||||
*Returns*: e[.](#10.sentence-1)
|
||||
|
||||
[11](#11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2516)
|
||||
|
||||
*Remarks*: The exception specification is equivalent to noexcept(e)[.](#11.sentence-1)
|
||||
80
cppdraft/exec/env.md
Normal file
80
cppdraft/exec/env.md
Normal file
@@ -0,0 +1,80 @@
|
||||
[exec.env]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.11 Queryable utilities [[exec.envs]](exec.envs#exec.env)
|
||||
|
||||
### 33.11.2 Class template env [exec.env]
|
||||
|
||||
namespace std::execution {template<[*queryable*](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]")... Envs>struct [env](#lib:env "33.11.2 Class template env [exec.env]") { Envs0 envs0; // *exposition only* Envs1 envs1; // *exposition only* ⋮
|
||||
Envsnâ1 envsnâ1; // *exposition only*template<class QueryTag>constexpr decltype(auto) query(QueryTag q) const noexcept(*see below*); }; template<class... Envs> env(Envs...) -> env<unwrap_reference_t<Envs>...>;}
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6246)
|
||||
|
||||
The class template env is used to construct a queryable object
|
||||
from several queryable objects[.](#1.sentence-1)
|
||||
|
||||
Query invocations on the resulting object are resolved
|
||||
by attempting to query each subobject in lexical order[.](#1.sentence-2)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6252)
|
||||
|
||||
Specializations of env are not assignable[.](#2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6255)
|
||||
|
||||
It is unspecified
|
||||
whether env supports initialization
|
||||
using a parenthesized [*expression-list*](expr.post.general#nt:expression-list "7.6.1.1 General [expr.post.general]") ([[dcl.init]](dcl.init "9.5 Initializers")),
|
||||
unless the [*expression-list*](expr.post.general#nt:expression-list "7.6.1.1 General [expr.post.general]") consist of
|
||||
a single element of type (possibly const) env[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6262)
|
||||
|
||||
[*Example [1](#example-1)*: template<[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sndr> sender auto parameterize_work(Sndr sndr) {// Make an environment such that:// get_allocator(env) returns a reference to a copy of my_alloc{}// get_scheduler(env) returns a reference to a copy of my_sched{}auto e = env{prop(get_allocator, my_alloc{}),
|
||||
prop(get_scheduler, my_sched{})}; // Parameterize the input sender so that it will use our custom execution environment.return write_env(sndr, e);} â *end example*]
|
||||
|
||||
[ð](#lib:query,env)
|
||||
|
||||
`template<class QueryTag>
|
||||
constexpr decltype(auto) query(QueryTag q) const noexcept(see below);
|
||||
`
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6286)
|
||||
|
||||
Let [*has-query*](#concept:has-query "33.11.2 Class template env [exec.env]") be the following exposition-only concept:template<class Env, class QueryTag>concept [*has-query*](#concept:has-query "33.11.2 Class template env [exec.env]") = // *exposition only*requires (const Env& env) { env.query(QueryTag()); };
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6296)
|
||||
|
||||
Let *fe* be the first element ofenvs0, envs1, …, envsnâ1 such that the expression *fe*.query(q) is well-formed[.](#6.sentence-1)
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6301)
|
||||
|
||||
*Constraints*: ([*has-query*](#concept:has-query "33.11.2 Class template env [exec.env]")<Envs, QueryTag> || ...) is true[.](#7.sentence-1)
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6305)
|
||||
|
||||
*Effects*: Equivalent to: return *fe*.query(q);
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6309)
|
||||
|
||||
*Remarks*: The expression in the noexcept clause is equivalent
|
||||
to noexcept(*fe*.query(q))[.](#9.sentence-1)
|
||||
110
cppdraft/exec/envs.md
Normal file
110
cppdraft/exec/envs.md
Normal file
@@ -0,0 +1,110 @@
|
||||
[exec.envs]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.11 Queryable utilities [exec.envs]
|
||||
|
||||
### [33.11.1](#exec.prop) Class template prop [[exec.prop]](exec.prop)
|
||||
|
||||
namespace std::execution {template<class QueryTag, class ValueType>struct [prop](#lib:prop "33.11.1 Class template prop [exec.prop]") { QueryTag *query_*; // *exposition only* ValueType *value_*; // *exposition only*constexpr const ValueType& query(QueryTag) const noexcept {return *value_*; }}; template<class QueryTag, class ValueType> prop(QueryTag, ValueType) -> prop<QueryTag, unwrap_reference_t<ValueType>>;}
|
||||
|
||||
[1](#exec.prop-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6193)
|
||||
|
||||
Class template prop is for building a queryable object
|
||||
from a query object and a value[.](#exec.prop-1.sentence-1)
|
||||
|
||||
[2](#exec.prop-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6197)
|
||||
|
||||
*Mandates*: [*callable*](functional.syn#concept:callable "22.10.2 Header <functional> synopsis [functional.syn]")<QueryTag, *prop-like*<ValueType>> is modeled,
|
||||
where *prop-like* is the following exposition-only class template:template<class ValueType>struct *prop-like* { // *exposition only*const ValueType& query(auto) const noexcept;};
|
||||
|
||||
[3](#exec.prop-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6209)
|
||||
|
||||
[*Example [1](#exec.prop-example-1)*: template<[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sndr> sender auto parameterize_work(Sndr sndr) {// Make an environment such that get_allocator(env) returns a reference to a copy of my_alloc{}.auto e = prop(get_allocator, my_alloc{}); // Parameterize the input sender so that it will use our custom execution environment.return write_env(sndr, e);} â *end example*]
|
||||
|
||||
[4](#exec.prop-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6223)
|
||||
|
||||
Specializations of prop are not assignable[.](#exec.prop-4.sentence-1)
|
||||
|
||||
### [33.11.2](#exec.env) Class template env [[exec.env]](exec.env)
|
||||
|
||||
namespace std::execution {template<[*queryable*](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]")... Envs>struct [env](#lib:env "33.11.2 Class template env [exec.env]") { Envs0 envs0; // *exposition only* Envs1 envs1; // *exposition only* ⋮
|
||||
Envsnâ1 envsnâ1; // *exposition only*template<class QueryTag>constexpr decltype(auto) query(QueryTag q) const noexcept(*see below*); }; template<class... Envs> env(Envs...) -> env<unwrap_reference_t<Envs>...>;}
|
||||
|
||||
[1](#exec.env-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6246)
|
||||
|
||||
The class template env is used to construct a queryable object
|
||||
from several queryable objects[.](#exec.env-1.sentence-1)
|
||||
|
||||
Query invocations on the resulting object are resolved
|
||||
by attempting to query each subobject in lexical order[.](#exec.env-1.sentence-2)
|
||||
|
||||
[2](#exec.env-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6252)
|
||||
|
||||
Specializations of env are not assignable[.](#exec.env-2.sentence-1)
|
||||
|
||||
[3](#exec.env-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6255)
|
||||
|
||||
It is unspecified
|
||||
whether env supports initialization
|
||||
using a parenthesized [*expression-list*](expr.post.general#nt:expression-list "7.6.1.1 General [expr.post.general]") ([[dcl.init]](dcl.init "9.5 Initializers")),
|
||||
unless the [*expression-list*](expr.post.general#nt:expression-list "7.6.1.1 General [expr.post.general]") consist of
|
||||
a single element of type (possibly const) env[.](#exec.env-3.sentence-1)
|
||||
|
||||
[4](#exec.env-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6262)
|
||||
|
||||
[*Example [1](#exec.env-example-1)*: template<[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sndr> sender auto parameterize_work(Sndr sndr) {// Make an environment such that:// get_allocator(env) returns a reference to a copy of my_alloc{}// get_scheduler(env) returns a reference to a copy of my_sched{}auto e = env{prop(get_allocator, my_alloc{}),
|
||||
prop(get_scheduler, my_sched{})}; // Parameterize the input sender so that it will use our custom execution environment.return write_env(sndr, e);} â *end example*]
|
||||
|
||||
[ð](#lib:query,env)
|
||||
|
||||
`template<class QueryTag>
|
||||
constexpr decltype(auto) query(QueryTag q) const noexcept(see below);
|
||||
`
|
||||
|
||||
[5](#exec.env-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6286)
|
||||
|
||||
Let [*has-query*](#concept:has-query "33.11.2 Class template env [exec.env]") be the following exposition-only concept:template<class Env, class QueryTag>concept [*has-query*](#concept:has-query "33.11.2 Class template env [exec.env]") = // *exposition only*requires (const Env& env) { env.query(QueryTag()); };
|
||||
|
||||
[6](#exec.env-6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6296)
|
||||
|
||||
Let *fe* be the first element ofenvs0, envs1, …, envsnâ1 such that the expression *fe*.query(q) is well-formed[.](#exec.env-6.sentence-1)
|
||||
|
||||
[7](#exec.env-7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6301)
|
||||
|
||||
*Constraints*: ([*has-query*](#concept:has-query "33.11.2 Class template env [exec.env]")<Envs, QueryTag> || ...) is true[.](#exec.env-7.sentence-1)
|
||||
|
||||
[8](#exec.env-8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6305)
|
||||
|
||||
*Effects*: Equivalent to: return *fe*.query(q);
|
||||
|
||||
[9](#exec.env-9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6309)
|
||||
|
||||
*Remarks*: The expression in the noexcept clause is equivalent
|
||||
to noexcept(*fe*.query(q))[.](#exec.env-9.sentence-1)
|
||||
134
cppdraft/exec/factories.md
Normal file
134
cppdraft/exec/factories.md
Normal file
@@ -0,0 +1,134 @@
|
||||
[exec.factories]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#exec.factories)
|
||||
|
||||
### 33.9.11 Sender factories [exec.factories]
|
||||
|
||||
#### [33.9.11.1](#exec.schedule) execution::schedule [[exec.schedule]](exec.schedule)
|
||||
|
||||
[1](#exec.schedule-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2877)
|
||||
|
||||
schedule obtains a schedule sender ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations"))
|
||||
from a scheduler[.](#exec.schedule-1.sentence-1)
|
||||
|
||||
[2](#exec.schedule-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2881)
|
||||
|
||||
The name schedule denotes a customization point object[.](#exec.schedule-2.sentence-1)
|
||||
|
||||
For a subexpression sch,
|
||||
the expression schedule(sch) is expression-equivalent tosch.schedule()[.](#exec.schedule-2.sentence-2)
|
||||
|
||||
[3](#exec.schedule-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2887)
|
||||
|
||||
*Mandates*: The type of sch.schedule() satisfies [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]")[.](#exec.schedule-3.sentence-1)
|
||||
|
||||
[4](#exec.schedule-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2891)
|
||||
|
||||
If the expressionget_completion_scheduler<set_value_t>(get_env(sch.schedule())) == sch is ill-formed or evaluates to false,
|
||||
the behavior of calling schedule(sch) is undefined[.](#exec.schedule-4.sentence-1)
|
||||
|
||||
#### [33.9.11.2](#exec.just) execution::just, execution::just_error, execution::just_stopped [[exec.just]](exec.just)
|
||||
|
||||
[1](#exec.just-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2901)
|
||||
|
||||
just, just_error, and just_stopped are sender factories
|
||||
whose asynchronous operations complete synchronously in their start operation
|
||||
with a value completion operation,
|
||||
an error completion operation, or
|
||||
a stopped completion operation, respectively[.](#exec.just-1.sentence-1)
|
||||
|
||||
[2](#exec.just-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2908)
|
||||
|
||||
The names just, just_error, and just_stopped denote
|
||||
customization point objects[.](#exec.just-2.sentence-1)
|
||||
|
||||
Let *just-cpo* be one ofjust, just_error, or just_stopped[.](#exec.just-2.sentence-2)
|
||||
|
||||
For a pack of subexpressions ts,
|
||||
let Ts be the pack of types decltype((ts))[.](#exec.just-2.sentence-3)
|
||||
|
||||
The expression *just-cpo*(ts...) is ill-formed if
|
||||
|
||||
- [(2.1)](#exec.just-2.1)
|
||||
|
||||
([*movable-value*](exec.general#concept:movable-value "33.1 General [exec.general]")<Ts> &&...) is false, or
|
||||
|
||||
- [(2.2)](#exec.just-2.2)
|
||||
|
||||
*just-cpo* is just_error andsizeof...(ts) == 1 is false, or
|
||||
|
||||
- [(2.3)](#exec.just-2.3)
|
||||
|
||||
*just-cpo* is just_stopped andsizeof...(ts) == 0 is false[.](#exec.just-2.sentence-4)
|
||||
|
||||
Otherwise, it is expression-equivalent to*make-sender*(*just-cpo*, *product-type*{ts...})[.](#exec.just-2.sentence-5)
|
||||
|
||||
For just, just_error, and just_stopped,
|
||||
let *set-cpo* beset_value, set_error, and set_stopped, respectively[.](#exec.just-2.sentence-6)
|
||||
|
||||
The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
|
||||
is specialized for *just-cpo* as follows:namespace std::execution {template<>struct *impls-for*<*decayed-typeof*<*just-cpo*>> : *default-impls* {static constexpr auto *start* =[](auto& state, auto& rcvr) noexcept -> void {auto& [...ts] = state; *set-cpo*(std::move(rcvr), std::move(ts)...); }; };}
|
||||
|
||||
#### [33.9.11.3](#exec.read.env) execution::read_env [[exec.read.env]](exec.read.env)
|
||||
|
||||
[1](#exec.read.env-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2950)
|
||||
|
||||
read_env is a sender factory for a sender
|
||||
whose asynchronous operation completes synchronously in its start operation
|
||||
with a value completion result equal to
|
||||
a value read from the receiver's associated environment[.](#exec.read.env-1.sentence-1)
|
||||
|
||||
[2](#exec.read.env-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2956)
|
||||
|
||||
read_env is a customization point object[.](#exec.read.env-2.sentence-1)
|
||||
|
||||
For some query object q,
|
||||
the expression read_env(q) is expression-equivalent to*make-sender*(read_env, q)[.](#exec.read.env-2.sentence-2)
|
||||
|
||||
[3](#exec.read.env-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2962)
|
||||
|
||||
The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
|
||||
is specialized for read_env as follows:
|
||||
|
||||
[ð](#lib:impls-for%3cdecayed-typeof%3cread_env%3e%3e)
|
||||
|
||||
namespace std::execution {template<>struct *impls-for*<*decayed-typeof*<read_env>> : *default-impls* {static constexpr auto start =[](auto query, auto& rcvr) noexcept -> void {*TRY-SET-VALUE*(rcvr, query(get_env(rcvr))); }; }; template<class Sndr, class Env>static consteval void *check-types*();}
|
||||
|
||||
[ð](#lib:check-types,impls-for%3cdecayed-typeof%3cread_env%3e%3e)
|
||||
|
||||
`template<class Sndr, class Env>
|
||||
static consteval void check-types();
|
||||
`
|
||||
|
||||
[4](#exec.read.env-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2988)
|
||||
|
||||
Let Q be decay_t<*data-type*<Sndr>>[.](#exec.read.env-4.sentence-1)
|
||||
|
||||
[5](#exec.read.env-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2991)
|
||||
|
||||
*Throws*: An exception of an unspecified type derived from exception if
|
||||
the expression Q()(env) is ill-formed or has type void, whereenv is an lvalue subexpression whose type is Env[.](#exec.read.env-5.sentence-1)
|
||||
36
cppdraft/exec/fwd/env.md
Normal file
36
cppdraft/exec/fwd/env.md
Normal file
@@ -0,0 +1,36 @@
|
||||
[exec.fwd.env]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.5 Queries [[exec.queries]](exec.queries#exec.fwd.env)
|
||||
|
||||
### 33.5.1 forwarding_query [exec.fwd.env]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L837)
|
||||
|
||||
forwarding_query asks a query object
|
||||
whether it should be forwarded through queryable adaptors[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L841)
|
||||
|
||||
The name forwarding_query denotes a query object[.](#2.sentence-1)
|
||||
|
||||
For some query object q of type Q,forwarding_query(q) is expression-equivalent to:
|
||||
|
||||
- [(2.1)](#2.1)
|
||||
|
||||
*MANDATE-NOTHROW*(q.query(forwarding_query)) if that expression is well-formed[.](#2.1.sentence-1)
|
||||
*Mandates*: The expression above has type bool and
|
||||
is a core constant expression if q is a core constant expression[.](#2.1.sentence-2)
|
||||
|
||||
- [(2.2)](#2.2)
|
||||
|
||||
Otherwise, true if [derived_from](concept.derived#concept:derived_from "18.4.3 Concept derived_from [concept.derived]")<Q, forwarding_query_t> is true[.](#2.2.sentence-1)
|
||||
|
||||
- [(2.3)](#2.3)
|
||||
|
||||
Otherwise, false[.](#2.3.sentence-1)
|
||||
103
cppdraft/exec/general.md
Normal file
103
cppdraft/exec/general.md
Normal file
@@ -0,0 +1,103 @@
|
||||
[exec.general]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.1 General [exec.general]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6)
|
||||
|
||||
This Clause describes components
|
||||
supporting execution of function objects ([[function.objects]](function.objects "22.10 Function objects"))[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L10)
|
||||
|
||||
The following subclauses describe
|
||||
the requirements, concepts, and components
|
||||
for execution control primitives as summarized in Table [157](#tab:exec.summary "Table 157: Execution control library summary")[.](#2.sentence-1)
|
||||
|
||||
Table [157](#tab:exec.summary) — Execution control library summary [[tab:exec.summary]](./tab:exec.summary)
|
||||
|
||||
| [ð](#tab:exec.summary-row-1) | **Subclause** | **Header** |
|
||||
| --- | --- | --- |
|
||||
| [ð](#tab:exec.summary-row-2)<br>[[exec.sched]](exec.sched "33.6 Schedulers") | Schedulers | <execution> |
|
||||
| [ð](#tab:exec.summary-row-3)<br>[[exec.recv]](exec.recv "33.7 Receivers") | Receivers | |
|
||||
| [ð](#tab:exec.summary-row-4)<br>[[exec.opstate]](exec.opstate "33.8 Operation states") | Operation states | |
|
||||
| [ð](#tab:exec.summary-row-5)<br>[[exec.snd]](exec.snd "33.9 Senders") | Senders | |
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L22)
|
||||
|
||||
Table [158](#tab:exec.pos "Table 158: Types of customization point objects in the execution control library") shows
|
||||
the types of customization point objects ([[customization.point.object]](customization.point.object "16.3.3.3.5 Customization Point Object types"))
|
||||
used in the execution control library[.](#3.sentence-1)
|
||||
|
||||
Table [158](#tab:exec.pos) — Types of customization point objects in the execution control library [[tab:exec.pos]](./tab:exec.pos)
|
||||
|
||||
| [ð](#tab:exec.pos-row-1)<br>**Customization point** | **Purpose** | **Examples** |
|
||||
| --- | --- | --- |
|
||||
| [ð](#tab:exec.pos-row-2)<br>**object type** | | |
|
||||
| [ð](#tab:exec.pos-row-3)<br>core | provide core execution functionality, and connection between core components | e.g., [connect](execution.syn#lib:connect "33.4 Header <execution> synopsis [execution.syn]"), [start](execution.syn#lib:start "33.4 Header <execution> synopsis [execution.syn]") |
|
||||
| [ð](#tab:exec.pos-row-4)<br>completion functions | called by senders to announce the completion of the work (success, error, or cancellation) | [set_value](execution.syn#lib:set_value "33.4 Header <execution> synopsis [execution.syn]"), [set_error](execution.syn#lib:set_error "33.4 Header <execution> synopsis [execution.syn]"), [set_stopped](execution.syn#lib:set_stopped "33.4 Header <execution> synopsis [execution.syn]") |
|
||||
| [ð](#tab:exec.pos-row-5)<br>senders | allow the specialization of the provided sender algorithms | sender factories (e.g., [schedule](execution.syn#lib:schedule "33.4 Header <execution> synopsis [execution.syn]"), [just](execution.syn#lib:just "33.4 Header <execution> synopsis [execution.syn]"), [read_env](execution.syn#lib:read_env "33.4 Header <execution> synopsis [execution.syn]"))sender adaptors (e.g., [continues_on](execution.syn#lib:continues_on "33.4 Header <execution> synopsis [execution.syn]"), [then](execution.syn#lib:then "33.4 Header <execution> synopsis [execution.syn]"), [let_value](execution.syn#lib:let_value "33.4 Header <execution> synopsis [execution.syn]"))sender consumers (e.g., [sync_wait](execution.syn#lib:sync_wait "33.4 Header <execution> synopsis [execution.syn]")) |
|
||||
| [ð](#tab:exec.pos-row-6)<br>queries | allow querying different properties of objects | general queries (e.g., [get_allocator](execution.syn#lib:get_allocator "33.4 Header <execution> synopsis [execution.syn]"), [get_stop_token](execution.syn#lib:get_stop_token "33.4 Header <execution> synopsis [execution.syn]"))environment queries (e.g., get_scheduler, [get_delegation_scheduler](execution.syn#lib:get_delegation_scheduler "33.4 Header <execution> synopsis [execution.syn]"))scheduler queries (e.g., [get_forward_progress_guarantee](execution.syn#lib:get_forward_progress_guarantee "33.4 Header <execution> synopsis [execution.syn]"))sender attribute queries (e.g., [get_completion_scheduler](execution.syn#lib:get_completion_scheduler "33.4 Header <execution> synopsis [execution.syn]")) |
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L57)
|
||||
|
||||
This clause makes use of the following exposition-only entities[.](#4.sentence-1)
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L60)
|
||||
|
||||
For a subexpression expr,
|
||||
let *MANDATE-NOTHROW*(expr) be
|
||||
expression-equivalent to expr[.](#5.sentence-1)
|
||||
|
||||
*Mandates*: noexcept(expr) is true[.](#5.sentence-2)
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L68)
|
||||
|
||||
namespace std {template<class T>concept [*movable-value*](#concept:movable-value "33.1 General [exec.general]") = // *exposition only*[move_constructible](concept.moveconstructible#concept:move_constructible "18.4.13 Concept move_constructible [concept.moveconstructible]")<decay_t<T>> &&[constructible_from](concept.constructible#concept:constructible_from "18.4.11 Concept constructible_from [concept.constructible]")<decay_t<T>, T> &&(!is_array_v<remove_reference_t<T>>);}
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L79)
|
||||
|
||||
For function types F1 and F2 denotingR1(Args1...) and R2(Args2...), respectively,*MATCHING-SIG*(F1, F2) is true if and only if[same_as](concept.same#concept:same_as "18.4.2 Concept same_as [concept.same]")<R1(Args1&&...), R2(Args2&&...)> is true[.](#7.sentence-1)
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L86)
|
||||
|
||||
For a subexpression err,
|
||||
let Err be decltype((err)) and
|
||||
let *AS-EXCEPT-PTR*(err) be:
|
||||
|
||||
- [(8.1)](#8.1)
|
||||
|
||||
err if decay_t<Err> denotes the type exception_ptr[.](#8.1.sentence-1)
|
||||
*Preconditions*: !err is false[.](#8.1.sentence-2)
|
||||
|
||||
- [(8.2)](#8.2)
|
||||
|
||||
Otherwise,make_exception_ptr(system_error(err)) if decay_t<Err> denotes the type error_code[.](#8.2.sentence-1)
|
||||
|
||||
- [(8.3)](#8.3)
|
||||
|
||||
Otherwise, make_exception_ptr(err)[.](#8.3.sentence-1)
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L104)
|
||||
|
||||
For a subexpression expr,
|
||||
let *AS-CONST*(expr) be expression-equivalent to[](const auto& x) noexcept -> const auto& { return x; }(expr)
|
||||
31
cppdraft/exec/get/allocator.md
Normal file
31
cppdraft/exec/get/allocator.md
Normal file
@@ -0,0 +1,31 @@
|
||||
[exec.get.allocator]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.5 Queries [[exec.queries]](exec.queries#exec.get.allocator)
|
||||
|
||||
### 33.5.2 get_allocator [exec.get.allocator]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L861)
|
||||
|
||||
get_allocator asks a queryable object for its associated allocator[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L864)
|
||||
|
||||
The name get_allocator denotes a query object[.](#2.sentence-1)
|
||||
|
||||
For a subexpression env,get_allocator(env) is expression-equivalent to*MANDATE-NOTHROW*(*AS-CONST*(env).query(get_allocator))[.](#2.sentence-2)
|
||||
|
||||
*Mandates*: If the expression above is well-formed,
|
||||
its type satisfies[*simple-allocator*](allocator.requirements.general#concept:simple-allocator "16.4.4.6.1 General [allocator.requirements.general]") ([[allocator.requirements.general]](allocator.requirements.general "16.4.4.6.1 General"))[.](#2.sentence-3)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L875)
|
||||
|
||||
forwarding_query(get_allocator) is a core constant expression and
|
||||
has value true[.](#3.sentence-1)
|
||||
28
cppdraft/exec/get/await/adapt.md
Normal file
28
cppdraft/exec/get/await/adapt.md
Normal file
@@ -0,0 +1,28 @@
|
||||
[exec.get.await.adapt]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.5 Queries [[exec.queries]](exec.queries#exec.get.await.adapt)
|
||||
|
||||
### 33.5.10 execution::get_await_completion_adaptor [exec.get.await.adapt]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1078)
|
||||
|
||||
get_await_completion_adaptor asks a queryable object for
|
||||
its associated awaitable completion adaptor[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1082)
|
||||
|
||||
The name get_await_completion_adaptor denotes a query object[.](#2.sentence-1)
|
||||
|
||||
For a subexpression env,get_await_completion_adaptor(env) is expression-equivalent to*MANDATE-NOTHROW*(*AS-CONST*(env).query(get_await_completion_adaptor))
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1093)
|
||||
|
||||
forwarding_query(execution::get_await_completion_adaptor) is a core constant expression and has value true[.](#3.sentence-1)
|
||||
50
cppdraft/exec/get/compl/sched.md
Normal file
50
cppdraft/exec/get/compl/sched.md
Normal file
@@ -0,0 +1,50 @@
|
||||
[exec.get.compl.sched]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.5 Queries [[exec.queries]](exec.queries#exec.get.compl.sched)
|
||||
|
||||
### 33.5.9 execution::get_completion_scheduler [exec.get.compl.sched]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1035)
|
||||
|
||||
get_completion_scheduler<*completion-tag>* obtains
|
||||
the completion scheduler associated with a completion tag
|
||||
from a sender's attributes[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1040)
|
||||
|
||||
The name get_completion_scheduler denotes a query object template[.](#2.sentence-1)
|
||||
|
||||
For a subexpression q,
|
||||
the expression get_completion_scheduler<*completion-tag*>(q) is ill-formed if *completion-tag* is not one ofset_value_t, set_error_t, or set_stopped_t[.](#2.sentence-2)
|
||||
|
||||
Otherwise, get_completion_scheduler<*completion-tag*>(q) is expression-equivalent to*MANDATE-NOTHROW*(*AS-CONST*(q).query(get_completion_scheduler<*completion-tag*>))*Mandates*: If the expression above is well-formed,
|
||||
its type satisfies [scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]")[.](#2.sentence-3)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1055)
|
||||
|
||||
Let *completion-fn* be a completion function ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations"));
|
||||
let *completion-tag* be
|
||||
the associated completion tag of *completion-fn*;
|
||||
let args be a pack of subexpressions; and
|
||||
let sndr be a subexpression
|
||||
such that [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]")<decltype((sndr))> is true andget_completion_scheduler<*completion-tag*>(get_env(sndr)) is well-formed and denotes a scheduler sch[.](#3.sentence-1)
|
||||
|
||||
If an asynchronous operation
|
||||
created by connecting sndr with a receiver rcvr causes the evaluation of *completion-fn*(rcvr, args...),
|
||||
the behavior is undefined
|
||||
unless the evaluation happens on an execution agent
|
||||
that belongs to sch's associated execution resource[.](#3.sentence-2)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1071)
|
||||
|
||||
The expressionforwarding_query(get_completion_scheduler<*completion-tag*>) is a core constant expression and has value true[.](#4.sentence-1)
|
||||
33
cppdraft/exec/get/delegation/scheduler.md
Normal file
33
cppdraft/exec/get/delegation/scheduler.md
Normal file
@@ -0,0 +1,33 @@
|
||||
[exec.get.delegation.scheduler]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.5 Queries [[exec.queries]](exec.queries#exec.get.delegation.scheduler)
|
||||
|
||||
### 33.5.7 execution::get_delegation_scheduler [exec.get.delegation.scheduler]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L970)
|
||||
|
||||
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 ([[intro.progress]](intro.progress "6.10.2.3 Forward progress"))[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L975)
|
||||
|
||||
The name get_delegation_scheduler denotes a query object[.](#2.sentence-1)
|
||||
|
||||
For a subexpression env,get_delegation_scheduler(env) is expression-equivalent to*MANDATE-NOTHROW*(*AS-CONST*(env).query(get_delegation_scheduler))[.](#2.sentence-2)
|
||||
|
||||
*Mandates*: If the expression above is well-formed,
|
||||
its type satisfies [scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]")[.](#2.sentence-3)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L985)
|
||||
|
||||
forwarding_query(execution::get_delegation_scheduler) is
|
||||
a core constant expression and has value true[.](#3.sentence-1)
|
||||
29
cppdraft/exec/get/domain.md
Normal file
29
cppdraft/exec/get/domain.md
Normal file
@@ -0,0 +1,29 @@
|
||||
[exec.get.domain]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.5 Queries [[exec.queries]](exec.queries#exec.get.domain)
|
||||
|
||||
### 33.5.5 execution::get_domain [exec.get.domain]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L935)
|
||||
|
||||
get_domain asks a queryable object
|
||||
for its associated execution domain tag[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L939)
|
||||
|
||||
The name get_domain denotes a query object[.](#2.sentence-1)
|
||||
|
||||
For a subexpression env,get_domain(env) is expression-equivalent to*MANDATE-NOTHROW*(*AS-CONST*(env).query(get_domain))[.](#2.sentence-2)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L945)
|
||||
|
||||
forwarding_query(execution::get_domain) is
|
||||
a core constant expression and has value true[.](#3.sentence-1)
|
||||
42
cppdraft/exec/get/env.md
Normal file
42
cppdraft/exec/get/env.md
Normal file
@@ -0,0 +1,42 @@
|
||||
[exec.get.env]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.5 Queries [[exec.queries]](exec.queries#exec.get.env)
|
||||
|
||||
### 33.5.4 execution::get_env [exec.get.env]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L906)
|
||||
|
||||
execution::get_env is a customization point object[.](#1.sentence-1)
|
||||
|
||||
For a subexpression o,execution::get_env(o) is expression-equivalent to:
|
||||
|
||||
- [(1.1)](#1.1)
|
||||
|
||||
*MANDATE-NOTHROW*(*AS-CONST*(o).get_env()) if that expression is well-formed[.](#1.1.sentence-1)
|
||||
*Mandates*: The type of the expression above satisfies[*queryable*](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]") ([[exec.queryable]](exec.queryable "33.2 Queries and queryables"))[.](#1.1.sentence-2)
|
||||
|
||||
- [(1.2)](#1.2)
|
||||
|
||||
Otherwise, env<>{}[.](#1.2.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L922)
|
||||
|
||||
The value of get_env(o) shall be valid while o is valid[.](#2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L925)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
When passed a sender object,get_env returns the sender's associated attributes[.](#3.sentence-1)
|
||||
|
||||
When passed a receiver,get_env returns the receiver's associated execution environment[.](#3.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
53
cppdraft/exec/get/fwd/progress.md
Normal file
53
cppdraft/exec/get/fwd/progress.md
Normal file
@@ -0,0 +1,53 @@
|
||||
[exec.get.fwd.progress]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.5 Queries [[exec.queries]](exec.queries#exec.get.fwd.progress)
|
||||
|
||||
### 33.5.8 execution::get_forward_progress_guarantee [exec.get.fwd.progress]
|
||||
|
||||
namespace std::execution {enum class [forward_progress_guarantee](#lib:forward_progress_guarantee "33.5.8 execution::get_forward_progress_guarantee [exec.get.fwd.progress]") { concurrent,
|
||||
parallel,
|
||||
weakly_parallel };}
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1001)
|
||||
|
||||
get_forward_progress_guarantee asks a scheduler about
|
||||
the forward progress guarantee of execution agents
|
||||
created by that scheduler's associated execution resource ([[intro.progress]](intro.progress "6.10.2.3 Forward progress"))[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1006)
|
||||
|
||||
The name get_forward_progress_guarantee denotes a query object[.](#2.sentence-1)
|
||||
|
||||
For a subexpression sch, let Sch be decltype((sch))[.](#2.sentence-2)
|
||||
|
||||
If Sch does not satisfy [scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]"),get_forward_progress_guarantee is ill-formed[.](#2.sentence-3)
|
||||
|
||||
Otherwise,get_forward_progress_guarantee(sch) is expression-equivalent to:
|
||||
|
||||
- [(2.1)](#2.1)
|
||||
|
||||
*MANDATE-NOTHROW*(*AS-CONST*(sch).query(get_forward_progress_guarantee)),
|
||||
if that expression is well-formed[.](#2.1.sentence-1)
|
||||
*Mandates*: The type of the expression above is forward_progress_guarantee[.](#2.1.sentence-2)
|
||||
|
||||
- [(2.2)](#2.2)
|
||||
|
||||
Otherwise, forward_progress_guarantee::weakly_parallel[.](#2.2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1024)
|
||||
|
||||
If get_forward_progress_guarantee(sch) for some scheduler sch returns forward_progress_guarantee::concurrent,
|
||||
all execution agents created by that scheduler's associated execution resource
|
||||
shall provide the concurrent forward progress guarantee[.](#3.sentence-1)
|
||||
|
||||
If it returns forward_progress_guarantee::parallel,
|
||||
all such execution agents
|
||||
shall provide at least the parallel forward progress guarantee[.](#3.sentence-2)
|
||||
31
cppdraft/exec/get/scheduler.md
Normal file
31
cppdraft/exec/get/scheduler.md
Normal file
@@ -0,0 +1,31 @@
|
||||
[exec.get.scheduler]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.5 Queries [[exec.queries]](exec.queries#exec.get.scheduler)
|
||||
|
||||
### 33.5.6 execution::get_scheduler [exec.get.scheduler]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L951)
|
||||
|
||||
get_scheduler asks a queryable object for its associated scheduler[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L954)
|
||||
|
||||
The name get_scheduler denotes a query object[.](#2.sentence-1)
|
||||
|
||||
For a subexpression env,get_scheduler(env) is expression-equivalent to*MANDATE-NOTHROW*(*AS-CONST*(env).query(get_scheduler))[.](#2.sentence-2)
|
||||
|
||||
*Mandates*: If the expression above is well-formed,
|
||||
its type satisfies [scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]")[.](#2.sentence-3)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L964)
|
||||
|
||||
forwarding_query(execution::get_scheduler) is
|
||||
a core constant expression and has value true[.](#3.sentence-1)
|
||||
37
cppdraft/exec/get/stop/token.md
Normal file
37
cppdraft/exec/get/stop/token.md
Normal file
@@ -0,0 +1,37 @@
|
||||
[exec.get.stop.token]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.5 Queries [[exec.queries]](exec.queries#exec.get.stop.token)
|
||||
|
||||
### 33.5.3 get_stop_token [exec.get.stop.token]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L881)
|
||||
|
||||
get_stop_token asks a queryable object for an associated stop token[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L884)
|
||||
|
||||
The name get_stop_token denotes a query object[.](#2.sentence-1)
|
||||
|
||||
For a subexpression env,get_stop_token(env) is expression-equivalent to:
|
||||
|
||||
- [(2.1)](#2.1)
|
||||
|
||||
*MANDATE-NOTHROW*(*AS-CONST*(env).query(get_stop_token)) if that expression is well-formed[.](#2.1.sentence-1)
|
||||
*Mandates*: The type of the expression above satisfies [stoppable_token](stoptoken.concepts#concept:stoppable_token "32.3.3 Stop token concepts [stoptoken.concepts]")[.](#2.1.sentence-2)
|
||||
|
||||
- [(2.2)](#2.2)
|
||||
|
||||
Otherwise, never_stop_token{}[.](#2.2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L900)
|
||||
|
||||
forwarding_query(get_stop_token) is a core constant expression and
|
||||
has value true[.](#3.sentence-1)
|
||||
94
cppdraft/exec/getcomplsigs.md
Normal file
94
cppdraft/exec/getcomplsigs.md
Normal file
@@ -0,0 +1,94 @@
|
||||
[exec.getcomplsigs]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#exec.getcomplsigs)
|
||||
|
||||
### 33.9.9 execution::get_completion_signatures [exec.getcomplsigs]
|
||||
|
||||
[ð](#itemdecl:1)
|
||||
|
||||
`template<class Sndr, class... Env>
|
||||
consteval auto get_completion_signatures() -> [valid-completion-signatures](execution.syn#concept:valid-completion-signatures "33.4 Header <execution> synopsis [execution.syn]") auto;
|
||||
`
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2634)
|
||||
|
||||
Let except be an rvalue subexpression of
|
||||
an unspecified class type Except such that[move_constructible](concept.moveconstructible#concept:move_constructible "18.4.13 Concept move_constructible [concept.moveconstructible]")<Except> && [derived_from](concept.derived#concept:derived_from "18.4.3 Concept derived_from [concept.derived]")<Except, exception> is true[.](#1.sentence-1)
|
||||
|
||||
Let *CHECKED-COMPLSIGS*(e) be e if e is a core constant expression whose
|
||||
type satisfies [*valid-completion-signatures*](execution.syn#concept:valid-completion-signatures "33.4 Header <execution> synopsis [execution.syn]");
|
||||
otherwise, it is the following expression:(e, throw except, completion_signatures())
|
||||
|
||||
Let *get-complsigs*<Sndr, Env...>() be expression-equivalent toremove_reference_t<Sndr>::template get_completion_signatures<Sndr, Env...>()[.](#1.sentence-3)
|
||||
|
||||
Let NewSndr be Sndr if sizeof...(Env) == 0 is true;
|
||||
otherwise, decltype(s) where s is the following expression:transform_sender(*get-domain-late*(declval<Sndr>(), declval<Env>()...),
|
||||
declval<Sndr>(),
|
||||
declval<Env>()...)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2660)
|
||||
|
||||
*Constraints*: sizeof...(Env) <= 1 is true[.](#2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2664)
|
||||
|
||||
*Effects*: Equivalent to: return e; where e is expression-equivalent to the following:
|
||||
|
||||
- [(3.1)](#3.1)
|
||||
|
||||
*CHECKED-COMPLSIGS*(*get-complsigs*<NewSndr, Env...>()) if *get-complsigs*<NewSndr, Env
|
||||
...>() is a well-formed expression[.](#3.1.sentence-1)
|
||||
|
||||
- [(3.2)](#3.2)
|
||||
|
||||
Otherwise,*CHECKED-COMPLSIGS*(*get-complsigs*<NewSndr>()) if *get-complsigs*<NewSndr>() is a well-formed expression[.](#3.2.sentence-1)
|
||||
|
||||
- [(3.3)](#3.3)
|
||||
|
||||
Otherwise,completion_signatures<*SET-VALUE-SIG*(*await-result-type*<NewSndr, *env-promise*<Env>...>), // [[exec.snd.concepts]](exec.snd.concepts "33.9.3 Sender concepts") set_error_t(exception_ptr),
|
||||
set_stopped_t()> if [*is-awaitable*](exec.awaitable#concept:is-awaitable "33.9.4 Awaitable helpers [exec.awaitable]")<NewSndr, *env-promise*<Env>...> is true[.](#3.3.sentence-1)
|
||||
|
||||
- [(3.4)](#3.4)
|
||||
|
||||
Otherwise,(throw *dependent-sender-error*(), completion_signatures()) if sizeof...(
|
||||
Env) == 0 is true,
|
||||
where *dependent-sender-error* isdependent_sender_error or
|
||||
an unspecified type derived publicly and unambiguously fromdependent_sender_error[.](#3.4.sentence-1)
|
||||
|
||||
- [(3.5)](#3.5)
|
||||
|
||||
Otherwise,(throw except, completion_signatures())[.](#3.5.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2706)
|
||||
|
||||
Given a type Env, ifcompletion_signatures_of_t<Sndr> andcompletion_signatures_of_t<Sndr, Env> are both well-formed,
|
||||
they shall denote the same type[.](#4.sentence-1)
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2713)
|
||||
|
||||
Let rcvr be an rvalue
|
||||
whose type Rcvr models [receiver](exec.recv.concepts#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]"), and
|
||||
let Sndr be the type of a sender
|
||||
such that [sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr, env_of_t<Rcvr>> is true[.](#5.sentence-1)
|
||||
|
||||
Let Sigs... be the template arguments of
|
||||
the completion_signatures specialization
|
||||
named by completion_signatures_of_t<Sndr, env_of_t<Rcvr>>[.](#5.sentence-2)
|
||||
|
||||
Let CSO be a completion function[.](#5.sentence-3)
|
||||
|
||||
If sender Sndr or its operation state cause
|
||||
the expression CSO(rcvr, args...) to be potentially evaluated ([[basic.def.odr]](basic.def.odr "6.3 One-definition rule"))
|
||||
then there shall be a signature Sig in Sigs... such that*MATCHING-SIG*(*decayed-typeof*<CSO>(decltype(args)...), Sig) is true ([[exec.general]](exec.general "33.1 General"))[.](#5.sentence-4)
|
||||
62
cppdraft/exec/inline/scheduler.md
Normal file
62
cppdraft/exec/inline/scheduler.md
Normal file
@@ -0,0 +1,62 @@
|
||||
[exec.inline.scheduler]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.13 Coroutine utilities [[exec.coro.util]](exec.coro.util#exec.inline.scheduler)
|
||||
|
||||
### 33.13.4 execution::inline_scheduler [exec.inline.scheduler]
|
||||
|
||||
namespace std::execution {class [inline_scheduler](#lib:inline_scheduler "33.13.4 execution::inline_scheduler [exec.inline.scheduler]") {class *inline-sender*; // *exposition only*template<[receiver](exec.recv.concepts#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]") R>class *inline-state*; // *exposition only*public:using scheduler_concept = scheduler_t; constexpr *inline-sender* schedule() noexcept { return {}; }constexpr bool operator==(const inline_scheduler&) const noexcept = default; };}
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6954)
|
||||
|
||||
inline_scheduler is a class that models[scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]") ([[exec.sched]](exec.sched "33.6 Schedulers"))[.](#1.sentence-1)
|
||||
|
||||
All objects of type inline_scheduler are equal[.](#1.sentence-2)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6959)
|
||||
|
||||
*inline-sender* is an exposition-only type that satisfies[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]")[.](#2.sentence-1)
|
||||
|
||||
The type completion_signatures_of_t<*inline-sender*> is completion_signatures<set_value_t()>[.](#2.sentence-2)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6965)
|
||||
|
||||
Let sndr be an expression of type *inline-sender*,
|
||||
let rcvr be an expression such that[receiver_of](exec.recv.concepts#concept:receiver_of "33.7.1 Receiver concepts [exec.recv.concepts]")<decltype((rcvr)), CS> is true where CS is completion_signatures<set_value_t()>,
|
||||
then:
|
||||
|
||||
- [(3.1)](#3.1)
|
||||
|
||||
the expression connect(sndr, rcvr) has
|
||||
type *inline-state*<remove_cvref_t<decltype((rcvr))>> and is potentially-throwing if and only if((void)sndr, auto(rcvr)) is potentially-throwing, and
|
||||
|
||||
- [(3.2)](#3.2)
|
||||
|
||||
the expressionget_completion_scheduler<set_value_t>(get_env(sndr)) has
|
||||
type inline_scheduler and is potentially-throwing
|
||||
if and only if get_env(sndr) is potentially-throwing[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6982)
|
||||
|
||||
Let *o* be a non-const lvalue of type*inline-state*<Rcvr>, and let REC(*o*) be
|
||||
a non-const lvalue reference to an object of type Rcvr that
|
||||
was initialized with the expression rcvr passed to an
|
||||
invocation of connect that returned *o*, then:
|
||||
|
||||
- [(4.1)](#4.1)
|
||||
|
||||
the object to which REC(*o*) refers remains valid for
|
||||
the lifetime of the object to which *o* refers, and
|
||||
|
||||
- [(4.2)](#4.2)
|
||||
|
||||
the expression start(*o*) is equivalent toset_value(std::move(REC(*o*)))[.](#4.sentence-1)
|
||||
56
cppdraft/exec/into/variant.md
Normal file
56
cppdraft/exec/into/variant.md
Normal file
@@ -0,0 +1,56 @@
|
||||
[exec.into.variant]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#exec.into.variant)
|
||||
|
||||
### 33.9.12 Sender adaptors [[exec.adapt]](exec.adapt#exec.into.variant)
|
||||
|
||||
#### 33.9.12.13 execution::into_variant [exec.into.variant]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4722)
|
||||
|
||||
into_variant adapts a sender with multiple value completion signatures
|
||||
into a sender with just one value completion signature
|
||||
consisting of a variant of tuples[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4727)
|
||||
|
||||
The name into_variant denotes a pipeable sender adaptor object[.](#2.sentence-1)
|
||||
|
||||
For a subexpression sndr, let Sndr be decltype((sndr))[.](#2.sentence-2)
|
||||
|
||||
If Sndr does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"),into_variant(sndr) is ill-formed[.](#2.sentence-3)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4733)
|
||||
|
||||
Otherwise, the expression into_variant(sndr) is expression-equivalent to:transform_sender(*get-domain-early*(sndr), *make-sender*(into_variant, {}, sndr)) except that sndr is only evaluated once[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4741)
|
||||
|
||||
The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
|
||||
is specialized for into_variant as follows:
|
||||
|
||||
[ð](#lib:impls-for%3cinto_variant_t%3e)
|
||||
|
||||
namespace std::execution {template<>struct *impls-for*<into_variant_t> : *default-impls* {static constexpr auto *get-state* = *see below*; static constexpr auto *complete* = *see below*; template<class Sndr, class... Env>static consteval void *check-types*() {auto cs = get_completion_signatures<*child-type*<Sndr>, *FWD-ENV-T*(Env)...>(); *decay-copyable-result-datums*(cs); // see [[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities")}};}
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4762)
|
||||
|
||||
The member *impls-for*<into_variant_t>::*get-state* is initialized with a callable object equivalent to the following lambda:[]<class Sndr, class Rcvr>(Sndr&& sndr, Rcvr& rcvr) noexcept-> type_identity<value_types_of_t<*child-type*<Sndr>, *FWD-ENV-T*(env_of_t<Rcvr>)>> {return {};}
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4772)
|
||||
|
||||
The member *impls-for*<into_variant_t>::*complete* is initialized with a callable object equivalent to the following lambda:[]<class State, class Rcvr, class Tag, class... Args>(auto, State, Rcvr& rcvr, Tag, Args&&... args) noexcept -> void {if constexpr ([same_as](concept.same#concept:same_as "18.4.2 Concept same_as [concept.same]")<Tag, set_value_t>) {using variant_type = typename State::type; *TRY-SET-VALUE*(rcvr, variant_type(*decayed-tuple*<Args...>{std::forward<Args>(args)...})); } else { Tag()(std::move(rcvr), std::forward<Args>(args)...); }}
|
||||
53
cppdraft/exec/just.md
Normal file
53
cppdraft/exec/just.md
Normal file
@@ -0,0 +1,53 @@
|
||||
[exec.just]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#exec.just)
|
||||
|
||||
### 33.9.11 Sender factories [[exec.factories]](exec.factories#exec.just)
|
||||
|
||||
#### 33.9.11.2 execution::just, execution::just_error, execution::just_stopped [exec.just]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2901)
|
||||
|
||||
just, just_error, and just_stopped are sender factories
|
||||
whose asynchronous operations complete synchronously in their start operation
|
||||
with a value completion operation,
|
||||
an error completion operation, or
|
||||
a stopped completion operation, respectively[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2908)
|
||||
|
||||
The names just, just_error, and just_stopped denote
|
||||
customization point objects[.](#2.sentence-1)
|
||||
|
||||
Let *just-cpo* be one ofjust, just_error, or just_stopped[.](#2.sentence-2)
|
||||
|
||||
For a pack of subexpressions ts,
|
||||
let Ts be the pack of types decltype((ts))[.](#2.sentence-3)
|
||||
|
||||
The expression *just-cpo*(ts...) is ill-formed if
|
||||
|
||||
- [(2.1)](#2.1)
|
||||
|
||||
([*movable-value*](exec.general#concept:movable-value "33.1 General [exec.general]")<Ts> &&...) is false, or
|
||||
|
||||
- [(2.2)](#2.2)
|
||||
|
||||
*just-cpo* is just_error andsizeof...(ts) == 1 is false, or
|
||||
|
||||
- [(2.3)](#2.3)
|
||||
|
||||
*just-cpo* is just_stopped andsizeof...(ts) == 0 is false[.](#2.sentence-4)
|
||||
|
||||
Otherwise, it is expression-equivalent to*make-sender*(*just-cpo*, *product-type*{ts...})[.](#2.sentence-5)
|
||||
|
||||
For just, just_error, and just_stopped,
|
||||
let *set-cpo* beset_value, set_error, and set_stopped, respectively[.](#2.sentence-6)
|
||||
|
||||
The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
|
||||
is specialized for *just-cpo* as follows:namespace std::execution {template<>struct *impls-for*<*decayed-typeof*<*just-cpo*>> : *default-impls* {static constexpr auto *start* =[](auto& state, auto& rcvr) noexcept -> void {auto& [...ts] = state; *set-cpo*(std::move(rcvr), std::move(ts)...); }; };}
|
||||
232
cppdraft/exec/let.md
Normal file
232
cppdraft/exec/let.md
Normal file
@@ -0,0 +1,232 @@
|
||||
[exec.let]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#exec.let)
|
||||
|
||||
### 33.9.12 Sender adaptors [[exec.adapt]](exec.adapt#exec.let)
|
||||
|
||||
#### 33.9.12.10 execution::let_value, execution::let_error, execution::let_stopped [exec.let]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3847)
|
||||
|
||||
let_value, let_error, and let_stopped transform
|
||||
a sender's value, error, and stopped completions, respectively,
|
||||
into a new child asynchronous operation
|
||||
by passing the sender's result datums to a user-specified callable,
|
||||
which returns a new sender that is connected and started[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3854)
|
||||
|
||||
For let_value, let_error, and let_stopped,
|
||||
let *set-cpo* beset_value, set_error, and set_stopped, respectively[.](#2.sentence-1)
|
||||
|
||||
Let the expression *let-cpo* be one oflet_value, let_error, or let_stopped[.](#2.sentence-2)
|
||||
|
||||
For a subexpression sndr,
|
||||
let *let-env*(sndr) be expression-equivalent to
|
||||
the first well-formed expression below:
|
||||
|
||||
- [(2.1)](#2.1)
|
||||
|
||||
*SCHED-ENV*(get_completion_scheduler<*decayed-typeof*<*set-cpo*>>(get_env(sndr)))
|
||||
|
||||
- [(2.2)](#2.2)
|
||||
|
||||
*MAKE-ENV*(get_domain, get_domain(get_env(sndr)))
|
||||
|
||||
- [(2.3)](#2.3)
|
||||
|
||||
(void(sndr), env<>{})
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3872)
|
||||
|
||||
The names let_value, let_error, and let_stopped denote
|
||||
pipeable sender adaptor objects[.](#3.sentence-1)
|
||||
|
||||
For subexpressions sndr and f,
|
||||
let F be the decayed type of f[.](#3.sentence-2)
|
||||
|
||||
If decltype((sndr)) does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") or
|
||||
if decltype((f)) does not satisfy [*movable-value*](exec.general#concept:movable-value "33.1 General [exec.general]"),
|
||||
the expression *let-cpo*(sndr, f) is ill-formed[.](#3.sentence-3)
|
||||
|
||||
If F does not satisfy [invocable](concept.invocable#concept:invocable "18.7.2 Concept invocable [concept.invocable]"),
|
||||
the expression let_stopped(sndr, f) is ill-formed[.](#3.sentence-4)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3883)
|
||||
|
||||
Otherwise,
|
||||
the expression *let-cpo*(sndr, f) is expression-equivalent to:transform_sender(*get-domain-early*(sndr), *make-sender*(*let-cpo*, f, sndr)) except that sndr is evaluated only once[.](#4.sentence-1)
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3891)
|
||||
|
||||
The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
|
||||
is specialized for *let-cpo* as follows:
|
||||
|
||||
[ð](#lib:impls-for%3cdecayed-typeof%3clet-cpo%3e%3e)
|
||||
|
||||
namespace std::execution {template<class State, class Rcvr, class... Args>void *let-bind*(State& state, Rcvr& rcvr, Args&&... args); // *exposition only*template<>struct *impls-for*<*decayed-typeof*<*let-cpo*>> : *default-impls* {static constexpr auto *get-state* = *see below*; static constexpr auto *complete* = *see below*; template<class Sndr, class... Env>static consteval void *check-types*(); };}
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3911)
|
||||
|
||||
Let *receiver2* denote the following exposition-only class template:namespace std::execution {template<class Rcvr, class Env>struct *receiver2* {using receiver_concept = receiver_t; template<class... Args>void set_value(Args&&... args) && noexcept { execution::set_value(std::move(*rcvr*), std::forward<Args>(args)...); }template<class Error>void set_error(Error&& err) && noexcept { execution::set_error(std::move(*rcvr*), std::forward<Error>(err)); }void set_stopped() && noexcept { execution::set_stopped(std::move(*rcvr*)); }decltype(auto) get_env() const noexcept {return *see below*; } Rcvr& *rcvr*; // *exposition only* Env *env*; // *exposition only*};}
|
||||
|
||||
Invocation of the function *receiver2*::get_env returns an object e such that
|
||||
|
||||
- [(6.1)](#6.1)
|
||||
|
||||
decltype(e) models [*queryable*](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]") and
|
||||
|
||||
- [(6.2)](#6.2)
|
||||
|
||||
given a query object q,
|
||||
the expression e.query(q) is expression-equivalent
|
||||
to *env*.query(q) if that expression is valid;
|
||||
otherwise,
|
||||
if the type of q satisfies [*forwarding-query*](execution.syn#concept:forwarding-query "33.4 Header <execution> synopsis [execution.syn]"),e.query(q) is expression-equivalent
|
||||
to get_env(*rcvr*).query(q);
|
||||
otherwise,e.query(q) is ill-formed[.](#6.sentence-2)
|
||||
|
||||
[ð](#lib:check-types,impls-for%3cdecayed-typeof%3clet-cpo%3e%3e)
|
||||
|
||||
`template<class Sndr, class... Env>
|
||||
static consteval void check-types();
|
||||
`
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3966)
|
||||
|
||||
*Effects*: Equivalent to:using LetFn = remove_cvref_t<*data-type*<Sndr>>;auto cs = get_completion_signatures<*child-type*<Sndr>, *FWD-ENV-T*(Env)...>();auto fn = []<class... Ts>(*decayed-typeof*<*set-cpo*>(*)(Ts...)) {if constexpr (!*is-valid-let-sender*) // *see below*throw *unspecified-exception*();};
|
||||
cs.*for-each*(*overload-set*(fn, [](auto){})); where *unspecified-exception* is
|
||||
a type derived from exception, and
|
||||
where *is-valid-let-sender* is true if and only if
|
||||
all of the following are true:
|
||||
|
||||
- [(7.1)](#7.1)
|
||||
|
||||
([constructible_from](concept.constructible#concept:constructible_from "18.4.11 Concept constructible_from [concept.constructible]")<decay_t<Ts>, Ts> &&...)
|
||||
|
||||
- [(7.2)](#7.2)
|
||||
|
||||
[invocable](concept.invocable#concept:invocable "18.7.2 Concept invocable [concept.invocable]")<LetFn, decay_t<Ts>&...>
|
||||
|
||||
- [(7.3)](#7.3)
|
||||
|
||||
[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]")<invoke_result_t<LetFn, decay_t<Ts>&...>>
|
||||
|
||||
- [(7.4)](#7.4)
|
||||
|
||||
sizeof...(Env) == 0 || [sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<invoke_result_t<LetFn, decay_t<Ts>&...>, *env-t*
|
||||
...>
|
||||
|
||||
where *env-t* is the packdecltype(*let-cpo*.transform_env(declval<Sndr>(), declval<Env>()))[.](#7.sentence-1)
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3993)
|
||||
|
||||
*impls-for*<*decayed-typeof*<*let-cpo*>>::*get-state* is initialized with a callable object equivalent to the following:[]<class Sndr, class Rcvr>(Sndr&& sndr, Rcvr& rcvr) requires *see below* {auto& [_, fn, child] = sndr; using fn_t = decay_t<decltype(fn)>; using env_t = decltype(*let-env*(child)); using args_variant_t = *see below*; using ops2_variant_t = *see below*; struct *state-type* { fn_t *fn*; // *exposition only* env_t *env*; // *exposition only* args_variant_t *args*; // *exposition only* ops2_variant_t *ops2*; // *exposition only*}; return *state-type*{*allocator-aware-forward*(std::forward_like<Sndr>(fn), rcvr), *let-env*(child), {}, {}};}
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4015)
|
||||
|
||||
Let Sigs be a pack of the arguments
|
||||
to the completion_signatures specialization named bycompletion_signatures_of_t<*child-type*<Sndr>, *FWD-ENV-T*(env_of_t<Rcvr>)>[.](#9.sentence-1)
|
||||
|
||||
Let LetSigs be a pack of those types in Sigs with a return type of *decayed-typeof*<*set-cpo*>[.](#9.sentence-2)
|
||||
|
||||
Let *as-tuple* be an alias template
|
||||
such that *as-tuple*<Tag(Args...)> denotes
|
||||
the type *decayed-tuple*<Args...>[.](#9.sentence-3)
|
||||
|
||||
Then args_variant_t denotes
|
||||
the type variant<monostate, *as-tuple*<LetSigs>...> except with duplicate types removed[.](#9.sentence-4)
|
||||
|
||||
[10](#10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4028)
|
||||
|
||||
Given a type Tag and a pack Args,
|
||||
let *as-sndr2* be an alias template
|
||||
such that *as-sndr2*<Tag(Args...)> denotes
|
||||
the type *call-result-t*<F, decay_t<Args>&...>[.](#10.sentence-1)
|
||||
|
||||
Then ops2_variant_t denotes
|
||||
the typevariant<monostate, connect_result_t<*as-sndr2*<LetSigs>, *receiver2*<Rcvr, env_t>>...> except with duplicate types removed[.](#10.sentence-2)
|
||||
|
||||
[11](#11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4040)
|
||||
|
||||
The [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]") constraining the above lambda is satisfied
|
||||
if and only if
|
||||
the types args_variant_t and ops2_variant_t are well-formed[.](#11.sentence-1)
|
||||
|
||||
[12](#12)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4045)
|
||||
|
||||
The exposition-only function template *let-bind* has effects equivalent to:using args_t = *decayed-tuple*<Args...>;auto mkop2 = [&] {return connect( apply(std::move(state.fn),
|
||||
state.args.template emplace<args_t>(std::forward<Args>(args)...)), *receiver2*{rcvr, std::move(state.env)});};
|
||||
start(state.ops2.template emplace<decltype(mkop2())>(*emplace-from*{mkop2}));
|
||||
|
||||
[13](#13)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4059)
|
||||
|
||||
*impls-for*<*decayed-typeof*<let-cpo>>::*complete* is initialized with a callable object equivalent to the following:[]<class Tag, class... Args>(auto, auto& state, auto& rcvr, Tag, Args&&... args) noexcept -> void {if constexpr ([same_as](concept.same#concept:same_as "18.4.2 Concept same_as [concept.same]")<Tag, *decayed-typeof*<*set-cpo*>>) {*TRY-EVAL*(rcvr, *let-bind*(state, rcvr, std::forward<Args>(args)...)); } else { Tag()(std::move(rcvr), std::forward<Args>(args)...); }}
|
||||
|
||||
[14](#14)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4073)
|
||||
|
||||
Let sndr and env be subexpressions, and
|
||||
let Sndr be decltype((sndr))[.](#14.sentence-1)
|
||||
|
||||
If[*sender-for*](exec.snd.concepts#concept:sender-for "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr, *decayed-typeof*<*let-cpo*>> is false,
|
||||
then the expression *let-cpo*.transform_env(sndr, env) is ill-formed[.](#14.sentence-2)
|
||||
|
||||
Otherwise, it is equal to:auto& [_, _, child] = sndr;return *JOIN-ENV*(*let-env*(child), *FWD-ENV*(env));
|
||||
|
||||
[15](#15)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4087)
|
||||
|
||||
Let the subexpression out_sndr denote
|
||||
the result of the invocation *let-cpo*(sndr, f) or
|
||||
an object equal to such, and
|
||||
let the subexpression rcvr denote a receiver
|
||||
such that the expression connect(out_sndr, rcvr) is well-formed[.](#15.sentence-1)
|
||||
|
||||
The expression connect(out_sndr, rcvr) has undefined behavior
|
||||
unless it creates an asynchronous operation ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations")) that,
|
||||
when started:
|
||||
|
||||
- [(15.1)](#15.1)
|
||||
|
||||
invokes f when *set-cpo* is called
|
||||
with sndr's result datums,
|
||||
|
||||
- [(15.2)](#15.2)
|
||||
|
||||
makes its completion dependent on
|
||||
the completion of a sender returned by f, and
|
||||
|
||||
- [(15.3)](#15.3)
|
||||
|
||||
propagates the other completion operations sent by sndr[.](#15.sentence-2)
|
||||
211
cppdraft/exec/on.md
Normal file
211
cppdraft/exec/on.md
Normal file
@@ -0,0 +1,211 @@
|
||||
[exec.on]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#exec.on)
|
||||
|
||||
### 33.9.12 Sender adaptors [[exec.adapt]](exec.adapt#exec.on)
|
||||
|
||||
#### 33.9.12.8 execution::on [exec.on]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3561)
|
||||
|
||||
The on sender adaptor has two forms:
|
||||
|
||||
- [(1.1)](#1.1)
|
||||
|
||||
on(sch, sndr),
|
||||
which starts a sender sndr on an execution agent
|
||||
belonging to a scheduler sch's associated execution resource and
|
||||
that, upon sndr's completion,
|
||||
transfers execution back to the execution resource
|
||||
on which the on sender was started[.](#1.1.sentence-1)
|
||||
|
||||
- [(1.2)](#1.2)
|
||||
|
||||
on(sndr, sch, closure),
|
||||
which upon completion of a sender sndr,
|
||||
transfers execution to an execution agent
|
||||
belonging to a scheduler sch's associated execution resource,
|
||||
then executes a sender adaptor closure closure with the async results of the sender, and
|
||||
that then transfers execution back to the execution resource
|
||||
on which sndr completed[.](#1.2.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3582)
|
||||
|
||||
The name on denotes a pipeable sender adaptor object[.](#2.sentence-1)
|
||||
|
||||
For subexpressions sch and sndr,on(sch, sndr) is ill-formed if any of the following is true:
|
||||
|
||||
- [(2.1)](#2.1)
|
||||
|
||||
decltype((sch)) does not satisfy [scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]"), or
|
||||
|
||||
- [(2.2)](#2.2)
|
||||
|
||||
decltype((sndr)) does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") andsndr is not
|
||||
a pipeable sender adaptor closure object ([[exec.adapt.obj]](exec.adapt.obj "33.9.12.2 Closure objects")), or
|
||||
|
||||
- [(2.3)](#2.3)
|
||||
|
||||
decltype((sndr)) satisfies [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") andsndr is also a pipeable sender adaptor closure object[.](#2.sentence-2)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3598)
|
||||
|
||||
Otherwise, if decltype((sndr)) satisfies [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"),
|
||||
the expression on(sch, sndr) is expression-equivalent to:transform_sender(*query-with-default*(get_domain, sch, default_domain()), *make-sender*(on, sch, sndr)) except that sch is evaluated only once[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3608)
|
||||
|
||||
For subexpressions sndr, sch, and closure, if
|
||||
|
||||
- [(4.1)](#4.1)
|
||||
|
||||
decltype((sch)) does not satisfy [scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]"), or
|
||||
|
||||
- [(4.2)](#4.2)
|
||||
|
||||
decltype((sndr)) does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"), or
|
||||
|
||||
- [(4.3)](#4.3)
|
||||
|
||||
closure is not a pipeable sender adaptor closure object ([[exec.adapt.obj]](exec.adapt.obj "33.9.12.2 Closure objects")),
|
||||
|
||||
the expression on(sndr, sch, closure) is ill-formed;
|
||||
otherwise, it is expression-equivalent to:transform_sender(*get-domain-early*(sndr), *make-sender*(on, *product-type*{sch, closure}, sndr)) except that sndr is evaluated only once[.](#4.sentence-1)
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3627)
|
||||
|
||||
Let out_sndr and env be subexpressions,
|
||||
let OutSndr be decltype((out_sndr)), and
|
||||
let Env be decltype((env))[.](#5.sentence-1)
|
||||
|
||||
If [*sender-for*](exec.snd.concepts#concept:sender-for "33.9.3 Sender concepts [exec.snd.concepts]")<OutSndr, on_t> is false,
|
||||
then the expressions on.transform_env(out_sndr, env) andon.transform_sender(out_sndr, env) are ill-formed[.](#5.sentence-2)
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3635)
|
||||
|
||||
Otherwise:
|
||||
Let *not-a-scheduler* be an unspecified empty class type[.](#6.sentence-1)
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3639)
|
||||
|
||||
The expression on.transform_env(out_sndr, env) has effects equivalent to:auto&& [_, data, _] = out_sndr;if constexpr ([scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]")<decltype(data)>) {return *JOIN-ENV*(*SCHED-ENV*(std::forward_like<OutSndr>(data)), *FWD-ENV*(std::forward<Env>(env)));} else {return std::forward<Env>(env);}
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3651)
|
||||
|
||||
The expression on.transform_sender(out_sndr, env) has effects equivalent to:auto&& [_, data, child] = out_sndr;if constexpr ([scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]")<decltype(data)>) {auto orig_sch =*query-with-default*(get_scheduler, env, *not-a-scheduler*()); if constexpr ([same_as](concept.same#concept:same_as "18.4.2 Concept same_as [concept.same]")<decltype(orig_sch), *not-a-scheduler*>) {return *not-a-sender*{}; } else {return continues_on( starts_on(std::forward_like<OutSndr>(data), std::forward_like<OutSndr>(child)),
|
||||
std::move(orig_sch)); }} else {auto& [sch, closure] = data; auto orig_sch = *query-with-default*( get_completion_scheduler<set_value_t>,
|
||||
get_env(child), *query-with-default*(get_scheduler, env, *not-a-scheduler*())); if constexpr ([same_as](concept.same#concept:same_as "18.4.2 Concept same_as [concept.same]")<decltype(orig_sch), *not-a-scheduler*>) {return *not-a-sender*{}; } else {return write_env( continues_on( std::forward_like<OutSndr>(closure)( continues_on( write_env(std::forward_like<OutSndr>(child), *SCHED-ENV*(orig_sch)),
|
||||
sch)),
|
||||
orig_sch), *SCHED-ENV*(sch)); }}
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3689)
|
||||
|
||||
Let out_sndr be a subexpression denoting
|
||||
a sender returned from on(sch, sndr) or one equal to such, and
|
||||
let OutSndr be the type decltype((out_sndr))[.](#9.sentence-1)
|
||||
|
||||
Let out_rcvr be a subexpression denoting a receiver
|
||||
that has an environment of type Env such that [sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<OutSndr, Env> is true[.](#9.sentence-2)
|
||||
|
||||
Let op be an lvalue referring to the operation state
|
||||
that results from connecting out_sndr with out_rcvr[.](#9.sentence-3)
|
||||
|
||||
Calling start(op) shall
|
||||
|
||||
- [(9.1)](#9.1)
|
||||
|
||||
remember the current scheduler, get_scheduler(get_env(rcvr));
|
||||
|
||||
- [(9.2)](#9.2)
|
||||
|
||||
start sndr on an execution agent belonging tosch's associated execution resource;
|
||||
|
||||
- [(9.3)](#9.3)
|
||||
|
||||
upon sndr's completion,
|
||||
transfer execution back to the execution resource
|
||||
associated with the scheduler remembered in step 1; and
|
||||
|
||||
- [(9.4)](#9.4)
|
||||
|
||||
forward sndr's async result to out_rcvr[.](#9.sentence-4)
|
||||
|
||||
If any scheduling operation fails,
|
||||
an error completion on out_rcvr shall be executed
|
||||
on an unspecified execution agent[.](#9.sentence-5)
|
||||
|
||||
[10](#10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3716)
|
||||
|
||||
Let out_sndr be a subexpression denoting
|
||||
a sender returned from on(sndr, sch, closure) or one equal to such, and
|
||||
let OutSndr be the type decltype((out_sndr))[.](#10.sentence-1)
|
||||
|
||||
Let out_rcvr be a subexpression denoting a receiver
|
||||
that has an environment of type Env such that [sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<OutSndr, Env> is true[.](#10.sentence-2)
|
||||
|
||||
Let op be an lvalue referring to the operation state
|
||||
that results from connecting out_sndr with out_rcvr[.](#10.sentence-3)
|
||||
|
||||
Calling start(op) shall
|
||||
|
||||
- [(10.1)](#10.1)
|
||||
|
||||
remember the current scheduler,
|
||||
which is the first of the following expressions that is well-formed:
|
||||
* [(10.1.1)](#10.1.1)
|
||||
|
||||
get_completion_scheduler<set_value_t>(get_env(sndr))
|
||||
|
||||
* [(10.1.2)](#10.1.2)
|
||||
|
||||
get_scheduler(get_env(rcvr));
|
||||
|
||||
- [(10.2)](#10.2)
|
||||
|
||||
start sndr on the current execution agent;
|
||||
|
||||
- [(10.3)](#10.3)
|
||||
|
||||
upon sndr's completion,
|
||||
transfer execution to an agent
|
||||
owned by sch's associated execution resource;
|
||||
|
||||
- [(10.4)](#10.4)
|
||||
|
||||
forward sndr's async result as if by
|
||||
connecting and starting a sender closure(S),
|
||||
where S is a sender
|
||||
that completes synchronously with sndr's async result; and
|
||||
|
||||
- [(10.5)](#10.5)
|
||||
|
||||
upon completion of the operation started in the previous step,
|
||||
transfer execution back to the execution resource
|
||||
associated with the scheduler remembered in step 1 and
|
||||
forward the operation's async result to out_rcvr[.](#10.sentence-4)
|
||||
|
||||
If any scheduling operation fails,
|
||||
an error completion on out_rcvr shall be executed on
|
||||
an unspecified execution agent[.](#10.sentence-5)
|
||||
67
cppdraft/exec/opstate.md
Normal file
67
cppdraft/exec/opstate.md
Normal file
@@ -0,0 +1,67 @@
|
||||
[exec.opstate]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.8 Operation states [exec.opstate]
|
||||
|
||||
### [33.8.1](#general) General [[exec.opstate.general]](exec.opstate.general)
|
||||
|
||||
[1](#general-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1273)
|
||||
|
||||
The [operation_state](#concept:operation_state "33.8.1 General [exec.opstate.general]") concept defines
|
||||
the requirements of an operation state type ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations"))[.](#general-1.sentence-1)
|
||||
|
||||
namespace std::execution {template<class O>concept [operation_state](#concept:operation_state "33.8.1 General [exec.opstate.general]") =[derived_from](concept.derived#concept:derived_from "18.4.3 Concept derived_from [concept.derived]")<typename O::operation_state_concept, operation_state_t> &&requires (O& o) { start(o); };}
|
||||
|
||||
[2](#general-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1287)
|
||||
|
||||
If an [operation_state](#concept:operation_state "33.8.1 General [exec.opstate.general]") object is destroyed
|
||||
during the lifetime of its asynchronous operation ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations")),
|
||||
the behavior is undefined[.](#general-2.sentence-1)
|
||||
|
||||
[*Note [1](#general-note-1)*:
|
||||
|
||||
The [operation_state](#concept:operation_state "33.8.1 General [exec.opstate.general]") concept does not impose requirements
|
||||
on any operations other than destruction and start,
|
||||
including copy and move operations[.](#general-2.sentence-2)
|
||||
|
||||
Invoking any such operation on an object
|
||||
whose type models [operation_state](#concept:operation_state "33.8.1 General [exec.opstate.general]") can lead to undefined behavior[.](#general-2.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[3](#general-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1299)
|
||||
|
||||
The program is ill-formed
|
||||
if it performs a copy or move construction or assignment operation on
|
||||
an operation state object created by connecting a library-provided sender[.](#general-3.sentence-1)
|
||||
|
||||
### [33.8.2](#start) execution::start [[exec.opstate.start]](exec.opstate.start)
|
||||
|
||||
[1](#start-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1306)
|
||||
|
||||
The name start denotes a customization point object
|
||||
that starts ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations"))
|
||||
the asynchronous operation associated with the operation state object[.](#start-1.sentence-1)
|
||||
|
||||
For a subexpression op,
|
||||
the expression start(op) is ill-formed
|
||||
if op is an rvalue[.](#start-1.sentence-2)
|
||||
|
||||
Otherwise, it is expression-equivalent to*MANDATE-NOTHROW*(op.start())[.](#start-1.sentence-3)
|
||||
|
||||
[2](#start-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1316)
|
||||
|
||||
If op.start() does not start ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations"))
|
||||
the asynchronous operation associated with the operation state op,
|
||||
the behavior of calling start(op) is undefined[.](#start-2.sentence-1)
|
||||
43
cppdraft/exec/opstate/general.md
Normal file
43
cppdraft/exec/opstate/general.md
Normal file
@@ -0,0 +1,43 @@
|
||||
[exec.opstate.general]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.8 Operation states [[exec.opstate]](exec.opstate#general)
|
||||
|
||||
### 33.8.1 General [exec.opstate.general]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1273)
|
||||
|
||||
The [operation_state](#concept:operation_state "33.8.1 General [exec.opstate.general]") concept defines
|
||||
the requirements of an operation state type ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations"))[.](#1.sentence-1)
|
||||
|
||||
namespace std::execution {template<class O>concept [operation_state](#concept:operation_state "33.8.1 General [exec.opstate.general]") =[derived_from](concept.derived#concept:derived_from "18.4.3 Concept derived_from [concept.derived]")<typename O::operation_state_concept, operation_state_t> &&requires (O& o) { start(o); };}
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1287)
|
||||
|
||||
If an [operation_state](#concept:operation_state "33.8.1 General [exec.opstate.general]") object is destroyed
|
||||
during the lifetime of its asynchronous operation ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations")),
|
||||
the behavior is undefined[.](#2.sentence-1)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
The [operation_state](#concept:operation_state "33.8.1 General [exec.opstate.general]") concept does not impose requirements
|
||||
on any operations other than destruction and start,
|
||||
including copy and move operations[.](#2.sentence-2)
|
||||
|
||||
Invoking any such operation on an object
|
||||
whose type models [operation_state](#concept:operation_state "33.8.1 General [exec.opstate.general]") can lead to undefined behavior[.](#2.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1299)
|
||||
|
||||
The program is ill-formed
|
||||
if it performs a copy or move construction or assignment operation on
|
||||
an operation state object created by connecting a library-provided sender[.](#3.sentence-1)
|
||||
29
cppdraft/exec/opstate/start.md
Normal file
29
cppdraft/exec/opstate/start.md
Normal file
@@ -0,0 +1,29 @@
|
||||
[exec.opstate.start]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.8 Operation states [[exec.opstate]](exec.opstate#start)
|
||||
|
||||
### 33.8.2 execution::start [exec.opstate.start]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1306)
|
||||
|
||||
The name start denotes a customization point object
|
||||
that starts ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations"))
|
||||
the asynchronous operation associated with the operation state object[.](#1.sentence-1)
|
||||
|
||||
For a subexpression op,
|
||||
the expression start(op) is ill-formed
|
||||
if op is an rvalue[.](#1.sentence-2)
|
||||
|
||||
Otherwise, it is expression-equivalent to*MANDATE-NOTHROW*(op.start())[.](#1.sentence-3)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1316)
|
||||
|
||||
If op.start() does not start ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations"))
|
||||
the asynchronous operation associated with the operation state op,
|
||||
the behavior of calling start(op) is undefined[.](#2.sentence-1)
|
||||
188
cppdraft/exec/par/scheduler.md
Normal file
188
cppdraft/exec/par/scheduler.md
Normal file
@@ -0,0 +1,188 @@
|
||||
[exec.par.scheduler]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.15 Parallel scheduler [exec.par.scheduler]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8281)
|
||||
|
||||
parallel_scheduler models [scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]")[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8284)
|
||||
|
||||
Let sch be an object of type parallel_scheduler, and
|
||||
let *BACKEND-OF*(sch) be *ptr,
|
||||
where sch is associated with ptr[.](#2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8289)
|
||||
|
||||
The expression get_forward_progress_guarantee(sch) has the valueforward_progress_guarantee::parallel[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8293)
|
||||
|
||||
Let sch2 be an object of type parallel_scheduler[.](#4.sentence-1)
|
||||
|
||||
Two objects sch and sch2 compare equal if and only if*BACKEND-OF*(sch) and*BACKEND-OF*(sch2) refer to the same object[.](#4.sentence-2)
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8299)
|
||||
|
||||
Let rcvr be a receiver[.](#5.sentence-1)
|
||||
|
||||
A [*proxy for rcvr with base B*](#def:proxy "33.15 Parallel scheduler [exec.par.scheduler]") is
|
||||
an lvalue r of type B such that:
|
||||
|
||||
- [(5.1)](#5.1)
|
||||
|
||||
r.set_value() has effects equivalent toset_value(std::move(rcvr))[.](#5.1.sentence-1)
|
||||
|
||||
- [(5.2)](#5.2)
|
||||
|
||||
r.set_error(e), where e is an exception_ptr object,
|
||||
has effects equivalent to set_error(std::move(rcvr), std::move(e))[.](#5.2.sentence-1)
|
||||
|
||||
- [(5.3)](#5.3)
|
||||
|
||||
r.set_stopped() has effects equivalent toset_stopped(std::move(rcvr))[.](#5.3.sentence-1)
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8315)
|
||||
|
||||
A [*preallocated backend storage for a proxy*](#def:preallocated_backend_storage_for_a_proxy "33.15 Parallel scheduler [exec.par.scheduler]") r is
|
||||
an object s of type span<byte> such that the range s remains valid and may be overwritten
|
||||
until one of set_value, set_error, or set_stopped is called on r[.](#6.sentence-1)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
The storage referenced by s can be used as temporary storage
|
||||
for operations launched via calls to parallel_scheduler_backend[.](#6.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8326)
|
||||
|
||||
A [*bulk chunked proxy for rcvr with callable f and arguments args*](#def:proxy,bulk_chunked "33.15 Parallel scheduler [exec.par.scheduler]") is a proxy r for rcvr with base system_context_replaceability::bulk_item_receiver_proxy such thatr.execute(i, j) for indices i and j has effects equivalent to f(i, j, args...)[.](#7.sentence-1)
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8335)
|
||||
|
||||
A [*bulk unchunked proxy for rcvr with callable f and arguments args*](#def:proxy,bulk_unchunked "33.15 Parallel scheduler [exec.par.scheduler]") is a proxy r for rcvr with base system_context_replaceability::bulk_item_receiver_proxy such thatr.execute(i, i + 1) for index i has effects equivalent to f(i, args...)[.](#8.sentence-1)
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8344)
|
||||
|
||||
Let b be *BACKEND-OF*(sch),
|
||||
let sndr be the object returned by schedule(sch), and
|
||||
let rcvr be a receiver[.](#9.sentence-1)
|
||||
|
||||
If rcvr is connected to sndr and
|
||||
the resulting operation state is started, then:
|
||||
|
||||
- [(9.1)](#9.1)
|
||||
|
||||
If sndr completes successfully,
|
||||
then b.schedule(r, s) is called, where
|
||||
* [(9.1.1)](#9.1.1)
|
||||
|
||||
r is a proxy for rcvr with base system_context_replaceability::receiver_proxy and
|
||||
|
||||
* [(9.1.2)](#9.1.2)
|
||||
|
||||
s is a preallocated backend storage for r[.](#9.1.sentence-1)
|
||||
|
||||
- [(9.2)](#9.2)
|
||||
|
||||
All other completion operations are forwarded unchanged[.](#9.2.sentence-1)
|
||||
|
||||
[10](#10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8365)
|
||||
|
||||
parallel_scheduler provides a customized implementation of
|
||||
the bulk_chunked algorithm ([[exec.bulk]](exec.bulk "33.9.12.11 execution::bulk, execution::bulk_chunked, and execution::bulk_unchunked"))[.](#10.sentence-1)
|
||||
|
||||
If a receiver rcvr is connected to the sender
|
||||
returned by bulk_chunked(sndr, pol, shape, f) and
|
||||
the resulting operation state is started, then:
|
||||
|
||||
- [(10.1)](#10.1)
|
||||
|
||||
If sndr completes with values vals,
|
||||
let args be a pack of lvalue subexpressions designating vals,
|
||||
then b.schedule_bulk_chunked(shape, r, s) is called, where
|
||||
* [(10.1.1)](#10.1.1)
|
||||
|
||||
r is a bulk chunked proxy for rcvr with callable f and arguments args and
|
||||
|
||||
* [(10.1.2)](#10.1.2)
|
||||
|
||||
s is a preallocated backend storage for r[.](#10.1.sentence-1)
|
||||
|
||||
- [(10.2)](#10.2)
|
||||
|
||||
All other completion operations are forwarded unchanged[.](#10.2.sentence-1)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
Customizing the behavior of bulk_chunked affects the default implementation of bulk[.](#10.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[11](#11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8391)
|
||||
|
||||
parallel_scheduler provides a customized implementation of
|
||||
the bulk_unchunked algorithm ([[exec.bulk]](exec.bulk "33.9.12.11 execution::bulk, execution::bulk_chunked, and execution::bulk_unchunked"))[.](#11.sentence-1)
|
||||
|
||||
If a receiver rcvr is connected to the sender
|
||||
returned by bulk_unchunked(sndr, pol, shape, f) and
|
||||
the resulting operation state is started, then:
|
||||
|
||||
- [(11.1)](#11.1)
|
||||
|
||||
If sndr completes with values vals,
|
||||
let args be a pack of lvalue subexpressions designating vals,
|
||||
then b.schedule_bulk_unchunked(shape, r, s) is called, where
|
||||
* [(11.1.1)](#11.1.1)
|
||||
|
||||
r is a bulk unchunked proxy for rcvr with callable f and arguments args and
|
||||
|
||||
* [(11.1.2)](#11.1.2)
|
||||
|
||||
s is a preallocated backend storage for r[.](#11.1.sentence-1)
|
||||
|
||||
- [(11.2)](#11.2)
|
||||
|
||||
All other completion operations are forwarded unchanged[.](#11.2.sentence-1)
|
||||
|
||||
[ð](#lib:get_parallel_scheduler)
|
||||
|
||||
`parallel_scheduler get_parallel_scheduler();
|
||||
`
|
||||
|
||||
[12](#12)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8419)
|
||||
|
||||
*Effects*: Let eb be the result of system_context_replaceability::query_parallel_scheduler_backend()[.](#12.sentence-1)
|
||||
|
||||
If eb == nullptr is true,
|
||||
calls terminate ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#12.sentence-2)
|
||||
|
||||
Otherwise, returns a parallel_scheduler object
|
||||
associated with eb[.](#12.sentence-3)
|
||||
35
cppdraft/exec/prop.md
Normal file
35
cppdraft/exec/prop.md
Normal file
@@ -0,0 +1,35 @@
|
||||
[exec.prop]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.11 Queryable utilities [[exec.envs]](exec.envs#exec.prop)
|
||||
|
||||
### 33.11.1 Class template prop [exec.prop]
|
||||
|
||||
namespace std::execution {template<class QueryTag, class ValueType>struct [prop](#lib:prop "33.11.1 Class template prop [exec.prop]") { QueryTag *query_*; // *exposition only* ValueType *value_*; // *exposition only*constexpr const ValueType& query(QueryTag) const noexcept {return *value_*; }}; template<class QueryTag, class ValueType> prop(QueryTag, ValueType) -> prop<QueryTag, unwrap_reference_t<ValueType>>;}
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6193)
|
||||
|
||||
Class template prop is for building a queryable object
|
||||
from a query object and a value[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6197)
|
||||
|
||||
*Mandates*: [*callable*](functional.syn#concept:callable "22.10.2 Header <functional> synopsis [functional.syn]")<QueryTag, *prop-like*<ValueType>> is modeled,
|
||||
where *prop-like* is the following exposition-only class template:template<class ValueType>struct *prop-like* { // *exposition only*const ValueType& query(auto) const noexcept;};
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6209)
|
||||
|
||||
[*Example [1](#example-1)*: template<[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sndr> sender auto parameterize_work(Sndr sndr) {// Make an environment such that get_allocator(env) returns a reference to a copy of my_alloc{}.auto e = prop(get_allocator, my_alloc{}); // Parameterize the input sender so that it will use our custom execution environment.return write_env(sndr, e);} â *end example*]
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6223)
|
||||
|
||||
Specializations of prop are not assignable[.](#4.sentence-1)
|
||||
325
cppdraft/exec/queries.md
Normal file
325
cppdraft/exec/queries.md
Normal file
@@ -0,0 +1,325 @@
|
||||
[exec.queries]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.5 Queries [exec.queries]
|
||||
|
||||
### [33.5.1](#exec.fwd.env) forwarding_query [[exec.fwd.env]](exec.fwd.env)
|
||||
|
||||
[1](#exec.fwd.env-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L837)
|
||||
|
||||
forwarding_query asks a query object
|
||||
whether it should be forwarded through queryable adaptors[.](#exec.fwd.env-1.sentence-1)
|
||||
|
||||
[2](#exec.fwd.env-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L841)
|
||||
|
||||
The name forwarding_query denotes a query object[.](#exec.fwd.env-2.sentence-1)
|
||||
|
||||
For some query object q of type Q,forwarding_query(q) is expression-equivalent to:
|
||||
|
||||
- [(2.1)](#exec.fwd.env-2.1)
|
||||
|
||||
*MANDATE-NOTHROW*(q.query(forwarding_query)) if that expression is well-formed[.](#exec.fwd.env-2.1.sentence-1)
|
||||
*Mandates*: The expression above has type bool and
|
||||
is a core constant expression if q is a core constant expression[.](#exec.fwd.env-2.1.sentence-2)
|
||||
|
||||
- [(2.2)](#exec.fwd.env-2.2)
|
||||
|
||||
Otherwise, true if [derived_from](concept.derived#concept:derived_from "18.4.3 Concept derived_from [concept.derived]")<Q, forwarding_query_t> is true[.](#exec.fwd.env-2.2.sentence-1)
|
||||
|
||||
- [(2.3)](#exec.fwd.env-2.3)
|
||||
|
||||
Otherwise, false[.](#exec.fwd.env-2.3.sentence-1)
|
||||
|
||||
### [33.5.2](#exec.get.allocator) get_allocator [[exec.get.allocator]](exec.get.allocator)
|
||||
|
||||
[1](#exec.get.allocator-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L861)
|
||||
|
||||
get_allocator asks a queryable object for its associated allocator[.](#exec.get.allocator-1.sentence-1)
|
||||
|
||||
[2](#exec.get.allocator-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L864)
|
||||
|
||||
The name get_allocator denotes a query object[.](#exec.get.allocator-2.sentence-1)
|
||||
|
||||
For a subexpression env,get_allocator(env) is expression-equivalent to*MANDATE-NOTHROW*(*AS-CONST*(env).query(get_allocator))[.](#exec.get.allocator-2.sentence-2)
|
||||
|
||||
*Mandates*: If the expression above is well-formed,
|
||||
its type satisfies[*simple-allocator*](allocator.requirements.general#concept:simple-allocator "16.4.4.6.1 General [allocator.requirements.general]") ([[allocator.requirements.general]](allocator.requirements.general "16.4.4.6.1 General"))[.](#exec.get.allocator-2.sentence-3)
|
||||
|
||||
[3](#exec.get.allocator-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L875)
|
||||
|
||||
forwarding_query(get_allocator) is a core constant expression and
|
||||
has value true[.](#exec.get.allocator-3.sentence-1)
|
||||
|
||||
### [33.5.3](#exec.get.stop.token) get_stop_token [[exec.get.stop.token]](exec.get.stop.token)
|
||||
|
||||
[1](#exec.get.stop.token-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L881)
|
||||
|
||||
get_stop_token asks a queryable object for an associated stop token[.](#exec.get.stop.token-1.sentence-1)
|
||||
|
||||
[2](#exec.get.stop.token-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L884)
|
||||
|
||||
The name get_stop_token denotes a query object[.](#exec.get.stop.token-2.sentence-1)
|
||||
|
||||
For a subexpression env,get_stop_token(env) is expression-equivalent to:
|
||||
|
||||
- [(2.1)](#exec.get.stop.token-2.1)
|
||||
|
||||
*MANDATE-NOTHROW*(*AS-CONST*(env).query(get_stop_token)) if that expression is well-formed[.](#exec.get.stop.token-2.1.sentence-1)
|
||||
*Mandates*: The type of the expression above satisfies [stoppable_token](stoptoken.concepts#concept:stoppable_token "32.3.3 Stop token concepts [stoptoken.concepts]")[.](#exec.get.stop.token-2.1.sentence-2)
|
||||
|
||||
- [(2.2)](#exec.get.stop.token-2.2)
|
||||
|
||||
Otherwise, never_stop_token{}[.](#exec.get.stop.token-2.2.sentence-1)
|
||||
|
||||
[3](#exec.get.stop.token-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L900)
|
||||
|
||||
forwarding_query(get_stop_token) is a core constant expression and
|
||||
has value true[.](#exec.get.stop.token-3.sentence-1)
|
||||
|
||||
### [33.5.4](#exec.get.env) execution::get_env [[exec.get.env]](exec.get.env)
|
||||
|
||||
[1](#exec.get.env-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L906)
|
||||
|
||||
execution::get_env is a customization point object[.](#exec.get.env-1.sentence-1)
|
||||
|
||||
For a subexpression o,execution::get_env(o) is expression-equivalent to:
|
||||
|
||||
- [(1.1)](#exec.get.env-1.1)
|
||||
|
||||
*MANDATE-NOTHROW*(*AS-CONST*(o).get_env()) if that expression is well-formed[.](#exec.get.env-1.1.sentence-1)
|
||||
*Mandates*: The type of the expression above satisfies[*queryable*](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]") ([[exec.queryable]](exec.queryable "33.2 Queries and queryables"))[.](#exec.get.env-1.1.sentence-2)
|
||||
|
||||
- [(1.2)](#exec.get.env-1.2)
|
||||
|
||||
Otherwise, env<>{}[.](#exec.get.env-1.2.sentence-1)
|
||||
|
||||
[2](#exec.get.env-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L922)
|
||||
|
||||
The value of get_env(o) shall be valid while o is valid[.](#exec.get.env-2.sentence-1)
|
||||
|
||||
[3](#exec.get.env-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L925)
|
||||
|
||||
[*Note [1](#exec.get.env-note-1)*:
|
||||
|
||||
When passed a sender object,get_env returns the sender's associated attributes[.](#exec.get.env-3.sentence-1)
|
||||
|
||||
When passed a receiver,get_env returns the receiver's associated execution environment[.](#exec.get.env-3.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
### [33.5.5](#exec.get.domain) execution::get_domain [[exec.get.domain]](exec.get.domain)
|
||||
|
||||
[1](#exec.get.domain-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L935)
|
||||
|
||||
get_domain asks a queryable object
|
||||
for its associated execution domain tag[.](#exec.get.domain-1.sentence-1)
|
||||
|
||||
[2](#exec.get.domain-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L939)
|
||||
|
||||
The name get_domain denotes a query object[.](#exec.get.domain-2.sentence-1)
|
||||
|
||||
For a subexpression env,get_domain(env) is expression-equivalent to*MANDATE-NOTHROW*(*AS-CONST*(env).query(get_domain))[.](#exec.get.domain-2.sentence-2)
|
||||
|
||||
[3](#exec.get.domain-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L945)
|
||||
|
||||
forwarding_query(execution::get_domain) is
|
||||
a core constant expression and has value true[.](#exec.get.domain-3.sentence-1)
|
||||
|
||||
### [33.5.6](#exec.get.scheduler) execution::get_scheduler [[exec.get.scheduler]](exec.get.scheduler)
|
||||
|
||||
[1](#exec.get.scheduler-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L951)
|
||||
|
||||
get_scheduler asks a queryable object for its associated scheduler[.](#exec.get.scheduler-1.sentence-1)
|
||||
|
||||
[2](#exec.get.scheduler-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L954)
|
||||
|
||||
The name get_scheduler denotes a query object[.](#exec.get.scheduler-2.sentence-1)
|
||||
|
||||
For a subexpression env,get_scheduler(env) is expression-equivalent to*MANDATE-NOTHROW*(*AS-CONST*(env).query(get_scheduler))[.](#exec.get.scheduler-2.sentence-2)
|
||||
|
||||
*Mandates*: If the expression above is well-formed,
|
||||
its type satisfies [scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]")[.](#exec.get.scheduler-2.sentence-3)
|
||||
|
||||
[3](#exec.get.scheduler-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L964)
|
||||
|
||||
forwarding_query(execution::get_scheduler) is
|
||||
a core constant expression and has value true[.](#exec.get.scheduler-3.sentence-1)
|
||||
|
||||
### [33.5.7](#exec.get.delegation.scheduler) execution::get_delegation_scheduler [[exec.get.delegation.scheduler]](exec.get.delegation.scheduler)
|
||||
|
||||
[1](#exec.get.delegation.scheduler-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L970)
|
||||
|
||||
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 ([[intro.progress]](intro.progress "6.10.2.3 Forward progress"))[.](#exec.get.delegation.scheduler-1.sentence-1)
|
||||
|
||||
[2](#exec.get.delegation.scheduler-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L975)
|
||||
|
||||
The name get_delegation_scheduler denotes a query object[.](#exec.get.delegation.scheduler-2.sentence-1)
|
||||
|
||||
For a subexpression env,get_delegation_scheduler(env) is expression-equivalent to*MANDATE-NOTHROW*(*AS-CONST*(env).query(get_delegation_scheduler))[.](#exec.get.delegation.scheduler-2.sentence-2)
|
||||
|
||||
*Mandates*: If the expression above is well-formed,
|
||||
its type satisfies [scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]")[.](#exec.get.delegation.scheduler-2.sentence-3)
|
||||
|
||||
[3](#exec.get.delegation.scheduler-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L985)
|
||||
|
||||
forwarding_query(execution::get_delegation_scheduler) is
|
||||
a core constant expression and has value true[.](#exec.get.delegation.scheduler-3.sentence-1)
|
||||
|
||||
### [33.5.8](#exec.get.fwd.progress) execution::get_forward_progress_guarantee [[exec.get.fwd.progress]](exec.get.fwd.progress)
|
||||
|
||||
namespace std::execution {enum class [forward_progress_guarantee](#lib:forward_progress_guarantee "33.5.8 execution::get_forward_progress_guarantee [exec.get.fwd.progress]") { concurrent,
|
||||
parallel,
|
||||
weakly_parallel };}
|
||||
|
||||
[1](#exec.get.fwd.progress-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1001)
|
||||
|
||||
get_forward_progress_guarantee asks a scheduler about
|
||||
the forward progress guarantee of execution agents
|
||||
created by that scheduler's associated execution resource ([[intro.progress]](intro.progress "6.10.2.3 Forward progress"))[.](#exec.get.fwd.progress-1.sentence-1)
|
||||
|
||||
[2](#exec.get.fwd.progress-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1006)
|
||||
|
||||
The name get_forward_progress_guarantee denotes a query object[.](#exec.get.fwd.progress-2.sentence-1)
|
||||
|
||||
For a subexpression sch, let Sch be decltype((sch))[.](#exec.get.fwd.progress-2.sentence-2)
|
||||
|
||||
If Sch does not satisfy [scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]"),get_forward_progress_guarantee is ill-formed[.](#exec.get.fwd.progress-2.sentence-3)
|
||||
|
||||
Otherwise,get_forward_progress_guarantee(sch) is expression-equivalent to:
|
||||
|
||||
- [(2.1)](#exec.get.fwd.progress-2.1)
|
||||
|
||||
*MANDATE-NOTHROW*(*AS-CONST*(sch).query(get_forward_progress_guarantee)),
|
||||
if that expression is well-formed[.](#exec.get.fwd.progress-2.1.sentence-1)
|
||||
*Mandates*: The type of the expression above is forward_progress_guarantee[.](#exec.get.fwd.progress-2.1.sentence-2)
|
||||
|
||||
- [(2.2)](#exec.get.fwd.progress-2.2)
|
||||
|
||||
Otherwise, forward_progress_guarantee::weakly_parallel[.](#exec.get.fwd.progress-2.2.sentence-1)
|
||||
|
||||
[3](#exec.get.fwd.progress-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1024)
|
||||
|
||||
If get_forward_progress_guarantee(sch) for some scheduler sch returns forward_progress_guarantee::concurrent,
|
||||
all execution agents created by that scheduler's associated execution resource
|
||||
shall provide the concurrent forward progress guarantee[.](#exec.get.fwd.progress-3.sentence-1)
|
||||
|
||||
If it returns forward_progress_guarantee::parallel,
|
||||
all such execution agents
|
||||
shall provide at least the parallel forward progress guarantee[.](#exec.get.fwd.progress-3.sentence-2)
|
||||
|
||||
### [33.5.9](#exec.get.compl.sched) execution::get_completion_scheduler [[exec.get.compl.sched]](exec.get.compl.sched)
|
||||
|
||||
[1](#exec.get.compl.sched-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1035)
|
||||
|
||||
get_completion_scheduler<*completion-tag>* obtains
|
||||
the completion scheduler associated with a completion tag
|
||||
from a sender's attributes[.](#exec.get.compl.sched-1.sentence-1)
|
||||
|
||||
[2](#exec.get.compl.sched-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1040)
|
||||
|
||||
The name get_completion_scheduler denotes a query object template[.](#exec.get.compl.sched-2.sentence-1)
|
||||
|
||||
For a subexpression q,
|
||||
the expression get_completion_scheduler<*completion-tag*>(q) is ill-formed if *completion-tag* is not one ofset_value_t, set_error_t, or set_stopped_t[.](#exec.get.compl.sched-2.sentence-2)
|
||||
|
||||
Otherwise, get_completion_scheduler<*completion-tag*>(q) is expression-equivalent to*MANDATE-NOTHROW*(*AS-CONST*(q).query(get_completion_scheduler<*completion-tag*>))*Mandates*: If the expression above is well-formed,
|
||||
its type satisfies [scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]")[.](#exec.get.compl.sched-2.sentence-3)
|
||||
|
||||
[3](#exec.get.compl.sched-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1055)
|
||||
|
||||
Let *completion-fn* be a completion function ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations"));
|
||||
let *completion-tag* be
|
||||
the associated completion tag of *completion-fn*;
|
||||
let args be a pack of subexpressions; and
|
||||
let sndr be a subexpression
|
||||
such that [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]")<decltype((sndr))> is true andget_completion_scheduler<*completion-tag*>(get_env(sndr)) is well-formed and denotes a scheduler sch[.](#exec.get.compl.sched-3.sentence-1)
|
||||
|
||||
If an asynchronous operation
|
||||
created by connecting sndr with a receiver rcvr causes the evaluation of *completion-fn*(rcvr, args...),
|
||||
the behavior is undefined
|
||||
unless the evaluation happens on an execution agent
|
||||
that belongs to sch's associated execution resource[.](#exec.get.compl.sched-3.sentence-2)
|
||||
|
||||
[4](#exec.get.compl.sched-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1071)
|
||||
|
||||
The expressionforwarding_query(get_completion_scheduler<*completion-tag*>) is a core constant expression and has value true[.](#exec.get.compl.sched-4.sentence-1)
|
||||
|
||||
### [33.5.10](#exec.get.await.adapt) execution::get_await_completion_adaptor [[exec.get.await.adapt]](exec.get.await.adapt)
|
||||
|
||||
[1](#exec.get.await.adapt-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1078)
|
||||
|
||||
get_await_completion_adaptor asks a queryable object for
|
||||
its associated awaitable completion adaptor[.](#exec.get.await.adapt-1.sentence-1)
|
||||
|
||||
[2](#exec.get.await.adapt-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1082)
|
||||
|
||||
The name get_await_completion_adaptor denotes a query object[.](#exec.get.await.adapt-2.sentence-1)
|
||||
|
||||
For a subexpression env,get_await_completion_adaptor(env) is expression-equivalent to*MANDATE-NOTHROW*(*AS-CONST*(env).query(get_await_completion_adaptor))
|
||||
|
||||
[3](#exec.get.await.adapt-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1093)
|
||||
|
||||
forwarding_query(execution::get_await_completion_adaptor) is a core constant expression and has value true[.](#exec.get.await.adapt-3.sentence-1)
|
||||
82
cppdraft/exec/queryable.md
Normal file
82
cppdraft/exec/queryable.md
Normal file
@@ -0,0 +1,82 @@
|
||||
[exec.queryable]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.2 Queries and queryables [exec.queryable]
|
||||
|
||||
### [33.2.1](#general) General [[exec.queryable.general]](exec.queryable.general)
|
||||
|
||||
[1](#general-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L115)
|
||||
|
||||
A [*queryable object*](#def:object,queryable "33.2.1 General [exec.queryable.general]") is
|
||||
a read-only collection of key/value pair
|
||||
where each key is a customization point object known as a [*query object*](#def:query_object "33.2.1 General [exec.queryable.general]")[.](#general-1.sentence-1)
|
||||
|
||||
A [*query*](#def:query "33.2.1 General [exec.queryable.general]") is an invocation of a query object
|
||||
with a queryable object as its first argument and
|
||||
a (possibly empty) set of additional arguments[.](#general-1.sentence-2)
|
||||
|
||||
A query imposes syntactic and semantic requirements on its invocations[.](#general-1.sentence-3)
|
||||
|
||||
[2](#general-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L124)
|
||||
|
||||
Let q be a query object,
|
||||
let args be a (possibly empty) pack of subexpressions,
|
||||
let env be a subexpression
|
||||
that refers to a queryable object o of type O, and
|
||||
let cenv be a subexpression referring to o such that decltype((cenv)) is const O&[.](#general-2.sentence-1)
|
||||
|
||||
The expression q(env, args...) is equal to ([[concepts.equality]](concepts.equality "18.2 Equality preservation"))
|
||||
the expression q(cenv, args...)[.](#general-2.sentence-2)
|
||||
|
||||
[3](#general-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L134)
|
||||
|
||||
The type of a query expression cannot be void[.](#general-3.sentence-1)
|
||||
|
||||
[4](#general-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L137)
|
||||
|
||||
The expression q(env, args...) is
|
||||
equality-preserving ([[concepts.equality]](concepts.equality "18.2 Equality preservation")) and
|
||||
does not modify the query object or the arguments[.](#general-4.sentence-1)
|
||||
|
||||
[5](#general-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L142)
|
||||
|
||||
If the expression env.query(q, args...) is well-formed,
|
||||
then it is expression-equivalent to q(env, args...)[.](#general-5.sentence-1)
|
||||
|
||||
[6](#general-6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L146)
|
||||
|
||||
Unless otherwise specified,
|
||||
the result of a query is valid as long as the queryable object is valid[.](#general-6.sentence-1)
|
||||
|
||||
### [33.2.2](#concept) queryable concept [[exec.queryable.concept]](exec.queryable.concept)
|
||||
|
||||
namespace std {template<class T>concept [*queryable*](#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]") = [destructible](concept.destructible#concept:destructible "18.4.10 Concept destructible [concept.destructible]")<T>; // *exposition only*}
|
||||
|
||||
[1](#concept-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L159)
|
||||
|
||||
The exposition-only [*queryable*](#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]") concept specifies
|
||||
the constraints on the types of queryable objects[.](#concept-1.sentence-1)
|
||||
|
||||
[2](#concept-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L163)
|
||||
|
||||
Let env be an object of type Env[.](#concept-2.sentence-1)
|
||||
|
||||
The type Env models [*queryable*](#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]") if for each callable object q and a pack of subexpressions args,
|
||||
if requires { q(env, args...) } is true thenq(env, args...) meets any semantic requirements imposed by q[.](#concept-2.sentence-2)
|
||||
25
cppdraft/exec/queryable/concept.md
Normal file
25
cppdraft/exec/queryable/concept.md
Normal file
@@ -0,0 +1,25 @@
|
||||
[exec.queryable.concept]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.2 Queries and queryables [[exec.queryable]](exec.queryable#concept)
|
||||
|
||||
### 33.2.2 queryable concept [exec.queryable.concept]
|
||||
|
||||
namespace std {template<class T>concept [*queryable*](#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]") = [destructible](concept.destructible#concept:destructible "18.4.10 Concept destructible [concept.destructible]")<T>; // *exposition only*}
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L159)
|
||||
|
||||
The exposition-only [*queryable*](#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]") concept specifies
|
||||
the constraints on the types of queryable objects[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L163)
|
||||
|
||||
Let env be an object of type Env[.](#2.sentence-1)
|
||||
|
||||
The type Env models [*queryable*](#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]") if for each callable object q and a pack of subexpressions args,
|
||||
if requires { q(env, args...) } is true thenq(env, args...) meets any semantic requirements imposed by q[.](#2.sentence-2)
|
||||
62
cppdraft/exec/queryable/general.md
Normal file
62
cppdraft/exec/queryable/general.md
Normal file
@@ -0,0 +1,62 @@
|
||||
[exec.queryable.general]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.2 Queries and queryables [[exec.queryable]](exec.queryable#general)
|
||||
|
||||
### 33.2.1 General [exec.queryable.general]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L115)
|
||||
|
||||
A [*queryable object*](#def:object,queryable "33.2.1 General [exec.queryable.general]") is
|
||||
a read-only collection of key/value pair
|
||||
where each key is a customization point object known as a [*query object*](#def:query_object "33.2.1 General [exec.queryable.general]")[.](#1.sentence-1)
|
||||
|
||||
A [*query*](#def:query "33.2.1 General [exec.queryable.general]") is an invocation of a query object
|
||||
with a queryable object as its first argument and
|
||||
a (possibly empty) set of additional arguments[.](#1.sentence-2)
|
||||
|
||||
A query imposes syntactic and semantic requirements on its invocations[.](#1.sentence-3)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L124)
|
||||
|
||||
Let q be a query object,
|
||||
let args be a (possibly empty) pack of subexpressions,
|
||||
let env be a subexpression
|
||||
that refers to a queryable object o of type O, and
|
||||
let cenv be a subexpression referring to o such that decltype((cenv)) is const O&[.](#2.sentence-1)
|
||||
|
||||
The expression q(env, args...) is equal to ([[concepts.equality]](concepts.equality "18.2 Equality preservation"))
|
||||
the expression q(cenv, args...)[.](#2.sentence-2)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L134)
|
||||
|
||||
The type of a query expression cannot be void[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L137)
|
||||
|
||||
The expression q(env, args...) is
|
||||
equality-preserving ([[concepts.equality]](concepts.equality "18.2 Equality preservation")) and
|
||||
does not modify the query object or the arguments[.](#4.sentence-1)
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L142)
|
||||
|
||||
If the expression env.query(q, args...) is well-formed,
|
||||
then it is expression-equivalent to q(env, args...)[.](#5.sentence-1)
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L146)
|
||||
|
||||
Unless otherwise specified,
|
||||
the result of a query is valid as long as the queryable object is valid[.](#6.sentence-1)
|
||||
57
cppdraft/exec/read/env.md
Normal file
57
cppdraft/exec/read/env.md
Normal file
@@ -0,0 +1,57 @@
|
||||
[exec.read.env]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#exec.read.env)
|
||||
|
||||
### 33.9.11 Sender factories [[exec.factories]](exec.factories#exec.read.env)
|
||||
|
||||
#### 33.9.11.3 execution::read_env [exec.read.env]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2950)
|
||||
|
||||
read_env is a sender factory for a sender
|
||||
whose asynchronous operation completes synchronously in its start operation
|
||||
with a value completion result equal to
|
||||
a value read from the receiver's associated environment[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2956)
|
||||
|
||||
read_env is a customization point object[.](#2.sentence-1)
|
||||
|
||||
For some query object q,
|
||||
the expression read_env(q) is expression-equivalent to*make-sender*(read_env, q)[.](#2.sentence-2)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2962)
|
||||
|
||||
The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
|
||||
is specialized for read_env as follows:
|
||||
|
||||
[ð](#lib:impls-for%3cdecayed-typeof%3cread_env%3e%3e)
|
||||
|
||||
namespace std::execution {template<>struct *impls-for*<*decayed-typeof*<read_env>> : *default-impls* {static constexpr auto start =[](auto query, auto& rcvr) noexcept -> void {*TRY-SET-VALUE*(rcvr, query(get_env(rcvr))); }; }; template<class Sndr, class Env>static consteval void *check-types*();}
|
||||
|
||||
[ð](#lib:check-types,impls-for%3cdecayed-typeof%3cread_env%3e%3e)
|
||||
|
||||
`template<class Sndr, class Env>
|
||||
static consteval void check-types();
|
||||
`
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2988)
|
||||
|
||||
Let Q be decay_t<*data-type*<Sndr>>[.](#4.sentence-1)
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2991)
|
||||
|
||||
*Throws*: An exception of an unspecified type derived from exception if
|
||||
the expression Q()(env) is ill-formed or has type void, whereenv is an lvalue subexpression whose type is Env[.](#5.sentence-1)
|
||||
102
cppdraft/exec/recv.md
Normal file
102
cppdraft/exec/recv.md
Normal file
@@ -0,0 +1,102 @@
|
||||
[exec.recv]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.7 Receivers [exec.recv]
|
||||
|
||||
### [33.7.1](#concepts) Receiver concepts [[exec.recv.concepts]](exec.recv.concepts)
|
||||
|
||||
[1](#concepts-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1173)
|
||||
|
||||
A receiver represents the continuation of an asynchronous operation[.](#concepts-1.sentence-1)
|
||||
|
||||
The [receiver](#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]") concept defines
|
||||
the requirements for a receiver type ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations"))[.](#concepts-1.sentence-2)
|
||||
|
||||
The [receiver_of](#concept:receiver_of "33.7.1 Receiver concepts [exec.recv.concepts]") concept defines
|
||||
the requirements for a receiver type that is usable as
|
||||
the first argument of a set of completion operations
|
||||
corresponding to a set of completion signatures[.](#concepts-1.sentence-3)
|
||||
|
||||
The get_env customization point object is used to access
|
||||
a receiver's associated environment[.](#concepts-1.sentence-4)
|
||||
|
||||
namespace std::execution {template<class Rcvr>concept [receiver](#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]") =[derived_from](concept.derived#concept:derived_from "18.4.3 Concept derived_from [concept.derived]")<typename remove_cvref_t<Rcvr>::receiver_concept, receiver_t> &&requires(const remove_cvref_t<Rcvr>& rcvr) {{ get_env(rcvr) } -> [*queryable*](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]"); } &&[move_constructible](concept.moveconstructible#concept:move_constructible "18.4.13 Concept move_constructible [concept.moveconstructible]")<remove_cvref_t<Rcvr>> && // rvalues are movable, and[constructible_from](concept.constructible#concept:constructible_from "18.4.11 Concept constructible_from [concept.constructible]")<remove_cvref_t<Rcvr>, Rcvr>; // lvalues are copyabletemplate<class Signature, class Rcvr>concept [*valid-completion-for*](#concept:valid-completion-for "33.7.1 Receiver concepts [exec.recv.concepts]") = // *exposition only*requires (Signature* sig) {[]<class Tag, class... Args>(Tag(*)(Args...))requires [*callable*](functional.syn#concept:callable "22.10.2 Header <functional> synopsis [functional.syn]")<Tag, remove_cvref_t<Rcvr>, Args...>{}(sig); }; template<class Rcvr, class Completions>concept [*has-completions*](#concept:has-completions "33.7.1 Receiver concepts [exec.recv.concepts]") = // *exposition only*requires (Completions* completions) {[]<[*valid-completion-for*](#concept:valid-completion-for "33.7.1 Receiver concepts [exec.recv.concepts]")<Rcvr>...Sigs>(completion_signatures<Sigs...>*){}(completions); }; template<class Rcvr, class Completions>concept [receiver_of](#concept:receiver_of "33.7.1 Receiver concepts [exec.recv.concepts]") =[receiver](#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]")<Rcvr> && [*has-completions*](#concept:has-completions "33.7.1 Receiver concepts [exec.recv.concepts]")<Rcvr, Completions>;}
|
||||
|
||||
[2](#concepts-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1215)
|
||||
|
||||
Class types that are marked final do not model the [receiver](#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]") concept[.](#concepts-2.sentence-1)
|
||||
|
||||
[3](#concepts-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1218)
|
||||
|
||||
Let rcvr be a receiver and
|
||||
let op_state be an operation state associated with
|
||||
an asynchronous operation created by connecting rcvr with a sender[.](#concepts-3.sentence-1)
|
||||
|
||||
Let token be a stop token equal toget_stop_token(get_env(rcvr))[.](#concepts-3.sentence-2)
|
||||
|
||||
token shall remain valid
|
||||
for the duration of the asynchronous operation's lifetime ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations"))[.](#concepts-3.sentence-3)
|
||||
|
||||
[*Note [1](#concepts-note-1)*:
|
||||
|
||||
This means that, unless it knows about further guarantees
|
||||
provided by the type of rcvr,
|
||||
the implementation of op_state cannot use token after it executes a completion operation[.](#concepts-3.sentence-4)
|
||||
|
||||
This also implies that any stop callbacks registered on token
|
||||
must be destroyed before the invocation of the completion operation[.](#concepts-3.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
|
||||
### [33.7.2](#exec.set.value) execution::set_value [[exec.set.value]](exec.set.value)
|
||||
|
||||
[1](#exec.set.value-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1237)
|
||||
|
||||
set_value is a value completion function ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations"))[.](#exec.set.value-1.sentence-1)
|
||||
|
||||
Its associated completion tag is set_value_t[.](#exec.set.value-1.sentence-2)
|
||||
|
||||
The expression set_value(rcvr, vs...) for a subexpression rcvr and
|
||||
pack of subexpressions vs is ill-formed
|
||||
if rcvr is an lvalue or an rvalue of const type[.](#exec.set.value-1.sentence-3)
|
||||
|
||||
Otherwise, it is expression-equivalent to*MANDATE-NOTHROW*(rcvr.set_value(vs...))[.](#exec.set.value-1.sentence-4)
|
||||
|
||||
### [33.7.3](#exec.set.error) execution::set_error [[exec.set.error]](exec.set.error)
|
||||
|
||||
[1](#exec.set.error-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1249)
|
||||
|
||||
set_error is an error completion function ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations"))[.](#exec.set.error-1.sentence-1)
|
||||
|
||||
Its associated completion tag is set_error_t[.](#exec.set.error-1.sentence-2)
|
||||
|
||||
The expression set_error(rcvr, err) for some subexpressions rcvr and err is ill-formed
|
||||
if rcvr is an lvalue or an rvalue of const type[.](#exec.set.error-1.sentence-3)
|
||||
|
||||
Otherwise, it is expression-equivalent to*MANDATE-NOTHROW*(rcvr.set_error(err))[.](#exec.set.error-1.sentence-4)
|
||||
|
||||
### [33.7.4](#exec.set.stopped) execution::set_stopped [[exec.set.stopped]](exec.set.stopped)
|
||||
|
||||
[1](#exec.set.stopped-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1260)
|
||||
|
||||
set_stopped is a stopped completion function ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations"))[.](#exec.set.stopped-1.sentence-1)
|
||||
|
||||
Its associated completion tag is set_stopped_t[.](#exec.set.stopped-1.sentence-2)
|
||||
|
||||
The expression set_stopped(rcvr) for a subexpression rcvr is ill-formed
|
||||
if rcvr is an lvalue or an rvalue of const type[.](#exec.set.stopped-1.sentence-3)
|
||||
|
||||
Otherwise, it is expression-equivalent to*MANDATE-NOTHROW*(rcvr.set_stopped())[.](#exec.set.stopped-1.sentence-4)
|
||||
56
cppdraft/exec/recv/concepts.md
Normal file
56
cppdraft/exec/recv/concepts.md
Normal file
@@ -0,0 +1,56 @@
|
||||
[exec.recv.concepts]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.7 Receivers [[exec.recv]](exec.recv#concepts)
|
||||
|
||||
### 33.7.1 Receiver concepts [exec.recv.concepts]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1173)
|
||||
|
||||
A receiver represents the continuation of an asynchronous operation[.](#1.sentence-1)
|
||||
|
||||
The [receiver](#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]") concept defines
|
||||
the requirements for a receiver type ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations"))[.](#1.sentence-2)
|
||||
|
||||
The [receiver_of](#concept:receiver_of "33.7.1 Receiver concepts [exec.recv.concepts]") concept defines
|
||||
the requirements for a receiver type that is usable as
|
||||
the first argument of a set of completion operations
|
||||
corresponding to a set of completion signatures[.](#1.sentence-3)
|
||||
|
||||
The get_env customization point object is used to access
|
||||
a receiver's associated environment[.](#1.sentence-4)
|
||||
|
||||
namespace std::execution {template<class Rcvr>concept [receiver](#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]") =[derived_from](concept.derived#concept:derived_from "18.4.3 Concept derived_from [concept.derived]")<typename remove_cvref_t<Rcvr>::receiver_concept, receiver_t> &&requires(const remove_cvref_t<Rcvr>& rcvr) {{ get_env(rcvr) } -> [*queryable*](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]"); } &&[move_constructible](concept.moveconstructible#concept:move_constructible "18.4.13 Concept move_constructible [concept.moveconstructible]")<remove_cvref_t<Rcvr>> && // rvalues are movable, and[constructible_from](concept.constructible#concept:constructible_from "18.4.11 Concept constructible_from [concept.constructible]")<remove_cvref_t<Rcvr>, Rcvr>; // lvalues are copyabletemplate<class Signature, class Rcvr>concept [*valid-completion-for*](#concept:valid-completion-for "33.7.1 Receiver concepts [exec.recv.concepts]") = // *exposition only*requires (Signature* sig) {[]<class Tag, class... Args>(Tag(*)(Args...))requires [*callable*](functional.syn#concept:callable "22.10.2 Header <functional> synopsis [functional.syn]")<Tag, remove_cvref_t<Rcvr>, Args...>{}(sig); }; template<class Rcvr, class Completions>concept [*has-completions*](#concept:has-completions "33.7.1 Receiver concepts [exec.recv.concepts]") = // *exposition only*requires (Completions* completions) {[]<[*valid-completion-for*](#concept:valid-completion-for "33.7.1 Receiver concepts [exec.recv.concepts]")<Rcvr>...Sigs>(completion_signatures<Sigs...>*){}(completions); }; template<class Rcvr, class Completions>concept [receiver_of](#concept:receiver_of "33.7.1 Receiver concepts [exec.recv.concepts]") =[receiver](#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]")<Rcvr> && [*has-completions*](#concept:has-completions "33.7.1 Receiver concepts [exec.recv.concepts]")<Rcvr, Completions>;}
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1215)
|
||||
|
||||
Class types that are marked final do not model the [receiver](#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]") concept[.](#2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1218)
|
||||
|
||||
Let rcvr be a receiver and
|
||||
let op_state be an operation state associated with
|
||||
an asynchronous operation created by connecting rcvr with a sender[.](#3.sentence-1)
|
||||
|
||||
Let token be a stop token equal toget_stop_token(get_env(rcvr))[.](#3.sentence-2)
|
||||
|
||||
token shall remain valid
|
||||
for the duration of the asynchronous operation's lifetime ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations"))[.](#3.sentence-3)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
This means that, unless it knows about further guarantees
|
||||
provided by the type of rcvr,
|
||||
the implementation of op_state cannot use token after it executes a completion operation[.](#3.sentence-4)
|
||||
|
||||
This also implies that any stop callbacks registered on token
|
||||
must be destroyed before the invocation of the completion operation[.](#3.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
298
cppdraft/exec/run/loop.md
Normal file
298
cppdraft/exec/run/loop.md
Normal file
@@ -0,0 +1,298 @@
|
||||
[exec.run.loop]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.12 Execution contexts [[exec.ctx]](exec.ctx#exec.run.loop)
|
||||
|
||||
### 33.12.1 execution::run_loop [exec.run.loop]
|
||||
|
||||
#### [33.12.1.1](#general) General [[exec.run.loop.general]](exec.run.loop.general)
|
||||
|
||||
[1](#general-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6321)
|
||||
|
||||
A run_loop is an execution resource on which work can be scheduled[.](#general-1.sentence-1)
|
||||
|
||||
It maintains a thread-safe first-in-first-out queue of work[.](#general-1.sentence-2)
|
||||
|
||||
Its run member function removes elements from the queue and
|
||||
executes them in a loop on the thread of execution that calls run[.](#general-1.sentence-3)
|
||||
|
||||
[2](#general-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6327)
|
||||
|
||||
A run_loop instance has an associated [*count*](#def:count "33.12.1.1 General [exec.run.loop.general]") that corresponds to the number of work items that are in its queue[.](#general-2.sentence-1)
|
||||
|
||||
Additionally, a run_loop instance has an associated state
|
||||
that can be one of[*starting*](#def:starting "33.12.1.1 General [exec.run.loop.general]"), [*running*](#def:running "33.12.1.1 General [exec.run.loop.general]"), [*finishing*](#def:finishing "33.12.1.1 General [exec.run.loop.general]"), or [*finished*](#def:finished "33.12.1.1 General [exec.run.loop.general]")[.](#general-2.sentence-2)
|
||||
|
||||
[3](#general-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6334)
|
||||
|
||||
Concurrent invocations of the member functions of run_loop other than run and its destructor do not introduce data races[.](#general-3.sentence-1)
|
||||
|
||||
The member functions*pop-front*, *push-back*, and finish execute atomically[.](#general-3.sentence-2)
|
||||
|
||||
[4](#general-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6341)
|
||||
|
||||
*Recommended practice*: Implementations should use an intrusive queue of operation states
|
||||
to hold the work units to make scheduling allocation-free[.](#general-4.sentence-1)
|
||||
|
||||
namespace std::execution {class [run_loop](#lib:run_loop "33.12.1.1 General [exec.run.loop.general]") {// [[exec.run.loop.types]](#types "33.12.1.2 Associated types"), associated typesclass *run-loop-scheduler*; // *exposition only*class *run-loop-sender*; // *exposition only*struct *run-loop-opstate-base* { // *exposition only*virtual void *execute*() = 0; // *exposition only* run_loop* *loop*; // *exposition only**run-loop-opstate-base** *next*; // *exposition only*}; template<class Rcvr>using *run-loop-opstate* = *unspecified*; // *exposition only*// [[exec.run.loop.members]](#members "33.12.1.4 Member functions"), member functions*run-loop-opstate-base** *pop-front*(); // *exposition only*void *push-back*(*run-loop-opstate-base**); // *exposition only*public:// [[exec.run.loop.ctor]](#ctor "33.12.1.3 Constructor and destructor"), constructor and destructor run_loop() noexcept;
|
||||
run_loop(run_loop&&) = delete; ~run_loop(); // [[exec.run.loop.members]](#members "33.12.1.4 Member functions"), member functions*run-loop-scheduler* get_scheduler(); void run(); void finish(); };}
|
||||
|
||||
#### [33.12.1.2](#types) Associated types [[exec.run.loop.types]](exec.run.loop.types)
|
||||
|
||||
[ð](#types-itemdecl:1)
|
||||
|
||||
`class run-loop-scheduler;
|
||||
`
|
||||
|
||||
[1](#types-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6384)
|
||||
|
||||
*run-loop-scheduler* is an unspecified type
|
||||
that models [scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]")[.](#types-1.sentence-1)
|
||||
|
||||
[2](#types-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6388)
|
||||
|
||||
Instances of *run-loop-scheduler* remain valid
|
||||
until the end of the lifetime of the run_loop instance
|
||||
from which they were obtained[.](#types-2.sentence-1)
|
||||
|
||||
[3](#types-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6393)
|
||||
|
||||
Two instances of *run-loop-scheduler* compare equal
|
||||
if and only if they were obtained from the same run_loop instance[.](#types-3.sentence-1)
|
||||
|
||||
[4](#types-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6397)
|
||||
|
||||
Let *sch* be an expression of type *run-loop-scheduler*[.](#types-4.sentence-1)
|
||||
|
||||
The expression schedule(*sch*) has type *run-loop-
|
||||
sender* and
|
||||
is not potentially-throwing if *sch* is not potentially-throwing[.](#types-4.sentence-2)
|
||||
|
||||
[ð](#types-itemdecl:2)
|
||||
|
||||
`class run-loop-sender;
|
||||
`
|
||||
|
||||
[5](#types-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6407)
|
||||
|
||||
*run-loop-sender* is an exposition-only type
|
||||
that satisfies [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]")[.](#types-5.sentence-1)
|
||||
|
||||
completion_signatures_of_t<*run-
|
||||
loop-sender*> iscompletion_signatures<set_value_t(), set_error_t(exception_ptr), set_stopped_t()>
|
||||
|
||||
[6](#types-6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6415)
|
||||
|
||||
An instance of *run-loop-sender* remains valid
|
||||
until the end of the lifetime of its associated run_loop instance[.](#types-6.sentence-1)
|
||||
|
||||
[7](#types-7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6419)
|
||||
|
||||
Let *sndr* be an expression of type *run-loop-sender*,
|
||||
let *rcvr* be an expression
|
||||
such that [receiver_of](exec.recv.concepts#concept:receiver_of "33.7.1 Receiver concepts [exec.recv.concepts]")<decltype((*rcvr*)), CS> is true where CS is the completion_signatures specialization above[.](#types-7.sentence-1)
|
||||
|
||||
Let C be either set_value_t or set_stopped_t[.](#types-7.sentence-2)
|
||||
|
||||
Then:
|
||||
|
||||
- [(7.1)](#types-7.1)
|
||||
|
||||
The expression connect(*sndr*, *rcvr*) has type *run-loop-opstate*<decay_t<decltype((*rcvr*))>> and is potentially-throwing if and only if(void(*sndr*), auto(*rcvr*)) is potentially-throwing[.](#types-7.1.sentence-1)
|
||||
|
||||
- [(7.2)](#types-7.2)
|
||||
|
||||
The expression get_completion_scheduler<C>(get_env(*sndr*)) is potentially-throwing if and only if *sndr* is potentially-throwing,
|
||||
has type *run-loop-scheduler*, and
|
||||
compares equal to the *run-loop-
|
||||
scheduler* instance
|
||||
from which *sndr* was obtained[.](#types-7.2.sentence-1)
|
||||
|
||||
[ð](#types-itemdecl:3)
|
||||
|
||||
`template<class Rcvr>
|
||||
struct run-loop-opstate;
|
||||
`
|
||||
|
||||
[8](#types-8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6445)
|
||||
|
||||
*run-loop-opstate*<Rcvr> inherits privately and unambiguously from *run-loop-opstate-base*[.](#types-8.sentence-1)
|
||||
|
||||
[9](#types-9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6449)
|
||||
|
||||
Let o be a non-const lvalue of type *run-loop-opstate*<Rcvr>,
|
||||
and let REC(o) be a non-const lvalue reference to an instance of type Rcvr that was initialized with the expression *rcvr* passed to the invocation of connect that returned o[.](#types-9.sentence-1)
|
||||
|
||||
Then:
|
||||
|
||||
- [(9.1)](#types-9.1)
|
||||
|
||||
The object to which *REC*(o) refers
|
||||
remains valid for the lifetime of the object to which o refers.
|
||||
|
||||
- [(9.2)](#types-9.2)
|
||||
|
||||
The type *run-loop-opstate*<Rcvr> overrides*run-loop-opstate-base*::*execute*() such that o.*execute*() is equivalent to:if (get_stop_token(*REC*(o)).stop_requested()) { set_stopped(std::move(*REC*(o)));} else { set_value(std::move(*REC*(o)));}
|
||||
|
||||
- [(9.3)](#types-9.3)
|
||||
|
||||
The expression start(o) is equivalent to:try {o.*loop*->*push-back*(addressof(o));} catch(...) { set_error(std::move(*REC*(o)), current_exception());}
|
||||
|
||||
#### [33.12.1.3](#ctor) Constructor and destructor [[exec.run.loop.ctor]](exec.run.loop.ctor)
|
||||
|
||||
[ð](#lib:run_loop,constructor)
|
||||
|
||||
`run_loop() noexcept;
|
||||
`
|
||||
|
||||
[1](#ctor-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6489)
|
||||
|
||||
*Postconditions*: *count* is 0 and *state* is *starting*[.](#ctor-1.sentence-1)
|
||||
|
||||
[ð](#lib:run_loop,destructor)
|
||||
|
||||
`~run_loop();
|
||||
`
|
||||
|
||||
[2](#ctor-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6500)
|
||||
|
||||
*Effects*: If *count* is not 0 or if *state* is *running*,
|
||||
invokes terminate ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#ctor-2.sentence-1)
|
||||
|
||||
Otherwise, has no effects[.](#ctor-2.sentence-2)
|
||||
|
||||
#### [33.12.1.4](#members) Member functions [[exec.run.loop.members]](exec.run.loop.members)
|
||||
|
||||
[ð](#members-itemdecl:1)
|
||||
|
||||
`run-loop-opstate-base* pop-front();
|
||||
`
|
||||
|
||||
[1](#members-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6514)
|
||||
|
||||
*Effects*: Blocks ([[defns.block]](defns.block "3.6 block")) until one of the following conditions is true:
|
||||
|
||||
- [(1.1)](#members-1.1)
|
||||
|
||||
*count* is 0 and *state* is *finishing*,
|
||||
in which case *pop-front* sets *state* to *finished* and returns nullptr; or
|
||||
|
||||
- [(1.2)](#members-1.2)
|
||||
|
||||
*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[.](#members-1.sentence-1)
|
||||
|
||||
[ð](#members-itemdecl:2)
|
||||
|
||||
`void push-back(run-loop-opstate-base* item);
|
||||
`
|
||||
|
||||
[2](#members-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6535)
|
||||
|
||||
*Effects*: Adds item to the back of the queue and
|
||||
increments *count* by 1[.](#members-2.sentence-1)
|
||||
|
||||
[3](#members-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6540)
|
||||
|
||||
*Synchronization*: This operation synchronizes with
|
||||
the *pop-front* operation that obtains item[.](#members-3.sentence-1)
|
||||
|
||||
[ð](#lib:get_scheduler,run_loop)
|
||||
|
||||
`run-loop-scheduler get_scheduler();
|
||||
`
|
||||
|
||||
[4](#members-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6552)
|
||||
|
||||
*Returns*: An instance of *run-loop-scheduler* that can be used to schedule work onto this run_loop instance[.](#members-4.sentence-1)
|
||||
|
||||
[ð](#lib:run,run_loop)
|
||||
|
||||
`void run();
|
||||
`
|
||||
|
||||
[5](#members-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6564)
|
||||
|
||||
*Preconditions*: *state* is either *starting* or *finishing*[.](#members-5.sentence-1)
|
||||
|
||||
[6](#members-6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6568)
|
||||
|
||||
*Effects*: If *state* is *starting*,
|
||||
sets the *state* to *running*,
|
||||
otherwise leaves *state* unchanged[.](#members-6.sentence-1)
|
||||
|
||||
Then, equivalent to:while (auto* op = *pop-front*()) { op->*execute*();}
|
||||
|
||||
[7](#members-7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6580)
|
||||
|
||||
*Remarks*: When *state* changes, it does so without introducing data races[.](#members-7.sentence-1)
|
||||
|
||||
[ð](#lib:finish,run_loop)
|
||||
|
||||
`void finish();
|
||||
`
|
||||
|
||||
[8](#members-8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6591)
|
||||
|
||||
*Preconditions*: *state* is either *starting* or *running*[.](#members-8.sentence-1)
|
||||
|
||||
[9](#members-9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6595)
|
||||
|
||||
*Effects*: Changes *state* to *finishing*[.](#members-9.sentence-1)
|
||||
|
||||
[10](#members-10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6599)
|
||||
|
||||
*Synchronization*: finish synchronizes with the *pop-front* operation
|
||||
that returns nullptr[.](#members-10.sentence-1)
|
||||
34
cppdraft/exec/run/loop/ctor.md
Normal file
34
cppdraft/exec/run/loop/ctor.md
Normal file
@@ -0,0 +1,34 @@
|
||||
[exec.run.loop.ctor]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.12 Execution contexts [[exec.ctx]](exec.ctx#exec.run.loop.ctor)
|
||||
|
||||
### 33.12.1 execution::run_loop [[exec.run.loop]](exec.run.loop#ctor)
|
||||
|
||||
#### 33.12.1.3 Constructor and destructor [exec.run.loop.ctor]
|
||||
|
||||
[ð](#lib:run_loop,constructor)
|
||||
|
||||
`run_loop() noexcept;
|
||||
`
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6489)
|
||||
|
||||
*Postconditions*: *count* is 0 and *state* is *starting*[.](#1.sentence-1)
|
||||
|
||||
[ð](#lib:run_loop,destructor)
|
||||
|
||||
`~run_loop();
|
||||
`
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6500)
|
||||
|
||||
*Effects*: If *count* is not 0 or if *state* is *running*,
|
||||
invokes terminate ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#2.sentence-1)
|
||||
|
||||
Otherwise, has no effects[.](#2.sentence-2)
|
||||
47
cppdraft/exec/run/loop/general.md
Normal file
47
cppdraft/exec/run/loop/general.md
Normal file
@@ -0,0 +1,47 @@
|
||||
[exec.run.loop.general]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.12 Execution contexts [[exec.ctx]](exec.ctx#exec.run.loop.general)
|
||||
|
||||
### 33.12.1 execution::run_loop [[exec.run.loop]](exec.run.loop#general)
|
||||
|
||||
#### 33.12.1.1 General [exec.run.loop.general]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6321)
|
||||
|
||||
A run_loop is an execution resource on which work can be scheduled[.](#1.sentence-1)
|
||||
|
||||
It maintains a thread-safe first-in-first-out queue of work[.](#1.sentence-2)
|
||||
|
||||
Its run member function removes elements from the queue and
|
||||
executes them in a loop on the thread of execution that calls run[.](#1.sentence-3)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6327)
|
||||
|
||||
A run_loop instance has an associated [*count*](#def:count "33.12.1.1 General [exec.run.loop.general]") that corresponds to the number of work items that are in its queue[.](#2.sentence-1)
|
||||
|
||||
Additionally, a run_loop instance has an associated state
|
||||
that can be one of[*starting*](#def:starting "33.12.1.1 General [exec.run.loop.general]"), [*running*](#def:running "33.12.1.1 General [exec.run.loop.general]"), [*finishing*](#def:finishing "33.12.1.1 General [exec.run.loop.general]"), or [*finished*](#def:finished "33.12.1.1 General [exec.run.loop.general]")[.](#2.sentence-2)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6334)
|
||||
|
||||
Concurrent invocations of the member functions of run_loop other than run and its destructor do not introduce data races[.](#3.sentence-1)
|
||||
|
||||
The member functions*pop-front*, *push-back*, and finish execute atomically[.](#3.sentence-2)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6341)
|
||||
|
||||
*Recommended practice*: Implementations should use an intrusive queue of operation states
|
||||
to hold the work units to make scheduling allocation-free[.](#4.sentence-1)
|
||||
|
||||
namespace std::execution {class [run_loop](#lib:run_loop "33.12.1.1 General [exec.run.loop.general]") {// [[exec.run.loop.types]](exec.run.loop.types "33.12.1.2 Associated types"), associated typesclass *run-loop-scheduler*; // *exposition only*class *run-loop-sender*; // *exposition only*struct *run-loop-opstate-base* { // *exposition only*virtual void *execute*() = 0; // *exposition only* run_loop* *loop*; // *exposition only**run-loop-opstate-base** *next*; // *exposition only*}; template<class Rcvr>using *run-loop-opstate* = *unspecified*; // *exposition only*// [[exec.run.loop.members]](exec.run.loop.members "33.12.1.4 Member functions"), member functions*run-loop-opstate-base** *pop-front*(); // *exposition only*void *push-back*(*run-loop-opstate-base**); // *exposition only*public:// [[exec.run.loop.ctor]](exec.run.loop.ctor "33.12.1.3 Constructor and destructor"), constructor and destructor run_loop() noexcept;
|
||||
run_loop(run_loop&&) = delete; ~run_loop(); // [[exec.run.loop.members]](exec.run.loop.members "33.12.1.4 Member functions"), member functions*run-loop-scheduler* get_scheduler(); void run(); void finish(); };}
|
||||
112
cppdraft/exec/run/loop/members.md
Normal file
112
cppdraft/exec/run/loop/members.md
Normal file
@@ -0,0 +1,112 @@
|
||||
[exec.run.loop.members]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.12 Execution contexts [[exec.ctx]](exec.ctx#exec.run.loop.members)
|
||||
|
||||
### 33.12.1 execution::run_loop [[exec.run.loop]](exec.run.loop#members)
|
||||
|
||||
#### 33.12.1.4 Member functions [exec.run.loop.members]
|
||||
|
||||
[ð](#itemdecl:1)
|
||||
|
||||
`run-loop-opstate-base* pop-front();
|
||||
`
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6514)
|
||||
|
||||
*Effects*: Blocks ([[defns.block]](defns.block "3.6 block")) until one of the following conditions is true:
|
||||
|
||||
- [(1.1)](#1.1)
|
||||
|
||||
*count* is 0 and *state* is *finishing*,
|
||||
in which case *pop-front* sets *state* to *finished* and returns nullptr; or
|
||||
|
||||
- [(1.2)](#1.2)
|
||||
|
||||
*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[.](#1.sentence-1)
|
||||
|
||||
[ð](#itemdecl:2)
|
||||
|
||||
`void push-back(run-loop-opstate-base* item);
|
||||
`
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6535)
|
||||
|
||||
*Effects*: Adds item to the back of the queue and
|
||||
increments *count* by 1[.](#2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6540)
|
||||
|
||||
*Synchronization*: This operation synchronizes with
|
||||
the *pop-front* operation that obtains item[.](#3.sentence-1)
|
||||
|
||||
[ð](#lib:get_scheduler,run_loop)
|
||||
|
||||
`run-loop-scheduler get_scheduler();
|
||||
`
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6552)
|
||||
|
||||
*Returns*: An instance of *run-loop-scheduler* that can be used to schedule work onto this run_loop instance[.](#4.sentence-1)
|
||||
|
||||
[ð](#lib:run,run_loop)
|
||||
|
||||
`void run();
|
||||
`
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6564)
|
||||
|
||||
*Preconditions*: *state* is either *starting* or *finishing*[.](#5.sentence-1)
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6568)
|
||||
|
||||
*Effects*: If *state* is *starting*,
|
||||
sets the *state* to *running*,
|
||||
otherwise leaves *state* unchanged[.](#6.sentence-1)
|
||||
|
||||
Then, equivalent to:while (auto* op = *pop-front*()) { op->*execute*();}
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6580)
|
||||
|
||||
*Remarks*: When *state* changes, it does so without introducing data races[.](#7.sentence-1)
|
||||
|
||||
[ð](#lib:finish,run_loop)
|
||||
|
||||
`void finish();
|
||||
`
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6591)
|
||||
|
||||
*Preconditions*: *state* is either *starting* or *running*[.](#8.sentence-1)
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6595)
|
||||
|
||||
*Effects*: Changes *state* to *finishing*[.](#9.sentence-1)
|
||||
|
||||
[10](#10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6599)
|
||||
|
||||
*Synchronization*: finish synchronizes with the *pop-front* operation
|
||||
that returns nullptr[.](#10.sentence-1)
|
||||
126
cppdraft/exec/run/loop/types.md
Normal file
126
cppdraft/exec/run/loop/types.md
Normal file
@@ -0,0 +1,126 @@
|
||||
[exec.run.loop.types]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.12 Execution contexts [[exec.ctx]](exec.ctx#exec.run.loop.types)
|
||||
|
||||
### 33.12.1 execution::run_loop [[exec.run.loop]](exec.run.loop#types)
|
||||
|
||||
#### 33.12.1.2 Associated types [exec.run.loop.types]
|
||||
|
||||
[ð](#itemdecl:1)
|
||||
|
||||
`class run-loop-scheduler;
|
||||
`
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6384)
|
||||
|
||||
*run-loop-scheduler* is an unspecified type
|
||||
that models [scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]")[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6388)
|
||||
|
||||
Instances of *run-loop-scheduler* remain valid
|
||||
until the end of the lifetime of the run_loop instance
|
||||
from which they were obtained[.](#2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6393)
|
||||
|
||||
Two instances of *run-loop-scheduler* compare equal
|
||||
if and only if they were obtained from the same run_loop instance[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6397)
|
||||
|
||||
Let *sch* be an expression of type *run-loop-scheduler*[.](#4.sentence-1)
|
||||
|
||||
The expression schedule(*sch*) has type *run-loop-
|
||||
sender* and
|
||||
is not potentially-throwing if *sch* is not potentially-throwing[.](#4.sentence-2)
|
||||
|
||||
[ð](#itemdecl:2)
|
||||
|
||||
`class run-loop-sender;
|
||||
`
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6407)
|
||||
|
||||
*run-loop-sender* is an exposition-only type
|
||||
that satisfies [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]")[.](#5.sentence-1)
|
||||
|
||||
completion_signatures_of_t<*run-
|
||||
loop-sender*> iscompletion_signatures<set_value_t(), set_error_t(exception_ptr), set_stopped_t()>
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6415)
|
||||
|
||||
An instance of *run-loop-sender* remains valid
|
||||
until the end of the lifetime of its associated run_loop instance[.](#6.sentence-1)
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6419)
|
||||
|
||||
Let *sndr* be an expression of type *run-loop-sender*,
|
||||
let *rcvr* be an expression
|
||||
such that [receiver_of](exec.recv.concepts#concept:receiver_of "33.7.1 Receiver concepts [exec.recv.concepts]")<decltype((*rcvr*)), CS> is true where CS is the completion_signatures specialization above[.](#7.sentence-1)
|
||||
|
||||
Let C be either set_value_t or set_stopped_t[.](#7.sentence-2)
|
||||
|
||||
Then:
|
||||
|
||||
- [(7.1)](#7.1)
|
||||
|
||||
The expression connect(*sndr*, *rcvr*) has type *run-loop-opstate*<decay_t<decltype((*rcvr*))>> and is potentially-throwing if and only if(void(*sndr*), auto(*rcvr*)) is potentially-throwing[.](#7.1.sentence-1)
|
||||
|
||||
- [(7.2)](#7.2)
|
||||
|
||||
The expression get_completion_scheduler<C>(get_env(*sndr*)) is potentially-throwing if and only if *sndr* is potentially-throwing,
|
||||
has type *run-loop-scheduler*, and
|
||||
compares equal to the *run-loop-
|
||||
scheduler* instance
|
||||
from which *sndr* was obtained[.](#7.2.sentence-1)
|
||||
|
||||
[ð](#itemdecl:3)
|
||||
|
||||
`template<class Rcvr>
|
||||
struct run-loop-opstate;
|
||||
`
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6445)
|
||||
|
||||
*run-loop-opstate*<Rcvr> inherits privately and unambiguously from *run-loop-opstate-base*[.](#8.sentence-1)
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6449)
|
||||
|
||||
Let o be a non-const lvalue of type *run-loop-opstate*<Rcvr>,
|
||||
and let REC(o) be a non-const lvalue reference to an instance of type Rcvr that was initialized with the expression *rcvr* passed to the invocation of connect that returned o[.](#9.sentence-1)
|
||||
|
||||
Then:
|
||||
|
||||
- [(9.1)](#9.1)
|
||||
|
||||
The object to which *REC*(o) refers
|
||||
remains valid for the lifetime of the object to which o refers.
|
||||
|
||||
- [(9.2)](#9.2)
|
||||
|
||||
The type *run-loop-opstate*<Rcvr> overrides*run-loop-opstate-base*::*execute*() such that o.*execute*() is equivalent to:if (get_stop_token(*REC*(o)).stop_requested()) { set_stopped(std::move(*REC*(o)));} else { set_value(std::move(*REC*(o)));}
|
||||
|
||||
- [(9.3)](#9.3)
|
||||
|
||||
The expression start(o) is equivalent to:try {o.*loop*->*push-back*(addressof(o));} catch(...) { set_error(std::move(*REC*(o)), current_exception());}
|
||||
78
cppdraft/exec/sched.md
Normal file
78
cppdraft/exec/sched.md
Normal file
@@ -0,0 +1,78 @@
|
||||
[exec.sched]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.6 Schedulers [exec.sched]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1099)
|
||||
|
||||
The [scheduler](#concept:scheduler "33.6 Schedulers [exec.sched]") concept defines
|
||||
the requirements of a scheduler type ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations"))[.](#1.sentence-1)
|
||||
|
||||
schedule is a customization point object
|
||||
that accepts a scheduler[.](#1.sentence-2)
|
||||
|
||||
A valid invocation of schedule is a schedule-expression[.](#1.sentence-3)
|
||||
|
||||
namespace std::execution {template<class Sch>concept [scheduler](#concept:scheduler "33.6 Schedulers [exec.sched]") =[derived_from](concept.derived#concept:derived_from "18.4.3 Concept derived_from [concept.derived]")<typename remove_cvref_t<Sch>::scheduler_concept, scheduler_t> &&[*queryable*](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]")<Sch> &&requires(Sch&& sch) {{ schedule(std::forward<Sch>(sch)) } -> [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"); { auto(get_completion_scheduler<set_value_t>( get_env(schedule(std::forward<Sch>(sch))))) }-> [same_as](concept.same#concept:same_as "18.4.2 Concept same_as [concept.same]")<remove_cvref_t<Sch>>; } &&[equality_comparable](concept.equalitycomparable#concept:equality_comparable "18.5.4 Concept equality_comparable [concept.equalitycomparable]")<remove_cvref_t<Sch>> &&[copyable](concepts.object#concept:copyable "18.6 Object concepts [concepts.object]")<remove_cvref_t<Sch>>;}
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1122)
|
||||
|
||||
Let Sch be the type of a scheduler and
|
||||
let Env be the type of an execution environment
|
||||
for which [sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<schedule_result_t<Sch>, Env> is satisfied[.](#2.sentence-1)
|
||||
|
||||
Then [*sender-in-of*](exec.snd.concepts#concept:sender-in-of "33.9.3 Sender concepts [exec.snd.concepts]")<schedule_result_t<Sch>, Env> shall be modeled[.](#2.sentence-2)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1130)
|
||||
|
||||
No operation required by[copyable](concepts.object#concept:copyable "18.6 Object concepts [concepts.object]")<remove_cvref_t<Sch>> and[equality_comparable](concept.equalitycomparable#concept:equality_comparable "18.5.4 Concept equality_comparable [concept.equalitycomparable]")<remove_cvref_t<Sch>> shall exit via an exception[.](#3.sentence-1)
|
||||
|
||||
None of these operations,
|
||||
nor a scheduler type's schedule function,
|
||||
shall introduce data races
|
||||
as a result of potentially concurrent ([[intro.races]](intro.races "6.10.2.2 Data races")) invocations
|
||||
of those operations from different threads[.](#3.sentence-2)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1141)
|
||||
|
||||
For any two values sch1 and sch2 of some scheduler type Sch,sch1 == sch2 shall return true only if both sch1 and sch2 share
|
||||
the same associated execution resource[.](#4.sentence-1)
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1148)
|
||||
|
||||
For a given scheduler expression sch,
|
||||
the expressionget_completion_scheduler<set_value_t>(get_env(schedule(sch))) shall compare equal to sch[.](#5.sentence-1)
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1154)
|
||||
|
||||
For a given scheduler expression sch,
|
||||
if the expression get_domain(sch) is well-formed,
|
||||
then the expression get_domain(get_env(schedule(sch))) is also well-formed and has the same type[.](#6.sentence-1)
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1160)
|
||||
|
||||
A scheduler type's destructor shall not block
|
||||
pending completion of any receivers
|
||||
connected to the sender objects returned from schedule[.](#7.sentence-1)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
The ability to wait for completion of submitted function objects
|
||||
can be provided by the associated execution resource of the scheduler[.](#7.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
38
cppdraft/exec/schedule.md
Normal file
38
cppdraft/exec/schedule.md
Normal file
@@ -0,0 +1,38 @@
|
||||
[exec.schedule]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#exec.schedule)
|
||||
|
||||
### 33.9.11 Sender factories [[exec.factories]](exec.factories#exec.schedule)
|
||||
|
||||
#### 33.9.11.1 execution::schedule [exec.schedule]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2877)
|
||||
|
||||
schedule obtains a schedule sender ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations"))
|
||||
from a scheduler[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2881)
|
||||
|
||||
The name schedule denotes a customization point object[.](#2.sentence-1)
|
||||
|
||||
For a subexpression sch,
|
||||
the expression schedule(sch) is expression-equivalent tosch.schedule()[.](#2.sentence-2)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2887)
|
||||
|
||||
*Mandates*: The type of sch.schedule() satisfies [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]")[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2891)
|
||||
|
||||
If the expressionget_completion_scheduler<set_value_t>(get_env(sch.schedule())) == sch is ill-formed or evaluates to false,
|
||||
the behavior of calling schedule(sch) is undefined[.](#4.sentence-1)
|
||||
150
cppdraft/exec/schedule/from.md
Normal file
150
cppdraft/exec/schedule/from.md
Normal file
@@ -0,0 +1,150 @@
|
||||
[exec.schedule.from]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#exec.schedule.from)
|
||||
|
||||
### 33.9.12 Sender adaptors [[exec.adapt]](exec.adapt#exec.schedule.from)
|
||||
|
||||
#### 33.9.12.7 execution::schedule_from [exec.schedule.from]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3359)
|
||||
|
||||
schedule_from schedules work dependent on the completion of a sender
|
||||
onto a scheduler's associated execution resource[.](#1.sentence-1)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
schedule_from is not meant to be used in user code;
|
||||
it is used in the implementation of continues_on[.](#1.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3367)
|
||||
|
||||
The name schedule_from denotes a customization point object[.](#2.sentence-1)
|
||||
|
||||
For some subexpressions sch and sndr,
|
||||
let Sch be decltype((sch)) andSndr be decltype((sndr))[.](#2.sentence-2)
|
||||
|
||||
If Sch does not satisfy [scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]"), orSndr does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"),schedule_from(sch, sndr) is ill-formed[.](#2.sentence-3)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3376)
|
||||
|
||||
Otherwise,
|
||||
the expression schedule_from(sch, sndr) is expression-equivalent to:transform_sender(*query-with-default*(get_domain, sch, default_domain()), *make-sender*(schedule_from, sch, sndr)) except that sch is evaluated only once[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3386)
|
||||
|
||||
The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
|
||||
is specialized for schedule_from_t as follows:
|
||||
|
||||
[ð](#lib:impls-for%3cschedule_from_t%3e)
|
||||
|
||||
namespace std::execution {template<>struct *impls-for*<schedule_from_t> : *default-impls* {static constexpr auto *get-attrs* = *see below*; static constexpr auto *get-state* = *see below*; static constexpr auto *complete* = *see below*; template<class Sndr, class... Env>static consteval void *check-types*(); };}
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3404)
|
||||
|
||||
The member *impls-for*<schedule_from_t>::*get-attrs* is initialized with a callable object equivalent to the following lambda:[](const auto& data, const auto& child) noexcept -> decltype(auto) {return *JOIN-ENV*(*SCHED-ATTRS*(data), *FWD-ENV*(get_env(child)));}
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3413)
|
||||
|
||||
The member *impls-for*<schedule_from_t>::*get-state* is initialized with a callable object equivalent to the following lambda:[]<class Sndr, class Rcvr>(Sndr&& sndr, Rcvr& rcvr) noexcept(*see below*)requires [sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<*child-type*<Sndr>, *FWD-ENV-T*(env_of_t<Rcvr>)> {auto& [_, sch, child] = sndr; using sched_t = decltype(auto(sch)); using variant_t = *see below*; using receiver_t = *see below*; using operation_t = connect_result_t<schedule_result_t<sched_t>, receiver_t>; constexpr bool nothrow = noexcept(connect(schedule(sch), receiver_t{nullptr})); struct *state-type* { Rcvr& *rcvr*; // *exposition only* variant_t *async-result*; // *exposition only* operation_t *op-state*; // *exposition only*explicit *state-type*(sched_t sch, Rcvr& rcvr) noexcept(nothrow): *rcvr*(rcvr), *op-state*(connect(schedule(sch), receiver_t{this})) {}}; return *state-type*{sch, rcvr};}
|
||||
|
||||
[ð](#lib:check-types,impls-for%3cschedule_from_t%3e)
|
||||
|
||||
`template<class Sndr, class... Env>
|
||||
static consteval void check-types();
|
||||
`
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3448)
|
||||
|
||||
*Effects*: Equivalent to:get_completion_signatures<schedule_result_t<*data-type*<Sndr>>, *FWD-ENV-T*(Env)...>();auto cs = get_completion_signatures<*child-type*<Sndr>, *FWD-ENV-T*(Env)...>();*decay-copyable-result-datums*(cs); // see [[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities")
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3458)
|
||||
|
||||
Objects of the local class *state-type* can be used
|
||||
to initialize a structured binding[.](#8.sentence-1)
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3462)
|
||||
|
||||
Let Sigs be
|
||||
a pack of the arguments to the completion_signatures specialization
|
||||
named by completion_signatures_of_t<*child-type*<Sndr>, *FWD-ENV-T*(env_of_t<Rcvr>)>[.](#9.sentence-1)
|
||||
|
||||
Let *as-tuple* be an alias template such that*as-tuple*<Tag(Args...)> denotes
|
||||
the type *decayed-tuple*<Tag, Args...>, and
|
||||
let *is-nothrow-decay-copy-sig* be a variable template such thatauto(*is-nothrow-decay-copy-sig*<Tag(Args...
|
||||
)>) is
|
||||
a constant expression of type bool and
|
||||
equal to (is_nothrow_constructible_v<decay_t<Args>, Args> && ...)[.](#9.sentence-2)
|
||||
|
||||
Let *error-completion* be a pack consisting of
|
||||
the type set_error_t(exception_ptr) if (*is-nothrow-decay-copy-sig*<Sigs> &&...) is false,
|
||||
and an empty pack otherwise[.](#9.sentence-3)
|
||||
|
||||
Then variant_t denotes
|
||||
the type variant<monostate, *as-tuple*<Sigs>..., *error-completion*...>,
|
||||
except with duplicate types removed[.](#9.sentence-4)
|
||||
|
||||
[10](#10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3481)
|
||||
|
||||
receiver_t is an alias for the following exposition-only class:namespace std::execution {struct *receiver-type* {using receiver_concept = receiver_t; *state-type** *state*; // *exposition only*void set_value() && noexcept { visit([this]<class Tuple>(Tuple& result) noexcept -> void {if constexpr (<monostate, Tuple>) {auto& [tag, ...args] = result;
|
||||
tag(std::move(*state*->*rcvr*), std::move(args)...); }}, *state*->*async-result*); }template<class Error>void set_error(Error&& err) && noexcept { execution::set_error(std::move(*state*->*rcvr*), std::forward<Error>(err)); }void set_stopped() && noexcept { execution::set_stopped(std::move(*state*->*rcvr*)); }decltype(auto) get_env() const noexcept {return *FWD-ENV*(execution::get_env(*state*->*rcvr*)); }};}
|
||||
|
||||
[11](#11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3516)
|
||||
|
||||
The expression in the noexcept clause of the lambda is true if the construction of the returned *state-type* object
|
||||
is not potentially throwing;
|
||||
otherwise, false[.](#11.sentence-1)
|
||||
|
||||
[12](#12)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3522)
|
||||
|
||||
The member *impls-for*<schedule_from_t>::*complete* is initialized with a callable object equivalent to the following lambda:[]<class Tag, class... Args>(auto, auto& state, auto& rcvr, Tag, Args&&... args) noexcept-> void {using result_t = *decayed-tuple*<Tag, Args...>; constexpr bool nothrow = (is_nothrow_constructible_v<decay_t<Args>, Args> && ...); try { state.*async-result*.template emplace<result_t>(Tag(), std::forward<Args>(args)...); } catch (...) {if constexpr (!nothrow) state.*async-result*.template emplace<tuple<set_error_t,
|
||||
exception_ptr>>(set_error, current_exception()); } start(state.*op-state*);};
|
||||
|
||||
[13](#13)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3542)
|
||||
|
||||
Let out_sndr be a subexpression denoting
|
||||
a sender returned from schedule_from(sch, sndr) or one equal to such,
|
||||
and let OutSndr be the type decltype((out_sndr))[.](#13.sentence-1)
|
||||
|
||||
Let out_rcvr be a subexpression denoting a receiver
|
||||
that has an environment of type Env such that [sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<OutSndr, Env> is true[.](#13.sentence-2)
|
||||
|
||||
Let op be an lvalue referring to the operation state
|
||||
that results from connecting out_sndr with out_rcvr[.](#13.sentence-3)
|
||||
|
||||
Calling start(op) shall
|
||||
start sndr on the current execution agent and
|
||||
execute completion operations on out_rcvr on an execution agent of the execution resource associated with sch[.](#13.sentence-4)
|
||||
|
||||
If scheduling onto sch fails,
|
||||
an error completion on out_rcvr shall be executed
|
||||
on an unspecified execution agent[.](#13.sentence-5)
|
||||
460
cppdraft/exec/scope.md
Normal file
460
cppdraft/exec/scope.md
Normal file
@@ -0,0 +1,460 @@
|
||||
[exec.scope]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.14 Execution scope utilities [exec.scope]
|
||||
|
||||
### [33.14.1](#concepts) Execution scope concepts [[exec.scope.concepts]](exec.scope.concepts)
|
||||
|
||||
[1](#concepts-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7711)
|
||||
|
||||
The [scope_token](#concept:scope_token "33.14.1 Execution scope concepts [exec.scope.concepts]") concept defines the requirements on
|
||||
a type Token that can be used to create associations
|
||||
between senders and an async scope[.](#concepts-1.sentence-1)
|
||||
|
||||
[2](#concepts-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7716)
|
||||
|
||||
Let *test-sender* and *test-env* be unspecified types such that[sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<*test-sender*, *test-env*> is modeled[.](#concepts-2.sentence-1)
|
||||
|
||||
namespace std::execution {template<class Token>concept [scope_token](#concept:scope_token "33.14.1 Execution scope concepts [exec.scope.concepts]") =[copyable](concepts.object#concept:copyable "18.6 Object concepts [concepts.object]")<Token> &&requires(const Token token) {{ token.try_associate() } -> [same_as](concept.same#concept:same_as "18.4.2 Concept same_as [concept.same]")<bool>; { token.disassociate() } noexcept -> [same_as](concept.same#concept:same_as "18.4.2 Concept same_as [concept.same]")<void>; { token.wrap(declval<*test-sender*>()) } -> [sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<*test-env*>; };}
|
||||
|
||||
[3](#concepts-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7735)
|
||||
|
||||
A type Token models [scope_token](#concept:scope_token "33.14.1 Execution scope concepts [exec.scope.concepts]") only if:
|
||||
|
||||
- [(3.1)](#concepts-3.1)
|
||||
|
||||
no exceptions are thrown from
|
||||
copy construction,
|
||||
move construction,
|
||||
copy assignment, or
|
||||
move assignment
|
||||
of objects of type Token; and
|
||||
|
||||
- [(3.2)](#concepts-3.2)
|
||||
|
||||
given an lvalue token of type (possibly const) Token,
|
||||
for all expressions sndr such thatdecltype((
|
||||
sndr)) models [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"):
|
||||
* [(3.2.1)](#concepts-3.2.1)
|
||||
|
||||
token.wrap(sndr) is a valid expression,
|
||||
|
||||
* [(3.2.2)](#concepts-3.2.2)
|
||||
|
||||
decltype(token.wrap(sndr)) models [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"), and
|
||||
|
||||
* [(3.2.3)](#concepts-3.2.3)
|
||||
|
||||
completion_signatures_of_t<decltype(token.wrap(sndr)), E> contains the same completion signatures as completion_signatures_of_t<decltype((sndr)), E> for all types E such that [sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<decltype((sndr)), E> is modeled.
|
||||
|
||||
### [33.14.2](#exec.counting.scopes) Counting Scopes [[exec.counting.scopes]](exec.counting.scopes)
|
||||
|
||||
#### [33.14.2.1](#exec.counting.scopes.general) General [[exec.counting.scopes.general]](exec.counting.scopes.general)
|
||||
|
||||
[1](#exec.counting.scopes.general-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7769)
|
||||
|
||||
Scopes of type simple_counting_scope and counting_scope maintain counts of associations[.](#exec.counting.scopes.general-1.sentence-1)
|
||||
|
||||
Let:
|
||||
|
||||
- [(1.1)](#exec.counting.scopes.general-1.1)
|
||||
|
||||
Scope be either simple_counting_scope or counting_scope,
|
||||
|
||||
- [(1.2)](#exec.counting.scopes.general-1.2)
|
||||
|
||||
scope be an object of type Scope,
|
||||
|
||||
- [(1.3)](#exec.counting.scopes.general-1.3)
|
||||
|
||||
tkn be an object of type Scope::token obtained from scope.get_token(),
|
||||
|
||||
- [(1.4)](#exec.counting.scopes.general-1.4)
|
||||
|
||||
jsndr be a sender obtained from scope.join(), and
|
||||
|
||||
- [(1.5)](#exec.counting.scopes.general-1.5)
|
||||
|
||||
op be an operation state obtained from
|
||||
connecting jsndr to a receiver[.](#exec.counting.scopes.general-1.sentence-2)
|
||||
|
||||
During its lifetime scope goes through different states
|
||||
which govern what operations are allowed and the result of these operations:
|
||||
|
||||
- [(1.6)](#exec.counting.scopes.general-1.6)
|
||||
|
||||
*unused*:
|
||||
a newly constructed object starts in the *unused* state[.](#exec.counting.scopes.general-1.6.sentence-1)
|
||||
|
||||
- [(1.7)](#exec.counting.scopes.general-1.7)
|
||||
|
||||
*open*:
|
||||
when tkn.try_associate() is called
|
||||
while scope is in the *unused* state,scope moves to the *open* state[.](#exec.counting.scopes.general-1.7.sentence-1)
|
||||
|
||||
- [(1.8)](#exec.counting.scopes.general-1.8)
|
||||
|
||||
*open-and-joining*:
|
||||
when the operation state op is started
|
||||
while scope is in the *unused* or *open* state,scope moves to the *open-and-joining* state[.](#exec.counting.scopes.general-1.8.sentence-1)
|
||||
|
||||
- [(1.9)](#exec.counting.scopes.general-1.9)
|
||||
|
||||
*closed*:
|
||||
when scope.close() is called
|
||||
while scope is in the *open* state,scope moves to the *closed* state[.](#exec.counting.scopes.general-1.9.sentence-1)
|
||||
|
||||
- [(1.10)](#exec.counting.scopes.general-1.10)
|
||||
|
||||
*unused-and-closed*:
|
||||
when scope.close() is called
|
||||
while scope is in the *unused* state,scope moves to the *unused-and-closed* state[.](#exec.counting.scopes.general-1.10.sentence-1)
|
||||
|
||||
- [(1.11)](#exec.counting.scopes.general-1.11)
|
||||
|
||||
*closed-and-joining*:
|
||||
when scope.close() is called
|
||||
while scope is in the *open-and-joining* state or
|
||||
the operation state op is started
|
||||
while scope is in
|
||||
the *closed* or *unused-and-closed* state,scope moves to the *closed-and-joining* state[.](#exec.counting.scopes.general-1.11.sentence-1)
|
||||
|
||||
- [(1.12)](#exec.counting.scopes.general-1.12)
|
||||
|
||||
*joined*:
|
||||
when the count of associations drops to zero
|
||||
while scope is in
|
||||
the *open-and-joining* or *closed-and-joining* state,scope moves to the *joined* state[.](#exec.counting.scopes.general-1.12.sentence-1)
|
||||
|
||||
[2](#exec.counting.scopes.general-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7836)
|
||||
|
||||
*Recommended practice*: For simple_counting_scope and counting_scope,
|
||||
implementations should store the state and the count of associations
|
||||
in a single member of type size_t[.](#exec.counting.scopes.general-2.sentence-1)
|
||||
|
||||
[3](#exec.counting.scopes.general-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7842)
|
||||
|
||||
Subclause [[exec.counting.scopes]](#exec.counting.scopes "33.14.2 Counting Scopes") makes use of
|
||||
the following exposition-only entities:
|
||||
|
||||
struct *scope-join-t* {}; // *exposition only*enum *scope-state-type* { // *exposition only**unused*, // *exposition only**open*, // *exposition only**closed*, // *exposition only**open-and-joining*, // *exposition only**closed-and-joining*, // *exposition only**unused-and-closed*, // *exposition only**joined*, // *exposition only*};
|
||||
|
||||
[4](#exec.counting.scopes.general-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7860)
|
||||
|
||||
The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
|
||||
is specialized for *scope-join-t* as follows:
|
||||
|
||||
namespace std::execution {template<>struct *impls-for*<*scope-join-t*> : *default-impls* {template<class Scope, class Rcvr>struct *state* { // *exposition only*struct *rcvr-t* { // *exposition only*using receiver_concept = receiver_t;
|
||||
|
||||
Rcvr& *rcvr*; // *exposition only*void set_value() && noexcept { execution::set_value(std::move(*rcvr*)); }template<class E>void set_error(E&& e) && noexcept { execution::set_error(std::move(*rcvr*), std::forward<E>(e)); }void set_stopped() && noexcept { execution::set_stopped(std::move(*rcvr*)); }decltype(auto) get_env() const noexcept {return execution::get_env(*rcvr*); }}; using *sched-sender* = // *exposition only*decltype(schedule(get_scheduler(get_env(declval<Rcvr&>())))); using *op-t* = // *exposition only* connect_result_t<*sched-sender*, *rcvr-t*>;
|
||||
|
||||
Scope* *scope*; // *exposition only* Rcvr& *receiver*; // *exposition only**op-t* *op*; // *exposition only**state*(Scope* scope, Rcvr& rcvr) // *exposition only*noexcept([*nothrow-callable*](functional.syn#concept:nothrow-callable "22.10.2 Header <functional> synopsis [functional.syn]")<connect_t, *sched-sender*, *rcvr-t*>): *scope*(scope), *receiver*(rcvr), *op*(connect(schedule(get_scheduler(get_env(rcvr))), *rcvr-t*(rcvr))) {}void *complete*() noexcept { // *exposition only* start(*op*); }void *complete-inline*() noexcept { // *exposition only* set_value(std::move(*receiver*)); }}; static constexpr auto *get-state* = // *exposition only*[]<class Rcvr>(auto&& sender, Rcvr& receiver)noexcept(is_nothrow_constructible_v<*state*<Rcvr>, *data-type*<decltype(sender)>, Rcvr&>) {auto[_, self] = sender; return *state*(self, receiver); }; static constexpr auto *start* = // *exposition only*[](auto& s, auto&) noexcept {if (s.*scope*->*start-join-sender*(s)) s.*complete-inline*(); }; };}
|
||||
|
||||
#### [33.14.2.2](#simple.counting) Simple Counting Scope [[exec.scope.simple.counting]](exec.scope.simple.counting)
|
||||
|
||||
#### [33.14.2.2.1](#simple.counting.general) General [[exec.scope.simple.counting.general]](exec.scope.simple.counting.general)
|
||||
|
||||
[ð](#lib:execution::simple_counting_scope)
|
||||
|
||||
namespace std::execution {class simple_counting_scope {public:// [[exec.simple.counting.token]](#exec.simple.counting.token "33.14.2.2.4 Token"), tokenstruct token; static constexpr size_t max_associations = *implementation-defined*; // [[exec.simple.counting.ctor]](#exec.simple.counting.ctor "33.14.2.2.2 Constructor and Destructor"), constructor and destructor simple_counting_scope() noexcept;
|
||||
simple_counting_scope(simple_counting_scope&&) = delete; ~simple_counting_scope(); // [[exec.simple.counting.mem]](#exec.simple.counting.mem "33.14.2.2.3 Members"), members token get_token() noexcept; void close() noexcept; [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") auto join() noexcept; private: size_t *count*; // *exposition only**scope-state-type* *state*; // *exposition only*bool *try-associate*() noexcept; // *exposition only*void *disassociate*() noexcept; // *exposition only*template<class State>bool *start-join-sender*(State& state) noexcept; // *exposition only*};}
|
||||
|
||||
[1](#simple.counting.general-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7971)
|
||||
|
||||
For purposes of determining the existence of a data race,get_token,close,join,*try-associate*,*disassociate*, and*start-join-sender* behave as atomic operations ([[intro.multithread]](intro.multithread "6.10.2 Multi-threaded executions and data races"))[.](#simple.counting.general-1.sentence-1)
|
||||
|
||||
These operations on a single object of
|
||||
type simple_counting_scope appear to occur in a single total order[.](#simple.counting.general-1.sentence-2)
|
||||
|
||||
#### [33.14.2.2.2](#exec.simple.counting.ctor) Constructor and Destructor [[exec.simple.counting.ctor]](exec.simple.counting.ctor)
|
||||
|
||||
[ð](#lib:execution::simple_counting_scope,constructor)
|
||||
|
||||
`simple_counting_scope() noexcept;
|
||||
`
|
||||
|
||||
[1](#exec.simple.counting.ctor-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7991)
|
||||
|
||||
*Postconditions*: *count* is 0 and *state* is *unused*[.](#exec.simple.counting.ctor-1.sentence-1)
|
||||
|
||||
[ð](#lib:execution::simple_counting_scope,destructor)
|
||||
|
||||
`~simple_counting_scope();
|
||||
`
|
||||
|
||||
[2](#exec.simple.counting.ctor-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8002)
|
||||
|
||||
*Effects*: If *state* is not one of*joined*, *unused*, or *unused-and-closed*,
|
||||
invokes terminate ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#exec.simple.counting.ctor-2.sentence-1)
|
||||
|
||||
Otherwise, has no effects[.](#exec.simple.counting.ctor-2.sentence-2)
|
||||
|
||||
#### [33.14.2.2.3](#exec.simple.counting.mem) Members [[exec.simple.counting.mem]](exec.simple.counting.mem)
|
||||
|
||||
[ð](#lib:get_token,execution::simple_counting_scope)
|
||||
|
||||
`token get_token() noexcept;
|
||||
`
|
||||
|
||||
[1](#exec.simple.counting.mem-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8018)
|
||||
|
||||
*Returns*: An object t of type simple_counting_scope::token such thatt.*scope* == this is true[.](#exec.simple.counting.mem-1.sentence-1)
|
||||
|
||||
[ð](#lib:close,execution::simple_counting_scope)
|
||||
|
||||
`void close() noexcept;
|
||||
`
|
||||
|
||||
[2](#exec.simple.counting.mem-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8030)
|
||||
|
||||
*Effects*: If *state* is
|
||||
|
||||
- [(2.1)](#exec.simple.counting.mem-2.1)
|
||||
|
||||
*unused*, then changes *state* to *unused-and-closed*;
|
||||
|
||||
- [(2.2)](#exec.simple.counting.mem-2.2)
|
||||
|
||||
*open*, then changes *state* to *closed*;
|
||||
|
||||
- [(2.3)](#exec.simple.counting.mem-2.3)
|
||||
|
||||
*open-and-joining*,
|
||||
then changes *state* to *closed-and-joining*;
|
||||
|
||||
- [(2.4)](#exec.simple.counting.mem-2.4)
|
||||
|
||||
otherwise, no effects[.](#exec.simple.counting.mem-2.sentence-1)
|
||||
|
||||
[3](#exec.simple.counting.mem-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8045)
|
||||
|
||||
*Postconditions*: Any subsequent call to *try-associate*() on *this returns false[.](#exec.simple.counting.mem-3.sentence-1)
|
||||
|
||||
[ð](#lib:join,execution::simple_counting_scope)
|
||||
|
||||
`[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") auto join() noexcept;
|
||||
`
|
||||
|
||||
[4](#exec.simple.counting.mem-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8057)
|
||||
|
||||
*Returns*: *make-sender*(*scope-join-t*(), this)[.](#exec.simple.counting.mem-4.sentence-1)
|
||||
|
||||
[ð](#lib:try-associate,execution::simple_counting_scope)
|
||||
|
||||
`bool try-associate() noexcept;
|
||||
`
|
||||
|
||||
[5](#exec.simple.counting.mem-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8068)
|
||||
|
||||
*Effects*: If *count* is equal to max_associations, then no effects[.](#exec.simple.counting.mem-5.sentence-1)
|
||||
|
||||
Otherwise, if *state* is
|
||||
|
||||
- [(5.1)](#exec.simple.counting.mem-5.1)
|
||||
|
||||
*unused*,
|
||||
then increments *count* and changes *state* to *open*;
|
||||
|
||||
- [(5.2)](#exec.simple.counting.mem-5.2)
|
||||
|
||||
*open* or *open-and-joining*,
|
||||
then increments *count*;
|
||||
|
||||
- [(5.3)](#exec.simple.counting.mem-5.3)
|
||||
|
||||
otherwise, no effects[.](#exec.simple.counting.mem-5.sentence-2)
|
||||
|
||||
[6](#exec.simple.counting.mem-6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8083)
|
||||
|
||||
*Returns*: true if *count* was incremented, false otherwise[.](#exec.simple.counting.mem-6.sentence-1)
|
||||
|
||||
[ð](#lib:disassociate,execution::simple_counting_scope)
|
||||
|
||||
`void disassociate() noexcept;
|
||||
`
|
||||
|
||||
[7](#exec.simple.counting.mem-7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8094)
|
||||
|
||||
*Preconditions*: *count* is greater than zero[.](#exec.simple.counting.mem-7.sentence-1)
|
||||
|
||||
[8](#exec.simple.counting.mem-8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8098)
|
||||
|
||||
*Effects*: Decrements *count*[.](#exec.simple.counting.mem-8.sentence-1)
|
||||
|
||||
If *count* is zero after decrementing and*state* is *open-and-joining* or *closed-and-joining*,
|
||||
changes *state* to *joined* and
|
||||
calls *complete*() on all objects registered with *this[.](#exec.simple.counting.mem-8.sentence-2)
|
||||
|
||||
[*Note [1](#exec.simple.counting.mem-note-1)*:
|
||||
|
||||
Calling *complete*() on any registered object
|
||||
can cause *this to be destroyed[.](#exec.simple.counting.mem-8.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[ð](#lib:start-join-sender,execution::simple_counting_scope)
|
||||
|
||||
`template<class State>
|
||||
bool start-join-sender(State& st) noexcept;
|
||||
`
|
||||
|
||||
[9](#exec.simple.counting.mem-9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8118)
|
||||
|
||||
*Effects*: If *state* is
|
||||
|
||||
- [(9.1)](#exec.simple.counting.mem-9.1)
|
||||
|
||||
*unused*, *unused-and-closed*, or *joined*, then
|
||||
changes *state* to *joined* and returns true;
|
||||
|
||||
- [(9.2)](#exec.simple.counting.mem-9.2)
|
||||
|
||||
*open* or *open-and-joining*, then
|
||||
changes *state* to *open-and-joining*,
|
||||
registers st with *this and returns false;
|
||||
|
||||
- [(9.3)](#exec.simple.counting.mem-9.3)
|
||||
|
||||
*closed* or *closed-and-joining*, then
|
||||
changes *state* to *closed-and-joining*,
|
||||
registers st with *this and returns false[.](#exec.simple.counting.mem-9.sentence-1)
|
||||
|
||||
#### [33.14.2.2.4](#exec.simple.counting.token) Token [[exec.simple.counting.token]](exec.simple.counting.token)
|
||||
|
||||
[ð](#lib:execution::simple_counting_scope::token)
|
||||
|
||||
namespace std::execution {struct simple_counting_scope::token {template<[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sender> Sender&& wrap(Sender&& snd) const noexcept; bool try_associate() const noexcept; void disassociate() const noexcept; private: simple_counting_scope* *scope*; // *exposition only*};}
|
||||
|
||||
[ð](#lib:wrap,execution::simple_counting_scope::token)
|
||||
|
||||
`template<[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sender>
|
||||
Sender&& wrap(Sender&& snd) const noexcept;
|
||||
`
|
||||
|
||||
[1](#exec.simple.counting.token-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8160)
|
||||
|
||||
*Returns*: std::forward<Sender>(snd)[.](#exec.simple.counting.token-1.sentence-1)
|
||||
|
||||
[ð](#lib:try_associate,execution::simple_counting_scope::token)
|
||||
|
||||
`bool try_associate() const noexcept;
|
||||
`
|
||||
|
||||
[2](#exec.simple.counting.token-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8171)
|
||||
|
||||
*Effects*: Equivalent to: return *scope*->*try-associate*();
|
||||
|
||||
[ð](#lib:disassociate,execution::simple_counting_scope::token)
|
||||
|
||||
`void disassociate() const noexcept;
|
||||
`
|
||||
|
||||
[3](#exec.simple.counting.token-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8182)
|
||||
|
||||
*Effects*: Equivalent to *scope*->*disassociate*()[.](#exec.simple.counting.token-3.sentence-1)
|
||||
|
||||
#### [33.14.2.3](#counting) Counting Scope [[exec.scope.counting]](exec.scope.counting)
|
||||
|
||||
[ð](#lib:execution::counting_scope)
|
||||
|
||||
namespace std::execution {class counting_scope {public:struct token {template<[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sender>[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") auto wrap(Sender&& snd) const noexcept(*see below*); bool try_associate() const noexcept; void disassociate() const noexcept; private: counting_scope* *scope*; // *exposition only*}; static constexpr size_t max_associations = *implementation-defined*;
|
||||
|
||||
counting_scope() noexcept;
|
||||
counting_scope(counting_scope&&) = delete; ~counting_scope();
|
||||
|
||||
token get_token() noexcept; void close() noexcept; [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") auto join() noexcept; void request_stop() noexcept; private: size_t *count*; // *exposition only**scope-state-type* *state*; // *exposition only* inplace_stop_source *s_source*; // *exposition only*bool *try-associate*() noexcept; // *exposition only*void *disassociate*() noexcept; // *exposition only*template<class State>bool *start-join-sender*(State& state) noexcept; // *exposition only*};}
|
||||
|
||||
[1](#counting-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8230)
|
||||
|
||||
counting_scope differs from simple_counting_scope by
|
||||
adding support for cancellation[.](#counting-1.sentence-1)
|
||||
|
||||
Unless specified below, the semantics of members of counting_scope are the same as the corresponding members of simple_counting_scope[.](#counting-1.sentence-2)
|
||||
|
||||
[ð](#lib:get_token,execution::counting_scope)
|
||||
|
||||
`token get_token() noexcept;
|
||||
`
|
||||
|
||||
[2](#counting-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8242)
|
||||
|
||||
*Returns*: An object t of type counting_scope::token such thatt.*scope* == this is true[.](#counting-2.sentence-1)
|
||||
|
||||
[ð](#lib:request_stop,execution::counting_scope)
|
||||
|
||||
`void request_stop() noexcept;
|
||||
`
|
||||
|
||||
[3](#counting-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8254)
|
||||
|
||||
*Effects*: Equivalent to *s_source*.request_stop()[.](#counting-3.sentence-1)
|
||||
|
||||
[4](#counting-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8258)
|
||||
|
||||
*Remarks*: Calls to request_stop do not introduce data races[.](#counting-4.sentence-1)
|
||||
|
||||
[ð](#lib:wrap,execution::counting_scope::token)
|
||||
|
||||
`template<[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sender>
|
||||
[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") auto counting_scope::token::wrap(Sender&& snd) const
|
||||
noexcept(is_nothrow_constructible_v<remove_cvref_t<Sender>, Sender>);
|
||||
`
|
||||
|
||||
[5](#counting-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8271)
|
||||
|
||||
*Effects*: Equivalent to:return *stop-when*(std::forward<Sender>(snd), *scope*->*s_source*.get_token());
|
||||
55
cppdraft/exec/scope/concepts.md
Normal file
55
cppdraft/exec/scope/concepts.md
Normal file
@@ -0,0 +1,55 @@
|
||||
[exec.scope.concepts]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.14 Execution scope utilities [[exec.scope]](exec.scope#concepts)
|
||||
|
||||
### 33.14.1 Execution scope concepts [exec.scope.concepts]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7711)
|
||||
|
||||
The [scope_token](#concept:scope_token "33.14.1 Execution scope concepts [exec.scope.concepts]") concept defines the requirements on
|
||||
a type Token that can be used to create associations
|
||||
between senders and an async scope[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7716)
|
||||
|
||||
Let *test-sender* and *test-env* be unspecified types such that[sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<*test-sender*, *test-env*> is modeled[.](#2.sentence-1)
|
||||
|
||||
namespace std::execution {template<class Token>concept [scope_token](#concept:scope_token "33.14.1 Execution scope concepts [exec.scope.concepts]") =[copyable](concepts.object#concept:copyable "18.6 Object concepts [concepts.object]")<Token> &&requires(const Token token) {{ token.try_associate() } -> [same_as](concept.same#concept:same_as "18.4.2 Concept same_as [concept.same]")<bool>; { token.disassociate() } noexcept -> [same_as](concept.same#concept:same_as "18.4.2 Concept same_as [concept.same]")<void>; { token.wrap(declval<*test-sender*>()) } -> [sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<*test-env*>; };}
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7735)
|
||||
|
||||
A type Token models [scope_token](#concept:scope_token "33.14.1 Execution scope concepts [exec.scope.concepts]") only if:
|
||||
|
||||
- [(3.1)](#3.1)
|
||||
|
||||
no exceptions are thrown from
|
||||
copy construction,
|
||||
move construction,
|
||||
copy assignment, or
|
||||
move assignment
|
||||
of objects of type Token; and
|
||||
|
||||
- [(3.2)](#3.2)
|
||||
|
||||
given an lvalue token of type (possibly const) Token,
|
||||
for all expressions sndr such thatdecltype((
|
||||
sndr)) models [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"):
|
||||
* [(3.2.1)](#3.2.1)
|
||||
|
||||
token.wrap(sndr) is a valid expression,
|
||||
|
||||
* [(3.2.2)](#3.2.2)
|
||||
|
||||
decltype(token.wrap(sndr)) models [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"), and
|
||||
|
||||
* [(3.2.3)](#3.2.3)
|
||||
|
||||
completion_signatures_of_t<decltype(token.wrap(sndr)), E> contains the same completion signatures as completion_signatures_of_t<decltype((sndr)), E> for all types E such that [sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<decltype((sndr)), E> is modeled.
|
||||
68
cppdraft/exec/scope/counting.md
Normal file
68
cppdraft/exec/scope/counting.md
Normal file
@@ -0,0 +1,68 @@
|
||||
[exec.scope.counting]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.14 Execution scope utilities [[exec.scope]](exec.scope#counting)
|
||||
|
||||
### 33.14.2 Counting Scopes [[exec.counting.scopes]](exec.counting.scopes#exec.scope.counting)
|
||||
|
||||
#### 33.14.2.3 Counting Scope [exec.scope.counting]
|
||||
|
||||
[ð](#lib:execution::counting_scope)
|
||||
|
||||
namespace std::execution {class counting_scope {public:struct token {template<[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sender>[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") auto wrap(Sender&& snd) const noexcept(*see below*); bool try_associate() const noexcept; void disassociate() const noexcept; private: counting_scope* *scope*; // *exposition only*}; static constexpr size_t max_associations = *implementation-defined*;
|
||||
|
||||
counting_scope() noexcept;
|
||||
counting_scope(counting_scope&&) = delete; ~counting_scope();
|
||||
|
||||
token get_token() noexcept; void close() noexcept; [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") auto join() noexcept; void request_stop() noexcept; private: size_t *count*; // *exposition only**scope-state-type* *state*; // *exposition only* inplace_stop_source *s_source*; // *exposition only*bool *try-associate*() noexcept; // *exposition only*void *disassociate*() noexcept; // *exposition only*template<class State>bool *start-join-sender*(State& state) noexcept; // *exposition only*};}
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8230)
|
||||
|
||||
counting_scope differs from simple_counting_scope by
|
||||
adding support for cancellation[.](#1.sentence-1)
|
||||
|
||||
Unless specified below, the semantics of members of counting_scope are the same as the corresponding members of simple_counting_scope[.](#1.sentence-2)
|
||||
|
||||
[ð](#lib:get_token,execution::counting_scope)
|
||||
|
||||
`token get_token() noexcept;
|
||||
`
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8242)
|
||||
|
||||
*Returns*: An object t of type counting_scope::token such thatt.*scope* == this is true[.](#2.sentence-1)
|
||||
|
||||
[ð](#lib:request_stop,execution::counting_scope)
|
||||
|
||||
`void request_stop() noexcept;
|
||||
`
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8254)
|
||||
|
||||
*Effects*: Equivalent to *s_source*.request_stop()[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8258)
|
||||
|
||||
*Remarks*: Calls to request_stop do not introduce data races[.](#4.sentence-1)
|
||||
|
||||
[ð](#lib:wrap,execution::counting_scope::token)
|
||||
|
||||
`template<[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sender>
|
||||
[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") auto counting_scope::token::wrap(Sender&& snd) const
|
||||
noexcept(is_nothrow_constructible_v<remove_cvref_t<Sender>, Sender>);
|
||||
`
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8271)
|
||||
|
||||
*Effects*: Equivalent to:return *stop-when*(std::forward<Sender>(snd), *scope*->*s_source*.get_token());
|
||||
240
cppdraft/exec/scope/simple/counting.md
Normal file
240
cppdraft/exec/scope/simple/counting.md
Normal file
@@ -0,0 +1,240 @@
|
||||
[exec.scope.simple.counting]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.14 Execution scope utilities [[exec.scope]](exec.scope#simple.counting)
|
||||
|
||||
### 33.14.2 Counting Scopes [[exec.counting.scopes]](exec.counting.scopes#exec.scope.simple.counting)
|
||||
|
||||
#### 33.14.2.2 Simple Counting Scope [exec.scope.simple.counting]
|
||||
|
||||
#### [33.14.2.2.1](#general) General [[exec.scope.simple.counting.general]](exec.scope.simple.counting.general)
|
||||
|
||||
[ð](#lib:execution::simple_counting_scope)
|
||||
|
||||
namespace std::execution {class simple_counting_scope {public:// [[exec.simple.counting.token]](#exec.simple.counting.token "33.14.2.2.4 Token"), tokenstruct token; static constexpr size_t max_associations = *implementation-defined*; // [[exec.simple.counting.ctor]](#exec.simple.counting.ctor "33.14.2.2.2 Constructor and Destructor"), constructor and destructor simple_counting_scope() noexcept;
|
||||
simple_counting_scope(simple_counting_scope&&) = delete; ~simple_counting_scope(); // [[exec.simple.counting.mem]](#exec.simple.counting.mem "33.14.2.2.3 Members"), members token get_token() noexcept; void close() noexcept; [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") auto join() noexcept; private: size_t *count*; // *exposition only**scope-state-type* *state*; // *exposition only*bool *try-associate*() noexcept; // *exposition only*void *disassociate*() noexcept; // *exposition only*template<class State>bool *start-join-sender*(State& state) noexcept; // *exposition only*};}
|
||||
|
||||
[1](#general-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7971)
|
||||
|
||||
For purposes of determining the existence of a data race,get_token,close,join,*try-associate*,*disassociate*, and*start-join-sender* behave as atomic operations ([[intro.multithread]](intro.multithread "6.10.2 Multi-threaded executions and data races"))[.](#general-1.sentence-1)
|
||||
|
||||
These operations on a single object of
|
||||
type simple_counting_scope appear to occur in a single total order[.](#general-1.sentence-2)
|
||||
|
||||
#### [33.14.2.2.2](#exec.simple.counting.ctor) Constructor and Destructor [[exec.simple.counting.ctor]](exec.simple.counting.ctor)
|
||||
|
||||
[ð](#lib:execution::simple_counting_scope,constructor)
|
||||
|
||||
`simple_counting_scope() noexcept;
|
||||
`
|
||||
|
||||
[1](#exec.simple.counting.ctor-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7991)
|
||||
|
||||
*Postconditions*: *count* is 0 and *state* is *unused*[.](#exec.simple.counting.ctor-1.sentence-1)
|
||||
|
||||
[ð](#lib:execution::simple_counting_scope,destructor)
|
||||
|
||||
`~simple_counting_scope();
|
||||
`
|
||||
|
||||
[2](#exec.simple.counting.ctor-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8002)
|
||||
|
||||
*Effects*: If *state* is not one of*joined*, *unused*, or *unused-and-closed*,
|
||||
invokes terminate ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#exec.simple.counting.ctor-2.sentence-1)
|
||||
|
||||
Otherwise, has no effects[.](#exec.simple.counting.ctor-2.sentence-2)
|
||||
|
||||
#### [33.14.2.2.3](#exec.simple.counting.mem) Members [[exec.simple.counting.mem]](exec.simple.counting.mem)
|
||||
|
||||
[ð](#lib:get_token,execution::simple_counting_scope)
|
||||
|
||||
`token get_token() noexcept;
|
||||
`
|
||||
|
||||
[1](#exec.simple.counting.mem-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8018)
|
||||
|
||||
*Returns*: An object t of type simple_counting_scope::token such thatt.*scope* == this is true[.](#exec.simple.counting.mem-1.sentence-1)
|
||||
|
||||
[ð](#lib:close,execution::simple_counting_scope)
|
||||
|
||||
`void close() noexcept;
|
||||
`
|
||||
|
||||
[2](#exec.simple.counting.mem-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8030)
|
||||
|
||||
*Effects*: If *state* is
|
||||
|
||||
- [(2.1)](#exec.simple.counting.mem-2.1)
|
||||
|
||||
*unused*, then changes *state* to *unused-and-closed*;
|
||||
|
||||
- [(2.2)](#exec.simple.counting.mem-2.2)
|
||||
|
||||
*open*, then changes *state* to *closed*;
|
||||
|
||||
- [(2.3)](#exec.simple.counting.mem-2.3)
|
||||
|
||||
*open-and-joining*,
|
||||
then changes *state* to *closed-and-joining*;
|
||||
|
||||
- [(2.4)](#exec.simple.counting.mem-2.4)
|
||||
|
||||
otherwise, no effects[.](#exec.simple.counting.mem-2.sentence-1)
|
||||
|
||||
[3](#exec.simple.counting.mem-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8045)
|
||||
|
||||
*Postconditions*: Any subsequent call to *try-associate*() on *this returns false[.](#exec.simple.counting.mem-3.sentence-1)
|
||||
|
||||
[ð](#lib:join,execution::simple_counting_scope)
|
||||
|
||||
`[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") auto join() noexcept;
|
||||
`
|
||||
|
||||
[4](#exec.simple.counting.mem-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8057)
|
||||
|
||||
*Returns*: *make-sender*(*scope-join-t*(), this)[.](#exec.simple.counting.mem-4.sentence-1)
|
||||
|
||||
[ð](#lib:try-associate,execution::simple_counting_scope)
|
||||
|
||||
`bool try-associate() noexcept;
|
||||
`
|
||||
|
||||
[5](#exec.simple.counting.mem-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8068)
|
||||
|
||||
*Effects*: If *count* is equal to max_associations, then no effects[.](#exec.simple.counting.mem-5.sentence-1)
|
||||
|
||||
Otherwise, if *state* is
|
||||
|
||||
- [(5.1)](#exec.simple.counting.mem-5.1)
|
||||
|
||||
*unused*,
|
||||
then increments *count* and changes *state* to *open*;
|
||||
|
||||
- [(5.2)](#exec.simple.counting.mem-5.2)
|
||||
|
||||
*open* or *open-and-joining*,
|
||||
then increments *count*;
|
||||
|
||||
- [(5.3)](#exec.simple.counting.mem-5.3)
|
||||
|
||||
otherwise, no effects[.](#exec.simple.counting.mem-5.sentence-2)
|
||||
|
||||
[6](#exec.simple.counting.mem-6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8083)
|
||||
|
||||
*Returns*: true if *count* was incremented, false otherwise[.](#exec.simple.counting.mem-6.sentence-1)
|
||||
|
||||
[ð](#lib:disassociate,execution::simple_counting_scope)
|
||||
|
||||
`void disassociate() noexcept;
|
||||
`
|
||||
|
||||
[7](#exec.simple.counting.mem-7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8094)
|
||||
|
||||
*Preconditions*: *count* is greater than zero[.](#exec.simple.counting.mem-7.sentence-1)
|
||||
|
||||
[8](#exec.simple.counting.mem-8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8098)
|
||||
|
||||
*Effects*: Decrements *count*[.](#exec.simple.counting.mem-8.sentence-1)
|
||||
|
||||
If *count* is zero after decrementing and*state* is *open-and-joining* or *closed-and-joining*,
|
||||
changes *state* to *joined* and
|
||||
calls *complete*() on all objects registered with *this[.](#exec.simple.counting.mem-8.sentence-2)
|
||||
|
||||
[*Note [1](#exec.simple.counting.mem-note-1)*:
|
||||
|
||||
Calling *complete*() on any registered object
|
||||
can cause *this to be destroyed[.](#exec.simple.counting.mem-8.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[ð](#lib:start-join-sender,execution::simple_counting_scope)
|
||||
|
||||
`template<class State>
|
||||
bool start-join-sender(State& st) noexcept;
|
||||
`
|
||||
|
||||
[9](#exec.simple.counting.mem-9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8118)
|
||||
|
||||
*Effects*: If *state* is
|
||||
|
||||
- [(9.1)](#exec.simple.counting.mem-9.1)
|
||||
|
||||
*unused*, *unused-and-closed*, or *joined*, then
|
||||
changes *state* to *joined* and returns true;
|
||||
|
||||
- [(9.2)](#exec.simple.counting.mem-9.2)
|
||||
|
||||
*open* or *open-and-joining*, then
|
||||
changes *state* to *open-and-joining*,
|
||||
registers st with *this and returns false;
|
||||
|
||||
- [(9.3)](#exec.simple.counting.mem-9.3)
|
||||
|
||||
*closed* or *closed-and-joining*, then
|
||||
changes *state* to *closed-and-joining*,
|
||||
registers st with *this and returns false[.](#exec.simple.counting.mem-9.sentence-1)
|
||||
|
||||
#### [33.14.2.2.4](#exec.simple.counting.token) Token [[exec.simple.counting.token]](exec.simple.counting.token)
|
||||
|
||||
[ð](#lib:execution::simple_counting_scope::token)
|
||||
|
||||
namespace std::execution {struct simple_counting_scope::token {template<[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sender> Sender&& wrap(Sender&& snd) const noexcept; bool try_associate() const noexcept; void disassociate() const noexcept; private: simple_counting_scope* *scope*; // *exposition only*};}
|
||||
|
||||
[ð](#lib:wrap,execution::simple_counting_scope::token)
|
||||
|
||||
`template<[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sender>
|
||||
Sender&& wrap(Sender&& snd) const noexcept;
|
||||
`
|
||||
|
||||
[1](#exec.simple.counting.token-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8160)
|
||||
|
||||
*Returns*: std::forward<Sender>(snd)[.](#exec.simple.counting.token-1.sentence-1)
|
||||
|
||||
[ð](#lib:try_associate,execution::simple_counting_scope::token)
|
||||
|
||||
`bool try_associate() const noexcept;
|
||||
`
|
||||
|
||||
[2](#exec.simple.counting.token-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8171)
|
||||
|
||||
*Effects*: Equivalent to: return *scope*->*try-associate*();
|
||||
|
||||
[ð](#lib:disassociate,execution::simple_counting_scope::token)
|
||||
|
||||
`void disassociate() const noexcept;
|
||||
`
|
||||
|
||||
[3](#exec.simple.counting.token-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8182)
|
||||
|
||||
*Effects*: Equivalent to *scope*->*disassociate*()[.](#exec.simple.counting.token-3.sentence-1)
|
||||
25
cppdraft/exec/scope/simple/counting/general.md
Normal file
25
cppdraft/exec/scope/simple/counting/general.md
Normal file
@@ -0,0 +1,25 @@
|
||||
[exec.scope.simple.counting.general]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.14 Execution scope utilities [[exec.scope]](exec.scope#simple.counting.general)
|
||||
|
||||
### 33.14.2 Counting Scopes [[exec.counting.scopes]](exec.counting.scopes#exec.scope.simple.counting.general)
|
||||
|
||||
#### 33.14.2.2 Simple Counting Scope [[exec.scope.simple.counting]](exec.scope.simple.counting#general)
|
||||
|
||||
#### 33.14.2.2.1 General [exec.scope.simple.counting.general]
|
||||
|
||||
[ð](#lib:execution::simple_counting_scope)
|
||||
|
||||
namespace std::execution {class simple_counting_scope {public:// [[exec.simple.counting.token]](exec.simple.counting.token "33.14.2.2.4 Token"), tokenstruct token; static constexpr size_t max_associations = *implementation-defined*; // [[exec.simple.counting.ctor]](exec.simple.counting.ctor "33.14.2.2.2 Constructor and Destructor"), constructor and destructor simple_counting_scope() noexcept;
|
||||
simple_counting_scope(simple_counting_scope&&) = delete; ~simple_counting_scope(); // [[exec.simple.counting.mem]](exec.simple.counting.mem "33.14.2.2.3 Members"), members token get_token() noexcept; void close() noexcept; [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") auto join() noexcept; private: size_t *count*; // *exposition only**scope-state-type* *state*; // *exposition only*bool *try-associate*() noexcept; // *exposition only*void *disassociate*() noexcept; // *exposition only*template<class State>bool *start-join-sender*(State& state) noexcept; // *exposition only*};}
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7971)
|
||||
|
||||
For purposes of determining the existence of a data race,get_token,close,join,*try-associate*,*disassociate*, and*start-join-sender* behave as atomic operations ([[intro.multithread]](intro.multithread "6.10.2 Multi-threaded executions and data races"))[.](#1.sentence-1)
|
||||
|
||||
These operations on a single object of
|
||||
type simple_counting_scope appear to occur in a single total order[.](#1.sentence-2)
|
||||
20
cppdraft/exec/set/error.md
Normal file
20
cppdraft/exec/set/error.md
Normal file
@@ -0,0 +1,20 @@
|
||||
[exec.set.error]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.7 Receivers [[exec.recv]](exec.recv#exec.set.error)
|
||||
|
||||
### 33.7.3 execution::set_error [exec.set.error]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1249)
|
||||
|
||||
set_error is an error completion function ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations"))[.](#1.sentence-1)
|
||||
|
||||
Its associated completion tag is set_error_t[.](#1.sentence-2)
|
||||
|
||||
The expression set_error(rcvr, err) for some subexpressions rcvr and err is ill-formed
|
||||
if rcvr is an lvalue or an rvalue of const type[.](#1.sentence-3)
|
||||
|
||||
Otherwise, it is expression-equivalent to*MANDATE-NOTHROW*(rcvr.set_error(err))[.](#1.sentence-4)
|
||||
20
cppdraft/exec/set/stopped.md
Normal file
20
cppdraft/exec/set/stopped.md
Normal file
@@ -0,0 +1,20 @@
|
||||
[exec.set.stopped]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.7 Receivers [[exec.recv]](exec.recv#exec.set.stopped)
|
||||
|
||||
### 33.7.4 execution::set_stopped [exec.set.stopped]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1260)
|
||||
|
||||
set_stopped is a stopped completion function ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations"))[.](#1.sentence-1)
|
||||
|
||||
Its associated completion tag is set_stopped_t[.](#1.sentence-2)
|
||||
|
||||
The expression set_stopped(rcvr) for a subexpression rcvr is ill-formed
|
||||
if rcvr is an lvalue or an rvalue of const type[.](#1.sentence-3)
|
||||
|
||||
Otherwise, it is expression-equivalent to*MANDATE-NOTHROW*(rcvr.set_stopped())[.](#1.sentence-4)
|
||||
21
cppdraft/exec/set/value.md
Normal file
21
cppdraft/exec/set/value.md
Normal file
@@ -0,0 +1,21 @@
|
||||
[exec.set.value]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.7 Receivers [[exec.recv]](exec.recv#exec.set.value)
|
||||
|
||||
### 33.7.2 execution::set_value [exec.set.value]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1237)
|
||||
|
||||
set_value is a value completion function ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations"))[.](#1.sentence-1)
|
||||
|
||||
Its associated completion tag is set_value_t[.](#1.sentence-2)
|
||||
|
||||
The expression set_value(rcvr, vs...) for a subexpression rcvr and
|
||||
pack of subexpressions vs is ill-formed
|
||||
if rcvr is an lvalue or an rvalue of const type[.](#1.sentence-3)
|
||||
|
||||
Otherwise, it is expression-equivalent to*MANDATE-NOTHROW*(rcvr.set_value(vs...))[.](#1.sentence-4)
|
||||
36
cppdraft/exec/simple/counting/ctor.md
Normal file
36
cppdraft/exec/simple/counting/ctor.md
Normal file
@@ -0,0 +1,36 @@
|
||||
[exec.simple.counting.ctor]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.14 Execution scope utilities [[exec.scope]](exec.scope#exec.simple.counting.ctor)
|
||||
|
||||
### 33.14.2 Counting Scopes [[exec.counting.scopes]](exec.counting.scopes#exec.simple.counting.ctor)
|
||||
|
||||
#### 33.14.2.2 Simple Counting Scope [[exec.scope.simple.counting]](exec.scope.simple.counting#exec.simple.counting.ctor)
|
||||
|
||||
#### 33.14.2.2.2 Constructor and Destructor [exec.simple.counting.ctor]
|
||||
|
||||
[ð](#lib:execution::simple_counting_scope,constructor)
|
||||
|
||||
`simple_counting_scope() noexcept;
|
||||
`
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7991)
|
||||
|
||||
*Postconditions*: *count* is 0 and *state* is *unused*[.](#1.sentence-1)
|
||||
|
||||
[ð](#lib:execution::simple_counting_scope,destructor)
|
||||
|
||||
`~simple_counting_scope();
|
||||
`
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8002)
|
||||
|
||||
*Effects*: If *state* is not one of*joined*, *unused*, or *unused-and-closed*,
|
||||
invokes terminate ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#2.sentence-1)
|
||||
|
||||
Otherwise, has no effects[.](#2.sentence-2)
|
||||
157
cppdraft/exec/simple/counting/mem.md
Normal file
157
cppdraft/exec/simple/counting/mem.md
Normal file
@@ -0,0 +1,157 @@
|
||||
[exec.simple.counting.mem]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.14 Execution scope utilities [[exec.scope]](exec.scope#exec.simple.counting.mem)
|
||||
|
||||
### 33.14.2 Counting Scopes [[exec.counting.scopes]](exec.counting.scopes#exec.simple.counting.mem)
|
||||
|
||||
#### 33.14.2.2 Simple Counting Scope [[exec.scope.simple.counting]](exec.scope.simple.counting#exec.simple.counting.mem)
|
||||
|
||||
#### 33.14.2.2.3 Members [exec.simple.counting.mem]
|
||||
|
||||
[ð](#lib:get_token,execution::simple_counting_scope)
|
||||
|
||||
`token get_token() noexcept;
|
||||
`
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8018)
|
||||
|
||||
*Returns*: An object t of type simple_counting_scope::token such thatt.*scope* == this is true[.](#1.sentence-1)
|
||||
|
||||
[ð](#lib:close,execution::simple_counting_scope)
|
||||
|
||||
`void close() noexcept;
|
||||
`
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8030)
|
||||
|
||||
*Effects*: If *state* is
|
||||
|
||||
- [(2.1)](#2.1)
|
||||
|
||||
*unused*, then changes *state* to *unused-and-closed*;
|
||||
|
||||
- [(2.2)](#2.2)
|
||||
|
||||
*open*, then changes *state* to *closed*;
|
||||
|
||||
- [(2.3)](#2.3)
|
||||
|
||||
*open-and-joining*,
|
||||
then changes *state* to *closed-and-joining*;
|
||||
|
||||
- [(2.4)](#2.4)
|
||||
|
||||
otherwise, no effects[.](#2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8045)
|
||||
|
||||
*Postconditions*: Any subsequent call to *try-associate*() on *this returns false[.](#3.sentence-1)
|
||||
|
||||
[ð](#lib:join,execution::simple_counting_scope)
|
||||
|
||||
`[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") auto join() noexcept;
|
||||
`
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8057)
|
||||
|
||||
*Returns*: *make-sender*(*scope-join-t*(), this)[.](#4.sentence-1)
|
||||
|
||||
[ð](#lib:try-associate,execution::simple_counting_scope)
|
||||
|
||||
`bool try-associate() noexcept;
|
||||
`
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8068)
|
||||
|
||||
*Effects*: If *count* is equal to max_associations, then no effects[.](#5.sentence-1)
|
||||
|
||||
Otherwise, if *state* is
|
||||
|
||||
- [(5.1)](#5.1)
|
||||
|
||||
*unused*,
|
||||
then increments *count* and changes *state* to *open*;
|
||||
|
||||
- [(5.2)](#5.2)
|
||||
|
||||
*open* or *open-and-joining*,
|
||||
then increments *count*;
|
||||
|
||||
- [(5.3)](#5.3)
|
||||
|
||||
otherwise, no effects[.](#5.sentence-2)
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8083)
|
||||
|
||||
*Returns*: true if *count* was incremented, false otherwise[.](#6.sentence-1)
|
||||
|
||||
[ð](#lib:disassociate,execution::simple_counting_scope)
|
||||
|
||||
`void disassociate() noexcept;
|
||||
`
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8094)
|
||||
|
||||
*Preconditions*: *count* is greater than zero[.](#7.sentence-1)
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8098)
|
||||
|
||||
*Effects*: Decrements *count*[.](#8.sentence-1)
|
||||
|
||||
If *count* is zero after decrementing and*state* is *open-and-joining* or *closed-and-joining*,
|
||||
changes *state* to *joined* and
|
||||
calls *complete*() on all objects registered with *this[.](#8.sentence-2)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
Calling *complete*() on any registered object
|
||||
can cause *this to be destroyed[.](#8.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[ð](#lib:start-join-sender,execution::simple_counting_scope)
|
||||
|
||||
`template<class State>
|
||||
bool start-join-sender(State& st) noexcept;
|
||||
`
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8118)
|
||||
|
||||
*Effects*: If *state* is
|
||||
|
||||
- [(9.1)](#9.1)
|
||||
|
||||
*unused*, *unused-and-closed*, or *joined*, then
|
||||
changes *state* to *joined* and returns true;
|
||||
|
||||
- [(9.2)](#9.2)
|
||||
|
||||
*open* or *open-and-joining*, then
|
||||
changes *state* to *open-and-joining*,
|
||||
registers st with *this and returns false;
|
||||
|
||||
- [(9.3)](#9.3)
|
||||
|
||||
*closed* or *closed-and-joining*, then
|
||||
changes *state* to *closed-and-joining*,
|
||||
registers st with *this and returns false[.](#9.sentence-1)
|
||||
49
cppdraft/exec/simple/counting/token.md
Normal file
49
cppdraft/exec/simple/counting/token.md
Normal file
@@ -0,0 +1,49 @@
|
||||
[exec.simple.counting.token]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.14 Execution scope utilities [[exec.scope]](exec.scope#exec.simple.counting.token)
|
||||
|
||||
### 33.14.2 Counting Scopes [[exec.counting.scopes]](exec.counting.scopes#exec.simple.counting.token)
|
||||
|
||||
#### 33.14.2.2 Simple Counting Scope [[exec.scope.simple.counting]](exec.scope.simple.counting#exec.simple.counting.token)
|
||||
|
||||
#### 33.14.2.2.4 Token [exec.simple.counting.token]
|
||||
|
||||
[ð](#lib:execution::simple_counting_scope::token)
|
||||
|
||||
namespace std::execution {struct simple_counting_scope::token {template<[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sender> Sender&& wrap(Sender&& snd) const noexcept; bool try_associate() const noexcept; void disassociate() const noexcept; private: simple_counting_scope* *scope*; // *exposition only*};}
|
||||
|
||||
[ð](#lib:wrap,execution::simple_counting_scope::token)
|
||||
|
||||
`template<[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sender>
|
||||
Sender&& wrap(Sender&& snd) const noexcept;
|
||||
`
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8160)
|
||||
|
||||
*Returns*: std::forward<Sender>(snd)[.](#1.sentence-1)
|
||||
|
||||
[ð](#lib:try_associate,execution::simple_counting_scope::token)
|
||||
|
||||
`bool try_associate() const noexcept;
|
||||
`
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8171)
|
||||
|
||||
*Effects*: Equivalent to: return *scope*->*try-associate*();
|
||||
|
||||
[ð](#lib:disassociate,execution::simple_counting_scope::token)
|
||||
|
||||
`void disassociate() const noexcept;
|
||||
`
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8182)
|
||||
|
||||
*Effects*: Equivalent to *scope*->*disassociate*()[.](#3.sentence-1)
|
||||
3837
cppdraft/exec/snd.md
Normal file
3837
cppdraft/exec/snd.md
Normal file
File diff suppressed because one or more lines are too long
40
cppdraft/exec/snd/apply.md
Normal file
40
cppdraft/exec/snd/apply.md
Normal file
@@ -0,0 +1,40 @@
|
||||
[exec.snd.apply]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#apply)
|
||||
|
||||
### 33.9.8 execution::apply_sender [exec.snd.apply]
|
||||
|
||||
[ð](#lib:apply_sender)
|
||||
|
||||
`namespace std::execution {
|
||||
template<class Domain, class Tag, [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sndr, class... Args>
|
||||
constexpr decltype(auto) apply_sender(Domain dom, Tag, Sndr&& sndr, Args&&... args)
|
||||
noexcept(see below);
|
||||
}
|
||||
`
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2601)
|
||||
|
||||
Let e be the expressiondom.apply_sender(Tag(), std::forward<Sndr>(sndr), std::forward<Args>(args)...) if that expression is well-formed; otherwise,default_domain().apply_sender(Tag(), std::forward<Sndr>(sndr), std::forward<Args>(args)...)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2611)
|
||||
|
||||
*Constraints*: The expression e is well-formed[.](#2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2615)
|
||||
|
||||
*Returns*: e[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2619)
|
||||
|
||||
*Remarks*: The exception specification is equivalent to noexcept(e)[.](#4.sentence-1)
|
||||
122
cppdraft/exec/snd/concepts.md
Normal file
122
cppdraft/exec/snd/concepts.md
Normal file
@@ -0,0 +1,122 @@
|
||||
[exec.snd.concepts]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#concepts)
|
||||
|
||||
### 33.9.3 Sender concepts [exec.snd.concepts]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2127)
|
||||
|
||||
The [sender](#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") concept defines
|
||||
the requirements for a sender type ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations"))[.](#1.sentence-1)
|
||||
|
||||
The [sender_in](#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]") concept defines
|
||||
the requirements for a sender type
|
||||
that can create asynchronous operations given an associated environment type[.](#1.sentence-2)
|
||||
|
||||
The [sender_to](#concept:sender_to "33.9.3 Sender concepts [exec.snd.concepts]") concept defines
|
||||
the requirements for a sender type
|
||||
that can connect with a specific receiver type[.](#1.sentence-3)
|
||||
|
||||
The get_env customization point object is used to access
|
||||
a sender's associated attributes[.](#1.sentence-4)
|
||||
|
||||
The connect customization point object is used to connect ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations"))
|
||||
a sender and a receiver to produce an operation state[.](#1.sentence-5)
|
||||
|
||||
[ð](#lib:is-dependent-sender-helper)
|
||||
|
||||
namespace std::execution {template<auto>concept [*is-constant*](#concept:is-constant "33.9.3 Sender concepts [exec.snd.concepts]") = true; // *exposition only*template<class Sndr>concept [*is-sender*](#concept:is-sender "33.9.3 Sender concepts [exec.snd.concepts]") = // *exposition only*[derived_from](concept.derived#concept:derived_from "18.4.3 Concept derived_from [concept.derived]")<typename Sndr::sender_concept, sender_t>; template<class Sndr>concept [*enable-sender*](#concept:enable-sender "33.9.3 Sender concepts [exec.snd.concepts]") = // *exposition only*[*is-sender*](#concept:is-sender "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr> ||[*is-awaitable*](exec.awaitable#concept:is-awaitable "33.9.4 Awaitable helpers [exec.awaitable]")<Sndr, *env-promise*<env<>>>; // [[exec.awaitable]](exec.awaitable "33.9.4 Awaitable helpers")template<class Sndr>inline constexpr bool enable_sender = [*enable-sender*](#concept:enable-sender "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr>; template<class Sndr>consteval bool *is-dependent-sender-helper*() try { // *exposition only* get_completion_signatures<Sndr>(); return false; } catch (dependent_sender_error&) {return true; }template<class Sndr>concept [sender](#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") = enable_sender<remove_cvref_t<Sndr>> &&requires (const remove_cvref_t<Sndr>& sndr) {{ get_env(sndr) } -> [*queryable*](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]"); } &&[move_constructible](concept.moveconstructible#concept:move_constructible "18.4.13 Concept move_constructible [concept.moveconstructible]")<remove_cvref_t<Sndr>> &&[constructible_from](concept.constructible#concept:constructible_from "18.4.11 Concept constructible_from [concept.constructible]")<remove_cvref_t<Sndr>, Sndr>; template<class Sndr, class... Env>concept [sender_in](#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]") =[sender](#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr> &&(sizeof...(Env) <= 1) &&([*queryable*](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]")<Env> &&...) &&[*is-constant*](#concept:is-constant "33.9.3 Sender concepts [exec.snd.concepts]")<get_completion_signatures<Sndr, Env...>()>; template<class Sndr>concept [dependent_sender](#concept:dependent_sender "33.9.3 Sender concepts [exec.snd.concepts]") =[sender](#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr> && bool_constant<*is-dependent-sender-helper*<Sndr>()>::value; template<class Sndr, class Rcvr>concept [sender_to](#concept:sender_to "33.9.3 Sender concepts [exec.snd.concepts]") =[sender_in](#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr, env_of_t<Rcvr>> &&[receiver_of](exec.recv.concepts#concept:receiver_of "33.7.1 Receiver concepts [exec.recv.concepts]")<Rcvr, completion_signatures_of_t<Sndr, env_of_t<Rcvr>>> &&requires (Sndr&& sndr, Rcvr&& rcvr) { connect(std::forward<Sndr>(sndr), std::forward<Rcvr>(rcvr)); };}
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2197)
|
||||
|
||||
For a type Sndr, if[sender](#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr> is true and[dependent_sender](#concept:dependent_sender "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr> is false,
|
||||
then Sndr is a non-dependent sender ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations"))[.](#2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2203)
|
||||
|
||||
Given a subexpression sndr,
|
||||
let Sndr be decltype((sndr)) and
|
||||
let rcvr be a receiver
|
||||
with an associated environment whose type is Env[.](#3.sentence-1)
|
||||
|
||||
A completion operation is a [*permissible completion*](#def:completion,permissible "33.9.3 Sender concepts [exec.snd.concepts]") for Sndr and Env if its completion signature appears in the argument list of the specialization of completion_signatures denoted bycompletion_signatures_of_t<Sndr, Env>[.](#3.sentence-2)
|
||||
|
||||
Sndr and Env model [sender_in](#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr, Env> if all the completion operations
|
||||
that are potentially evaluated by connecting sndr to rcvr and
|
||||
starting the resulting operation state
|
||||
are permissible completions for Sndr and Env[.](#3.sentence-3)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2218)
|
||||
|
||||
*Remarks*: Pursuant to [[namespace.std]](namespace.std "16.4.5.2.1 Namespace std"),
|
||||
users may specialize enable_sender totrue for cv-unqualified program-defined types that
|
||||
model [sender](#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"), andfalse for types that do not[.](#4.sentence-1)
|
||||
|
||||
Such specializations shall
|
||||
be usable in constant expressions ([[expr.const]](expr.const "7.7 Constant expressions")) and
|
||||
have type const bool[.](#4.sentence-2)
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2229)
|
||||
|
||||
The exposition-only concepts[*sender-of*](#concept:sender-of "33.9.3 Sender concepts [exec.snd.concepts]") and [*sender-in-of*](#concept:sender-in-of "33.9.3 Sender concepts [exec.snd.concepts]") define the requirements for a sender type
|
||||
that completes with a given unique set of value result types[.](#5.sentence-1)
|
||||
|
||||
namespace std::execution {template<class... As>using *value-signature* = set_value_t(As...); // *exposition only*template<class Sndr, class SetValue, class... Env>concept [*sender-in-of-impl*](#concept:sender-in-of-impl "33.9.3 Sender concepts [exec.snd.concepts]") = // *exposition only*[sender_in](#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr, Env...> &&*MATCHING-SIG*(SetValue, // see [[exec.general]](exec.general "33.1 General")*gather-signatures*<set_value_t, // see [[exec.cmplsig]](exec.cmplsig "33.10 Completion signatures") completion_signatures_of_t<Sndr, Env...>, *value-signature*,
|
||||
type_identity_t>); template<class Sndr, class Env, class... Values>concept [*sender-in-of*](#concept:sender-in-of "33.9.3 Sender concepts [exec.snd.concepts]") = // *exposition only*[*sender-in-of-impl*](#concept:sender-in-of-impl "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr, set_value_t(Values...), Env>; template<class Sndr, class... Values>concept [*sender-of*](#concept:sender-of "33.9.3 Sender concepts [exec.snd.concepts]") = // *exposition only*[*sender-in-of-impl*](#concept:sender-in-of-impl "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr, set_value_t(Values...)>;}
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2258)
|
||||
|
||||
Let sndr be an expression
|
||||
such that decltype((sndr)) is Sndr[.](#6.sentence-1)
|
||||
|
||||
The type tag_of_t<Sndr> is as follows:
|
||||
|
||||
- [(6.1)](#6.1)
|
||||
|
||||
If the declarationauto&& [tag, data, ...children] = sndr; would be well-formed, tag_of_t<Sndr> is
|
||||
an alias for decltype(auto(tag)).
|
||||
|
||||
- [(6.2)](#6.2)
|
||||
|
||||
Otherwise, tag_of_t<Sndr> is ill-formed.
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2274)
|
||||
|
||||
Let [*sender-for*](#concept:sender-for "33.9.3 Sender concepts [exec.snd.concepts]") be an exposition-only concept defined as follows:namespace std::execution {template<class Sndr, class Tag>concept [*sender-for*](#concept:sender-for "33.9.3 Sender concepts [exec.snd.concepts]") =[sender](#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr> &&[same_as](concept.same#concept:same_as "18.4.2 Concept same_as [concept.same]")<tag_of_t<Sndr>, Tag>;}
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2285)
|
||||
|
||||
For a type T,*SET-VALUE-SIG*(T) denotes the type set_value_t() if T is cv void;
|
||||
otherwise, it denotes the type set_value_t(T)[.](#8.sentence-1)
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2291)
|
||||
|
||||
Library-provided sender types
|
||||
|
||||
- [(9.1)](#9.1)
|
||||
|
||||
always expose an overload of a member connect that accepts an rvalue sender and
|
||||
|
||||
- [(9.2)](#9.2)
|
||||
|
||||
only expose an overload of a member connect that accepts an lvalue sender if they model [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14 Concept copy_constructible [concept.copyconstructible]")[.](#9.sentence-1)
|
||||
604
cppdraft/exec/snd/expos.md
Normal file
604
cppdraft/exec/snd/expos.md
Normal file
File diff suppressed because one or more lines are too long
59
cppdraft/exec/snd/general.md
Normal file
59
cppdraft/exec/snd/general.md
Normal file
@@ -0,0 +1,59 @@
|
||||
[exec.snd.general]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#general)
|
||||
|
||||
### 33.9.1 General [exec.snd.general]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L1325)
|
||||
|
||||
Subclauses [[exec.factories]](exec.factories "33.9.11 Sender factories") and [[exec.adapt]](exec.adapt "33.9.12 Sender adaptors") define
|
||||
customizable algorithms that return senders[.](#1.sentence-1)
|
||||
|
||||
Each algorithm has a default implementation[.](#1.sentence-2)
|
||||
|
||||
Let sndr be the result of an invocation of such an algorithm or
|
||||
an object equal to the result ([[concepts.equality]](concepts.equality "18.2 Equality preservation")), and
|
||||
let Sndr be decltype((sndr))[.](#1.sentence-3)
|
||||
|
||||
Let rcvr be a receiver of type Rcvr with associated environment env of type Env such that [sender_to](exec.snd.concepts#concept:sender_to "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr, Rcvr> is true[.](#1.sentence-4)
|
||||
|
||||
For the default implementation of the algorithm that produced sndr,
|
||||
connecting sndr to rcvr and
|
||||
starting the resulting operation state ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations"))
|
||||
necessarily results in the potential evaluation ([[basic.def.odr]](basic.def.odr "6.3 One-definition rule")) of
|
||||
a set of completion operations
|
||||
whose first argument is a subexpression equal to rcvr[.](#1.sentence-5)
|
||||
|
||||
Let Sigs be a pack of completion signatures corresponding to
|
||||
this set of completion operations, and
|
||||
let CS be
|
||||
the type of the expression get_completion_signatures<Sndr, Env>()[.](#1.sentence-6)
|
||||
|
||||
Then CS is
|
||||
a specialization of
|
||||
the class template completion_signatures ([[exec.cmplsig]](exec.cmplsig "33.10 Completion signatures")),
|
||||
the set of whose template arguments is Sigs[.](#1.sentence-7)
|
||||
|
||||
If none of the types in Sigs are dependent on the type Env, then
|
||||
the expression get_completion_signatures<Sndr>() is well-formed and
|
||||
its type is CS[.](#1.sentence-8)
|
||||
|
||||
If a user-provided implementation of the algorithm
|
||||
that produced sndr is selected instead of the default:
|
||||
|
||||
- [(1.1)](#1.1)
|
||||
|
||||
Any completion signature
|
||||
that is in the set of types
|
||||
denoted by completion_signatures_of_t<Sndr, Env> and
|
||||
that is not part of Sigs shall correspond to
|
||||
error or stopped completion operations,
|
||||
unless otherwise specified[.](#1.1.sentence-1)
|
||||
|
||||
- [(1.2)](#1.2)
|
||||
|
||||
If none of the types in Sigs are dependent on the type Env, thencompletion_signatures_of_t<Sndr> andcompletion_signatures_of_t<Sndr, Env> shall denote the same type[.](#1.2.sentence-1)
|
||||
39
cppdraft/exec/snd/transform.md
Normal file
39
cppdraft/exec/snd/transform.md
Normal file
@@ -0,0 +1,39 @@
|
||||
[exec.snd.transform]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#transform)
|
||||
|
||||
### 33.9.6 execution::transform_sender [exec.snd.transform]
|
||||
|
||||
[ð](#lib:transform_sender)
|
||||
|
||||
`namespace std::execution {
|
||||
template<class Domain, [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sndr, [queryable](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]")... Env>
|
||||
requires (sizeof...(Env) <= 1)
|
||||
constexpr [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") decltype(auto) transform_sender(Domain dom, Sndr&& sndr, const Env&... env)
|
||||
noexcept(see below);
|
||||
}
|
||||
`
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2534)
|
||||
|
||||
Let *transformed-sndr* be the expressiondom.transform_sender(std::forward<Sndr>(sndr), env...) if that expression is well-formed; otherwise,default_domain().transform_sender(std::forward<Sndr>(sndr), env...)
|
||||
|
||||
Let *final-sndr* be the expression *transformed-sndr* if *transformed-sndr* and *sndr* have the same type ignoring cv-qualifiers;
|
||||
otherwise, it is
|
||||
the expression transform_sender(dom, *transformed-sndr*, env...)[.](#1.sentence-2)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2549)
|
||||
|
||||
*Returns*: *final-sndr*[.](#2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2553)
|
||||
|
||||
*Remarks*: The exception specification is equivalent tonoexcept(*final-sndr*)[.](#3.sentence-1)
|
||||
33
cppdraft/exec/snd/transform/env.md
Normal file
33
cppdraft/exec/snd/transform/env.md
Normal file
@@ -0,0 +1,33 @@
|
||||
[exec.snd.transform.env]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#transform.env)
|
||||
|
||||
### 33.9.7 execution::transform_env [exec.snd.transform.env]
|
||||
|
||||
[ð](#lib:transform_env)
|
||||
|
||||
`namespace std::execution {
|
||||
template<class Domain, [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sndr, [queryable](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]") Env>
|
||||
constexpr [queryable](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]") decltype(auto) transform_env(Domain dom, Sndr&& sndr, Env&& env) noexcept;
|
||||
}
|
||||
`
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2570)
|
||||
|
||||
Let e be the expressiondom.transform_env(std::forward<Sndr>(sndr), std::forward<Env>(env)) if that expression is well-formed; otherwise,default_domain().transform_env(std::forward<Sndr>(sndr), std::forward<Env>(env))
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2580)
|
||||
|
||||
*Mandates*: noexcept(e) is true[.](#2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2584)
|
||||
|
||||
*Returns*: e[.](#3.sentence-1)
|
||||
161
cppdraft/exec/spawn.md
Normal file
161
cppdraft/exec/spawn.md
Normal file
@@ -0,0 +1,161 @@
|
||||
[exec.spawn]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#exec.spawn)
|
||||
|
||||
### 33.9.13 Sender consumers [[exec.consumers]](exec.consumers#exec.spawn)
|
||||
|
||||
#### 33.9.13.3 execution::spawn [exec.spawn]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5843)
|
||||
|
||||
spawn attempts to associate the given input sender with
|
||||
the given token's async scope and, on success,
|
||||
eagerly starts the input sender[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5848)
|
||||
|
||||
The name spawn denotes a customization point object[.](#2.sentence-1)
|
||||
|
||||
For subexpressions sndr, token, and env,
|
||||
|
||||
- [(2.1)](#2.1)
|
||||
|
||||
let Sndr be decltype((sndr)),
|
||||
|
||||
- [(2.2)](#2.2)
|
||||
|
||||
let Token be remove_cvref_t<decltype((token))>, and
|
||||
|
||||
- [(2.3)](#2.3)
|
||||
|
||||
let Env be remove_cvref_t<decltype((env))>[.](#2.sentence-2)
|
||||
|
||||
If any of[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr>,[scope_token](exec.scope.concepts#concept:scope_token "33.14.1 Execution scope concepts [exec.scope.concepts]")<Token>, or[*queryable*](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]")<Env> are not satisfied,
|
||||
the expression spawn(sndr, token, env) is ill-formed[.](#2.sentence-3)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5863)
|
||||
|
||||
Let *spawn-state-base* be the exposition-only class:
|
||||
|
||||
[ð](#lib:execution::spawn-state-base)
|
||||
|
||||
namespace std::execution {struct *spawn-state-base* { // *exposition only*virtual void *complete*() noexcept = 0; // *exposition only*};}
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5875)
|
||||
|
||||
Let *spawn-receiver* be the exposition-only class:
|
||||
|
||||
[ð](#lib:execution::spawn-receiver)
|
||||
|
||||
namespace std::execution {struct *spawn-receiver* { // *exposition only*using receiver_concept = receiver_t; *spawn-state-base** *state*; // *exposition only*void set_value() && noexcept { *state*->*complete*(); }void set_stopped() && noexcept { *state*->*complete*(); }};}
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5891)
|
||||
|
||||
Let *spawn-state* be the exposition-only class template:
|
||||
|
||||
[ð](#lib:execution::spawn-state)
|
||||
|
||||
namespace std::execution {template<class Alloc, [scope_token](exec.scope.concepts#concept:scope_token "33.14.1 Execution scope concepts [exec.scope.concepts]") Token, [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sender>struct *spawn-state* : *spawn-state-base* { // *exposition only*using *op-t* = connect_result_t<Sender, *spawn-receiver*>; // *exposition only**spawn-state*(Alloc alloc, Sender&& sndr, Token token); // *exposition only*void *complete*() noexcept override; // *exposition only*void *run*(); // *exposition only*private:using *alloc-t* = // *exposition only*typename allocator_traits<Alloc>::template rebind_alloc<*spawn-state*>; *alloc-t* *alloc*; // *exposition only**op-t* *op*; // *exposition only* Token *token*; // *exposition only*void *destroy*() noexcept; // *exposition only*};}
|
||||
|
||||
[ð](#lib:execution::spawn-state,constructor)
|
||||
|
||||
`spawn-state(Alloc alloc, Sender&& sndr, Token token);
|
||||
`
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5924)
|
||||
|
||||
*Effects*: Initializes*alloc* with alloc,*token* with token, and*op* with:connect(std::move(sndr), *spawn-receiver*(this))
|
||||
|
||||
[ð](#lib:run,execution::spawn-state)
|
||||
|
||||
`void run();
|
||||
`
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5941)
|
||||
|
||||
*Effects*: Equivalent to:if (*token*.try_associate()) start(*op*);else*destroy*();
|
||||
|
||||
[ð](#lib:complete,execution::spawn-state)
|
||||
|
||||
`void complete() noexcept override;
|
||||
`
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5958)
|
||||
|
||||
*Effects*: Equivalent to:auto token = std::move(this->*token*);
|
||||
|
||||
*destroy*();
|
||||
token.disassociate();
|
||||
|
||||
[ð](#lib:destroy,execution::spawn-state)
|
||||
|
||||
`void destroy() noexcept;
|
||||
`
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5975)
|
||||
|
||||
*Effects*: Equivalent to:auto alloc = std::move(this->*alloc*);
|
||||
|
||||
allocator_traits<*alloc-t*>::destroy(alloc, this);
|
||||
allocator_traits<*alloc-t*>::deallocate(alloc, this, 1);
|
||||
|
||||
[10](#10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5986)
|
||||
|
||||
For the expression spawn(sndr, token, env) let new_sender be the expression token.wrap(sndr) and
|
||||
let alloc and senv be defined as follows:
|
||||
|
||||
- [(10.1)](#10.1)
|
||||
|
||||
if the expression get_allocator(env) is well-formed, thenalloc is the result of get_allocator(env) andsenv is the expression env,
|
||||
|
||||
- [(10.2)](#10.2)
|
||||
|
||||
otherwise
|
||||
if the expression get_allocator(get_env(new_sender)) is well-formed, thenalloc is the result of get_allocator(get_env(new_sender)) andsenv is the expression *JOIN-ENV*(prop(get_allocator, alloc), env),
|
||||
|
||||
- [(10.3)](#10.3)
|
||||
|
||||
otherwisealloc is allocator<void>() andsenv is the expression env[.](#10.sentence-1)
|
||||
|
||||
[11](#11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6006)
|
||||
|
||||
The expression spawn(sndr, token, env) is of type void and
|
||||
has the following effects:
|
||||
|
||||
- [(11.1)](#11.1)
|
||||
|
||||
Uses alloc to allocate and construct an object o of
|
||||
type that is a specialization of *spawn-state* fromalloc, write_env(token.wrap(sndr), senv), and token and then
|
||||
invokes o.*run*()[.](#11.sentence-1)
|
||||
If an exception is thrown then
|
||||
any constructed objects are destroyed and any allocated memory is deallocated[.](#11.1.sentence-2)
|
||||
|
||||
[12](#12)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6021)
|
||||
|
||||
The expression spawn(sndr, token) is expression-equivalent tospawn(sndr, token, execution::env<>())[.](#12.sentence-1)
|
||||
276
cppdraft/exec/spawn/future.md
Normal file
276
cppdraft/exec/spawn/future.md
Normal file
@@ -0,0 +1,276 @@
|
||||
[exec.spawn.future]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#exec.spawn.future)
|
||||
|
||||
### 33.9.12 Sender adaptors [[exec.adapt]](exec.adapt#exec.spawn.future)
|
||||
|
||||
#### 33.9.12.18 execution::spawn_future [exec.spawn.future]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5230)
|
||||
|
||||
spawn_future attempts to associate the given input sender
|
||||
with the given token's async scope and, on success,
|
||||
eagerly starts the input sender;
|
||||
the return value is a sender that, when connected and started,
|
||||
completes with either
|
||||
the result of the eagerly-started input sender or withset_stopped if the input sender was not started[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5239)
|
||||
|
||||
The name spawn_future denotes a customization point object[.](#2.sentence-1)
|
||||
|
||||
For subexpressions sndr, token, and env,
|
||||
|
||||
- [(2.1)](#2.1)
|
||||
|
||||
let Sndr be decltype((sndr)),
|
||||
|
||||
- [(2.2)](#2.2)
|
||||
|
||||
let Token be remove_cvref_t<decltype((token))>, and
|
||||
|
||||
- [(2.3)](#2.3)
|
||||
|
||||
let Env be remove_cvref_t<decltype((env))>[.](#2.sentence-2)
|
||||
|
||||
If any of[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr>,[scope_token](exec.scope.concepts#concept:scope_token "33.14.1 Execution scope concepts [exec.scope.concepts]")<Token>, or[*queryable*](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]")<Env> are not satisfied,
|
||||
the expression spawn_future(sndr, token, env) is ill-formed[.](#2.sentence-3)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5254)
|
||||
|
||||
Let *spawn-future-state-base* be the exposition-only class template:
|
||||
|
||||
[ð](#lib:execution::spawn-future-state-base)
|
||||
|
||||
namespace std::execution {template<class Completions>struct *spawn-future-state-base*; // *exposition only*template<class... Sigs>struct *spawn-future-state-base*<completion_signatures<Sigs...>> { // *exposition only*using *variant-t* = *see below*; // *exposition only**variant-t* *result*; // *exposition only*virtual void *complete*() noexcept = 0; // *exposition only*};}
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5272)
|
||||
|
||||
Let Sigs be the pack of arguments to
|
||||
the completion_signatures specialization provided as
|
||||
a parameter to the *spawn-future-state-base* class template[.](#4.sentence-1)
|
||||
|
||||
Let *as-tuple* be an alias template that
|
||||
transforms a completion signature Tag(Args...) into the tuple specialization *decayed-tuple*<Tag, Args...>[.](#4.sentence-2)
|
||||
|
||||
- [(4.1)](#4.1)
|
||||
|
||||
If is_nothrow_constructible_v<decay_t<Arg>, Arg> is true for every type Arg in every parameter pack Args in every completion signature Tag(Args...) in Sigs then*variant-t* denotes the typevariant<monostate, tuple<set_stopped_t>, *as-tuple*<Sigs>...>,
|
||||
except with duplicate types removed[.](#4.1.sentence-1)
|
||||
|
||||
- [(4.2)](#4.2)
|
||||
|
||||
Otherwise*variant-t* denotes the typevariant<monostate, tuple<set_stopped_t>, tuple<set_error_t, exception_ptr>, *as-tuple*<Sigs>...>,
|
||||
except with duplicate types removed[.](#4.2.sentence-1)
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5298)
|
||||
|
||||
Let *spawn-future-receiver* be the exposition-only class template:
|
||||
|
||||
[ð](#lib:execution::spawn-future-receiver)
|
||||
|
||||
namespace std::execution {template<class Completions>struct *spawn-future-receiver* { // *exposition only*using receiver_concept = receiver_t; *spawn-future-state-base*<Completions>* *state*; // *exposition only*template<class... T>void set_value(T&&... t) && noexcept {*set-complete*<set_value_t>(std::forward<T>(t)...); }template<class E>void set_error(E&& e) && noexcept {*set-complete*<set_error_t>(std::forward<E>(e)); }void set_stopped() && noexcept {*set-complete*<set_stopped_t>(); }private:template<class CPO, class... T>void *set-complete*(T&&... t) noexcept { // *exposition only*constexpr bool nothrow = (is_nothrow_constructible_v<decay_t<T>, T> && ...); try {*state*->*result*.template emplace<*decayed-tuple*<CPO, T...>>(CPO{},
|
||||
std::forward<T>(t)...); }catch (...) {if constexpr (!nothrow) {using tuple_t = *decayed-tuple*<set_error_t, exception_ptr>; *state*->*result*.template emplace<tuple_t>(set_error_t{}, current_exception()); }}*state*->*complete*(); }};}
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5344)
|
||||
|
||||
Let *ssource-t* be an unspecified type
|
||||
that models [*stoppable-source*](stoptoken.concepts#concept:stoppable-source "32.3.3 Stop token concepts [stoptoken.concepts]") and
|
||||
let ssource be an lvalue of type *ssource-t*[.](#6.sentence-1)
|
||||
|
||||
Let *stoken-t* be decltype(ssource.get_token())[.](#6.sentence-2)
|
||||
|
||||
Let *future-spawned-sender* be the alias template:
|
||||
|
||||
template<[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sender, class Env>using *future-spawned-sender* = // *exposition only*decltype(write_env(*stop-when*(declval<Sender>(), declval<*stoken-t*>()), declval<Env>()));
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5357)
|
||||
|
||||
Let *spawn-future-state* be the exposition-only class template:
|
||||
|
||||
[ð](#lib:execution::spawn-future-state)
|
||||
|
||||
namespace std::execution {template<class Alloc, [scope_token](exec.scope.concepts#concept:scope_token "33.14.1 Execution scope concepts [exec.scope.concepts]") Token, [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sender, class Env>struct *spawn-future-state* // *exposition only*: *spawn-future-state-base*<completion_signatures_of_t<*future-spawned-sender*<Sender, Env>>> {using *sigs-t* = // *exposition only* completion_signatures_of_t<*future-spawned-sender*<Sender, Env>>; using *receiver-t* = // *exposition only**spawn-future-receiver*<*sigs-t*>; using *op-t* = // *exposition only* connect_result_t<*future-spawned-sender*<Sender, Env>, *receiver-t*>; *spawn-future-state*(Alloc alloc, Sender&& sndr, Token token, Env env) // *exposition only*: *alloc*(std::move(alloc)), *op*(connect( write_env(*stop-when*(std::forward<Sender>(sndr), *ssource*.get_token()), std::move(env)), *receiver-t*(this))), *token*(std::move(token)), *associated*(token.try_associate()) {if (associated) start(*op*); else set_stopped(*receiver-t*(this)); }void *complete*() noexcept override; // *exposition only*void *consume*([receiver](exec.recv.concepts#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]") auto& rcvr) noexcept; // *exposition only*void *abandon*() noexcept; // *exposition only*private:using *alloc-t* = // *exposition only*typename allocator_traits<Alloc>::template rebind_alloc<*spawn-future-state*>; *alloc-t* *alloc*; // *exposition only**ssource-t* *ssource*; // *exposition only**op-t* *op*; // *exposition only* Token *token*; // *exposition only*bool *associated*; // *exposition only*void *destroy*() noexcept; // *exposition only*};}
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5405)
|
||||
|
||||
For purposes of determining the existence of a data race,*complete*, *consume*, and *abandon* behave as atomic operations ([[intro.multithread]](intro.multithread "6.10.2 Multi-threaded executions and data races"))[.](#8.sentence-1)
|
||||
|
||||
These operations on a single object of a type
|
||||
that is a specialization of *spawn-future-state* appear to occur in a single total order[.](#8.sentence-2)
|
||||
|
||||
[ð](#lib:complete,execution::spawn-future-state)
|
||||
|
||||
`void complete() noexcept;
|
||||
`
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5419)
|
||||
|
||||
*Effects*:
|
||||
|
||||
- [(9.1)](#9.1)
|
||||
|
||||
No effects if this invocation of *complete* happens before
|
||||
an invocation of *consume* or *abandon* on *this;
|
||||
|
||||
- [(9.2)](#9.2)
|
||||
|
||||
otherwise,
|
||||
if an invocation of *consume* on *this happens before
|
||||
this invocation of *complete* then
|
||||
there is a receiver, rcvr, registered and
|
||||
that receiver is completed as if by *consume*(rcvr);
|
||||
|
||||
- [(9.3)](#9.3)
|
||||
|
||||
otherwise,*destroy* is invoked[.](#9.sentence-1)
|
||||
|
||||
[ð](#lib:consume,execution::spawn-future-state)
|
||||
|
||||
`void consume([receiver](exec.recv.concepts#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]") auto& rcvr) noexcept;
|
||||
`
|
||||
|
||||
[10](#10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5443)
|
||||
|
||||
*Effects*:
|
||||
|
||||
- [(10.1)](#10.1)
|
||||
|
||||
If this invocation of *consume* happens before
|
||||
an invocation of *complete* on *this thenrcvr is registered to be completed when*complete* is subsequently invoked on *this;
|
||||
|
||||
- [(10.2)](#10.2)
|
||||
|
||||
otherwise,rcvr is completed as if by:std::move(this->*result*).visit([&rcvr](auto&& tuple) noexcept {if constexpr (<remove_reference_t<decltype(tuple)>, monostate>) { apply([&rcvr](auto cpo, auto&&... vals) { cpo(std::move(rcvr), std::move(vals)...); }, std::move(tuple)); }});
|
||||
|
||||
[ð](#lib:abandon,execution::spawn-future-state)
|
||||
|
||||
`void abandon() noexcept;
|
||||
`
|
||||
|
||||
[11](#11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5474)
|
||||
|
||||
*Effects*:
|
||||
|
||||
- [(11.1)](#11.1)
|
||||
|
||||
If this invocation of *abandon* happens before
|
||||
an invocation of *complete* on *this then
|
||||
equivalent to:*ssource*.request_stop();
|
||||
|
||||
- [(11.2)](#11.2)
|
||||
|
||||
otherwise,*destroy* is invoked[.](#11.sentence-1)
|
||||
|
||||
[ð](#lib:destroy,execution::spawn-future-state)
|
||||
|
||||
`void destroy() noexcept;
|
||||
`
|
||||
|
||||
[12](#12)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5496)
|
||||
|
||||
*Effects*: Equivalent to:auto token = std::move(this->*token*);bool associated = this->*associated*;
|
||||
|
||||
{auto alloc = std::move(this->*alloc*);
|
||||
|
||||
allocator_traits<*alloc-t*>::destroy(alloc, this);
|
||||
allocator_traits<*alloc-t*>::deallocate(alloc, this, 1);}if (associated) token.disassociate();
|
||||
|
||||
[13](#13)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5515)
|
||||
|
||||
The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
|
||||
is specialized for spawn_future_t as follows:
|
||||
|
||||
[ð](#lib:execution::impls-for%3cspawn_future_t%3e)
|
||||
|
||||
namespace std::execution {template<>struct *impls-for*<spawn_future_t> : *default-impls* {static constexpr auto *start* = *see below*; // *exposition only*};}
|
||||
|
||||
[14](#14)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5529)
|
||||
|
||||
The member *impls-for*<spawn_future_t>::*start* is initialized with a callable object equivalent to the following lambda:[](auto& state, auto& rcvr) noexcept -> void { state->*consume*(rcvr);}
|
||||
|
||||
[15](#15)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5538)
|
||||
|
||||
For the expression spawn_future(sndr, token, env) let new_sender be the expression token.wrap(sndr) and
|
||||
let alloc and senv be defined as follows:
|
||||
|
||||
- [(15.1)](#15.1)
|
||||
|
||||
if the expression get_allocator(env) is well-formed, thenalloc is the result of get_allocator(env) andsenv is the expression env;
|
||||
|
||||
- [(15.2)](#15.2)
|
||||
|
||||
otherwise,
|
||||
if the expression get_allocator(get_env(new_sender)) is well-formed, thenalloc is the result of get_allocator(get_env(new_sender)) andsenv is the expression*JOIN-ENV*(prop(get_allocator, alloc), env);
|
||||
|
||||
- [(15.3)](#15.3)
|
||||
|
||||
otherwise,alloc is allocator<void>() andsenv is the expression env[.](#15.sentence-1)
|
||||
|
||||
[16](#16)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5559)
|
||||
|
||||
The expression spawn_future(sndr, token, env) has the following effects:
|
||||
|
||||
- [(16.1)](#16.1)
|
||||
|
||||
Uses alloc to allocate and construct an object s of
|
||||
a type that is a specialization of *spawn-future-state* from alloc, token.wrap(sndr), token, and senv[.](#16.1.sentence-1)
|
||||
If an exception is thrown then
|
||||
any constructed objects are destroyed and
|
||||
any allocated memory is deallocated[.](#16.1.sentence-2)
|
||||
|
||||
- [(16.2)](#16.2)
|
||||
|
||||
Constructs an object u of
|
||||
a type that is a specialization of unique_ptr such that:
|
||||
* [(16.2.1)](#16.2.1)
|
||||
|
||||
u.get() is equal to the address of s, and
|
||||
|
||||
* [(16.2.2)](#16.2.2)
|
||||
|
||||
u.get_deleter()(u.release()) is equivalent to u.release()->*abandon*()[.](#16.2.sentence-1)
|
||||
|
||||
- [(16.3)](#16.3)
|
||||
|
||||
Returns *make-sender*(spawn_future, std::move(u))[.](#16.3.sentence-1)
|
||||
|
||||
[17](#17)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5587)
|
||||
|
||||
The expression spawn_future(sndr, token) is expression-equivalent tospawn_future(sndr, token, execution::env<>())[.](#17.sentence-1)
|
||||
72
cppdraft/exec/starts/on.md
Normal file
72
cppdraft/exec/starts/on.md
Normal file
@@ -0,0 +1,72 @@
|
||||
[exec.starts.on]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#exec.starts.on)
|
||||
|
||||
### 33.9.12 Sender adaptors [[exec.adapt]](exec.adapt#exec.starts.on)
|
||||
|
||||
#### 33.9.12.5 execution::starts_on [exec.starts.on]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3224)
|
||||
|
||||
starts_on adapts an input sender into a sender
|
||||
that will start on an execution agent belonging to
|
||||
a particular scheduler's associated execution resource[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3229)
|
||||
|
||||
The name starts_on denotes a customization point object[.](#2.sentence-1)
|
||||
|
||||
For subexpressions sch and sndr,
|
||||
if decltype((
|
||||
sch)) does not satisfy [scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]"), ordecltype((sndr)) does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"),starts_on(sch, sndr) is ill-formed[.](#2.sentence-2)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3236)
|
||||
|
||||
Otherwise,
|
||||
the expression starts_on(sch, sndr) is expression-equivalent to:transform_sender(*query-with-default*(get_domain, sch, default_domain()), *make-sender*(starts_on, sch, sndr)) except that sch is evaluated only once[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3246)
|
||||
|
||||
Let out_sndr and env be subexpressions
|
||||
such that OutSndr is decltype((out_sndr))[.](#4.sentence-1)
|
||||
|
||||
If [*sender-for*](exec.snd.concepts#concept:sender-for "33.9.3 Sender concepts [exec.snd.concepts]")<OutSndr, starts_on_t> is false,
|
||||
then the expressions starts_on.transform_env(out_sndr, env) andstarts_on.transform_sender(out_sndr, env) are ill-formed; otherwise
|
||||
|
||||
- [(4.1)](#4.1)
|
||||
|
||||
starts_on.transform_env(out_sndr, env) is equivalent to:auto&& [_, sch, _] = out_sndr;return *JOIN-ENV*(*SCHED-ENV*(sch), *FWD-ENV*(env));
|
||||
|
||||
- [(4.2)](#4.2)
|
||||
|
||||
starts_on.transform_sender(out_sndr, env) is equivalent to:auto&& [_, sch, sndr] = out_sndr;return let_value( schedule(sch), [sndr = std::forward_like<OutSndr>(sndr)]() mutablenoexcept(is_nothrow_move_constructible_v<decay_t<OutSndr>>) {return std::move(sndr); });
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3272)
|
||||
|
||||
Let out_sndr be a subexpression denoting
|
||||
a sender returned from starts_on(sch, sndr) or one equal to such, and
|
||||
let OutSndr be the type decltype((out_sndr))[.](#5.sentence-1)
|
||||
|
||||
Let out_rcvr be a subexpression denoting a receiver
|
||||
that has an environment of type Env such that [sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<OutSndr, Env> is true[.](#5.sentence-2)
|
||||
|
||||
Let op be an lvalue referring to the operation state
|
||||
that results from connecting out_sndr with out_rcvr[.](#5.sentence-3)
|
||||
|
||||
Calling start(op) shall start sndr on an execution agent of the associated execution resource of sch[.](#5.sentence-4)
|
||||
|
||||
If scheduling onto sch fails,
|
||||
an error completion on out_rcvr shall be executed
|
||||
on an unspecified execution agent[.](#5.sentence-5)
|
||||
73
cppdraft/exec/stop/when.md
Normal file
73
cppdraft/exec/stop/when.md
Normal file
@@ -0,0 +1,73 @@
|
||||
[exec.stop.when]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#exec.stop.when)
|
||||
|
||||
### 33.9.12 Sender adaptors [[exec.adapt]](exec.adapt#exec.stop.when)
|
||||
|
||||
#### 33.9.12.17 Exposition-only execution::*stop-when* [exec.stop.when]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5154)
|
||||
|
||||
*stop-when* fuses an additional stop token t into a sender so that, upon connecting to a receiver r,
|
||||
the resulting operation state receives stop requests from botht and the token returned from get_stop_token(get_env(r))[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5161)
|
||||
|
||||
The name *stop-when* denotes an exposition-only sender adaptor[.](#2.sentence-1)
|
||||
|
||||
For subexpressions sndr and token:
|
||||
|
||||
- [(2.1)](#2.1)
|
||||
|
||||
If decltype((sndr)) does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"), orremove_cvref_t<decltype((token))> does not satisfy [stoppable_token](stoptoken.concepts#concept:stoppable_token "32.3.3 Stop token concepts [stoptoken.concepts]"),
|
||||
then *stop-when*(sndr, token) is ill-formed[.](#2.1.sentence-1)
|
||||
|
||||
- [(2.2)](#2.2)
|
||||
|
||||
Otherwise,
|
||||
if remove_cvref_t<decltype((token))> models[unstoppable_token](stoptoken.concepts#concept:unstoppable_token "32.3.3 Stop token concepts [stoptoken.concepts]") then*stop-when*(sndr, token) is expression-equivalent tosndr[.](#2.2.sentence-1)
|
||||
|
||||
- [(2.3)](#2.3)
|
||||
|
||||
Otherwise,*stop-when*(sndr, token) returns a sender osndr[.](#2.3.sentence-1)
|
||||
If osndr is connected to a receiver r,
|
||||
let rtoken be the result of get_stop_token(get_env(r))[.](#2.3.sentence-2)
|
||||
|
||||
* [(2.3.1)](#2.3.1)
|
||||
|
||||
If the type of rtoken models [unstoppable_token](stoptoken.concepts#concept:unstoppable_token "32.3.3 Stop token concepts [stoptoken.concepts]") then
|
||||
the effects of connecting osndr to r are equivalent toconnect(write_env(sndr, prop(get_stop_token, token)), r)[.](#2.3.1.sentence-1)
|
||||
|
||||
* [(2.3.2)](#2.3.2)
|
||||
|
||||
Otherwise,
|
||||
the effects of connecting osndr to r are equivalent toconnect(write_env(sndr, prop(get_stop_token, stoken)), r) where stoken is an object of
|
||||
an exposition-only type *stoken-t* such that:
|
||||
+
|
||||
[(2.3.2.1)](#2.3.2.1)
|
||||
*stoken-t* models [stoppable_token](stoptoken.concepts#concept:stoppable_token "32.3.3 Stop token concepts [stoptoken.concepts]");
|
||||
|
||||
+
|
||||
[(2.3.2.2)](#2.3.2.2)
|
||||
stoken.stop_requested() returns token.stop_requested() || rtoken.stop_reques-
|
||||
ted();
|
||||
|
||||
+
|
||||
[(2.3.2.3)](#2.3.2.3)
|
||||
stoken.stop_possible() returns token.stop_possible() || rtoken.stop_possible(); and
|
||||
|
||||
+
|
||||
[(2.3.2.4)](#2.3.2.4)
|
||||
for types Fn and Init such that both [invocable](concept.invocable#concept:invocable "18.7.2 Concept invocable [concept.invocable]")<Fn> and [constructible_from](concept.constructible#concept:constructible_from "18.4.11 Concept constructible_from [concept.constructible]")<Fn, Init> are modeled, *stoken-t*::callback_type<Fn> models [*stoppable-callback-for*](stoptoken.concepts#concept:stoppable-callback-for "32.3.3 Stop token concepts [stoptoken.concepts]")<Fn, *stoken-t*, Init>[.](#2.3.2.sentence-1)
|
||||
[*Note [1](#note-1)*:
|
||||
For an object fn of type Fn constructed from a value, init, of type Init,
|
||||
registering fn using *stoken-t*::callback_type<Fn>(stoken, init) results in an invocation of fn when
|
||||
a callback registered with token or rtoken would be invoked[.](#2.3.2.4.sentence-2)
|
||||
fn is invoked at most once[.](#2.3.2.4.sentence-3)
|
||||
â *end note*]
|
||||
45
cppdraft/exec/stopped/err.md
Normal file
45
cppdraft/exec/stopped/err.md
Normal file
@@ -0,0 +1,45 @@
|
||||
[exec.stopped.err]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#exec.stopped.err)
|
||||
|
||||
### 33.9.12 Sender adaptors [[exec.adapt]](exec.adapt#exec.stopped.err)
|
||||
|
||||
#### 33.9.12.15 execution::stopped_as_error [exec.stopped.err]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4856)
|
||||
|
||||
stopped_as_error maps an input sender's stopped completion operation
|
||||
into an error completion operation as a custom error type[.](#1.sentence-1)
|
||||
|
||||
The result is a sender that never completes with stopped,
|
||||
reporting cancellation by completing with an error[.](#1.sentence-2)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4862)
|
||||
|
||||
The name stopped_as_error denotes a pipeable sender adaptor object[.](#2.sentence-1)
|
||||
|
||||
For some subexpressions sndr and err,
|
||||
let Sndr be decltype((sndr)) and
|
||||
let Err be decltype((err))[.](#2.sentence-2)
|
||||
|
||||
If the type Sndr does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") or
|
||||
if the type Err does not satisfy [*movable-value*](exec.general#concept:movable-value "33.1 General [exec.general]"),stopped_as_error(sndr, err) is ill-formed[.](#2.sentence-3)
|
||||
|
||||
Otherwise, the expression stopped_as_error(sndr, err) is expression-equivalent to:transform_sender(*get-domain-early*(sndr), *make-sender*(stopped_as_error, err, sndr)) except that sndr is only evaluated once[.](#2.sentence-4)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4877)
|
||||
|
||||
Let sndr and env be subexpressions
|
||||
such that Sndr is decltype((sndr)) andEnv is decltype((env))[.](#3.sentence-1)
|
||||
|
||||
If [*sender-for*](exec.snd.concepts#concept:sender-for "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr, stopped_as_error_t> is false,
|
||||
then the expression stopped_as_error.transform_sender(sndr, env) is ill-formed;
|
||||
otherwise, it is equivalent to:auto&& [_, err, child] = sndr;using E = decltype(auto(err));return let_stopped( std::forward_like<Sndr>(child), [err = std::forward_like<Sndr>(err)]() mutable noexcept(is_nothrow_move_constructible_v<E>) {return just_error(std::move(err)); });
|
||||
57
cppdraft/exec/stopped/opt.md
Normal file
57
cppdraft/exec/stopped/opt.md
Normal file
@@ -0,0 +1,57 @@
|
||||
[exec.stopped.opt]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#exec.stopped.opt)
|
||||
|
||||
### 33.9.12 Sender adaptors [[exec.adapt]](exec.adapt#exec.stopped.opt)
|
||||
|
||||
#### 33.9.12.14 execution::stopped_as_optional [exec.stopped.opt]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4789)
|
||||
|
||||
stopped_as_optional maps a sender's stopped completion operation
|
||||
into a value completion operation as a disengaged optional[.](#1.sentence-1)
|
||||
|
||||
The sender's value completion operation
|
||||
is also converted into an optional[.](#1.sentence-2)
|
||||
|
||||
The result is a sender that never completes with stopped,
|
||||
reporting cancellation by completing with a disengaged optional[.](#1.sentence-3)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4797)
|
||||
|
||||
The name stopped_as_optional denotes a pipeable sender adaptor object[.](#2.sentence-1)
|
||||
|
||||
For a subexpression sndr, let Sndr be decltype((sndr))[.](#2.sentence-2)
|
||||
|
||||
The expression stopped_as_optional(sndr) is expression-equivalent to:transform_sender(*get-domain-early*(sndr), *make-sender*(stopped_as_optional, {}, sndr)) except that sndr is only evaluated once[.](#2.sentence-3)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4806)
|
||||
|
||||
The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
|
||||
is specialized for stopped_as_optional_t as follows:
|
||||
|
||||
[ð](#lib:impls-for%3cstopped_as_optional_t%3e)
|
||||
|
||||
namespace std::execution {template<>struct *impls-for*<stopped_as_optional_t> : *default-impls* {template<class Sndr, class... Env>static consteval void *check-types*() {*default-impls*::*check-types*<Sndr, Env...>(); if constexpr (!requires {requires (<void, *single-sender-value-type*<*child-type*<Sndr>, *FWD-ENV-T*(Env)...>>); })throw *unspecified-exception*(); }};} where *unspecified-exception* is
|
||||
a type derived from exception[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4829)
|
||||
|
||||
Let sndr and env be subexpressions
|
||||
such that Sndr is decltype((sndr)) andEnv is decltype((env))[.](#4.sentence-1)
|
||||
|
||||
If [*sender-for*](exec.snd.concepts#concept:sender-for "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr, stopped_as_optional_t> is false then the expression stopped_as_optional.transform_sender(sndr, env) is ill-formed;
|
||||
otherwise,
|
||||
if [sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<*child-type*<Sndr>, *FWD-ENV-T*(Env)> is false,
|
||||
the expression stopped_as_optional.transform_sender(sndr, env) is equivalent to *not-a-sender*();
|
||||
otherwise, it is equivalent to:auto&& [_, _, child] = sndr;using V = *single-sender-value-type*<*child-type*<Sndr>, *FWD-ENV-T*(Env)>;return let_stopped( then(std::forward_like<Sndr>(child), []<class... Ts>(Ts&&... ts) noexcept(is_nothrow_constructible_v<V, Ts...>) {return optional<V>(in_place, std::forward<Ts>(ts)...); }), []() noexcept { return just(optional<V>()); });
|
||||
147
cppdraft/exec/sync/wait.md
Normal file
147
cppdraft/exec/sync/wait.md
Normal file
@@ -0,0 +1,147 @@
|
||||
[exec.sync.wait]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#exec.sync.wait)
|
||||
|
||||
### 33.9.13 Sender consumers [[exec.consumers]](exec.consumers#exec.sync.wait)
|
||||
|
||||
#### 33.9.13.1 this_thread::sync_wait [exec.sync.wait]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5595)
|
||||
|
||||
this_thread::sync_wait and this_thread::sync_wait_with_variant are used
|
||||
to block the current thread of execution
|
||||
until the specified sender completes and
|
||||
to return its async result[.](#1.sentence-1)
|
||||
|
||||
sync_wait mandates
|
||||
that the input sender has exactly one value completion signature[.](#1.sentence-2)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5604)
|
||||
|
||||
Let *sync-wait-env* be the following exposition-only class type:namespace std::this_thread {struct *sync-wait-env* { execution::run_loop* *loop*; // *exposition only*auto query(execution::get_scheduler_t) const noexcept {return *loop*->get_scheduler(); }auto query(execution::get_delegation_scheduler_t) const noexcept {return *loop*->get_scheduler(); }};}
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5622)
|
||||
|
||||
Let *sync-wait-result-type* and*sync-wait-with-variant-result-type* be exposition-only alias templates defined as follows:namespace std::this_thread {template<execution::[sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<*sync-wait-env*> Sndr>using *sync-wait-result-type* = optional<execution::value_types_of_t<Sndr, *sync-wait-env*, *decayed-tuple*,
|
||||
type_identity_t>>; template<execution::[sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<*sync-wait-env*> Sndr>using *sync-wait-with-variant-result-type* = optional<execution::value_types_of_t<Sndr, *sync-wait-env*>>;}
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5639)
|
||||
|
||||
The name this_thread::sync_wait denotes a customization point object[.](#4.sentence-1)
|
||||
|
||||
For a subexpression sndr, let Sndr be decltype((sndr))[.](#4.sentence-2)
|
||||
|
||||
The expression this_thread::sync_wait(sndr) is expression-equivalent to the following,
|
||||
except that sndr is evaluated only once:apply_sender(*get-domain-early*(sndr), sync_wait, sndr)*Mandates*:
|
||||
|
||||
- [(4.1)](#4.1)
|
||||
|
||||
[sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr, *sync-wait-env*> is true[.](#4.1.sentence-1)
|
||||
|
||||
- [(4.2)](#4.2)
|
||||
|
||||
The type *sync-wait-result-type*<Sndr> is well-formed[.](#4.2.sentence-1)
|
||||
|
||||
- [(4.3)](#4.3)
|
||||
|
||||
[same_as](concept.same#concept:same_as "18.4.2 Concept same_as [concept.same]")<decltype(e), *sync-wait-result-type*<Sndr>> is true, where e is the apply_sender expression above[.](#4.3.sentence-1)
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5659)
|
||||
|
||||
Let *sync-wait-state* and *sync-wait-receiver* be the following exposition-only class templates:namespace std::this_thread {template<class Sndr>struct *sync-wait-state* { // *exposition only* execution::run_loop *loop*; // *exposition only* exception_ptr *error*; // *exposition only**sync-wait-result-type*<Sndr> *result*; // *exposition only*}; template<class Sndr>struct *sync-wait-receiver* { // *exposition only*using receiver_concept = execution::receiver_t; *sync-wait-state*<Sndr>* *state*; // *exposition only*template<class... Args>void set_value(Args&&... args) && noexcept; template<class Error>void set_error(Error&& err) && noexcept; void set_stopped() && noexcept; *sync-wait-env* get_env() const noexcept { return {&*state*->*loop*}; }};}
|
||||
|
||||
[ð](#itemdecl:1)
|
||||
|
||||
`template<class... Args>
|
||||
void set_value(Args&&... args) && noexcept;
|
||||
`
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5695)
|
||||
|
||||
*Effects*: Equivalent to:try {*state*->*result*.emplace(std::forward<Args>(args)...);} catch (...) {*state*->*error* = current_exception();}*state*->*loop*.finish();
|
||||
|
||||
[ð](#itemdecl:2)
|
||||
|
||||
`template<class Error>
|
||||
void set_error(Error&& err) && noexcept;
|
||||
`
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5714)
|
||||
|
||||
*Effects*: Equivalent to:*state*->*error* = *AS-EXCEPT-PTR*(std::forward<Error>(err)); // see [[exec.general]](exec.general "33.1 General")*state*->*loop*.finish();
|
||||
|
||||
[ð](#itemdecl:3)
|
||||
|
||||
`void set_stopped() && noexcept;
|
||||
`
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5728)
|
||||
|
||||
*Effects*: Equivalent to *state*->*loop*.finish()[.](#8.sentence-1)
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5733)
|
||||
|
||||
For a subexpression sndr, let Sndr be decltype((sndr))[.](#9.sentence-1)
|
||||
|
||||
If [sender_to](exec.snd.concepts#concept:sender_to "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr, *sync-wait-receiver*<Sndr>> is false,
|
||||
the expression sync_wait.apply_sender(sndr) is ill-formed;
|
||||
otherwise, it is equivalent to:*sync-wait-state*<Sndr> state;auto op = connect(sndr, *sync-wait-receiver*<Sndr>{&state});
|
||||
start(op);
|
||||
|
||||
state.*loop*.run();if (state.*error*) { rethrow_exception(std::move(state.*error*));}return std::move(state.*result*);
|
||||
|
||||
[10](#10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5751)
|
||||
|
||||
The behavior of this_thread::sync_wait(sndr) is undefined unless:
|
||||
|
||||
- [(10.1)](#10.1)
|
||||
|
||||
It blocks the current thread of execution ([[defns.block]](defns.block "3.6 block"))
|
||||
with forward progress guarantee delegation ([[intro.progress]](intro.progress "6.10.2.3 Forward progress"))
|
||||
until the specified sender completes[.](#10.1.sentence-1)
|
||||
[*Note [1](#note-1)*:
|
||||
The default implementation of sync_wait achieves
|
||||
forward progress guarantee delegation by providing a run_loop scheduler
|
||||
via the get_delegation_scheduler query
|
||||
on the *sync-wait-receiver*'s environment[.](#10.1.sentence-2)
|
||||
The run_loop is driven by the current thread of execution[.](#10.1.sentence-3)
|
||||
â *end note*]
|
||||
|
||||
- [(10.2)](#10.2)
|
||||
|
||||
It returns the specified sender's async results as follows:
|
||||
* [(10.2.1)](#10.2.1)
|
||||
|
||||
For a value completion,
|
||||
the result datums are returned in
|
||||
a tuple in an engaged optional object[.](#10.2.1.sentence-1)
|
||||
|
||||
* [(10.2.2)](#10.2.2)
|
||||
|
||||
For an error completion, an exception is thrown[.](#10.2.2.sentence-1)
|
||||
|
||||
* [(10.2.3)](#10.2.3)
|
||||
|
||||
For a stopped completion, a disengaged optional object is returned[.](#10.2.3.sentence-1)
|
||||
74
cppdraft/exec/sync/wait/var.md
Normal file
74
cppdraft/exec/sync/wait/var.md
Normal file
@@ -0,0 +1,74 @@
|
||||
[exec.sync.wait.var]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#exec.sync.wait.var)
|
||||
|
||||
### 33.9.13 Sender consumers [[exec.consumers]](exec.consumers#exec.sync.wait.var)
|
||||
|
||||
#### 33.9.13.2 this_thread::sync_wait_with_variant [exec.sync.wait.var]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5781)
|
||||
|
||||
The name this_thread::sync_wait_with_variant denotes
|
||||
a customization point object[.](#1.sentence-1)
|
||||
|
||||
For a subexpression sndr,
|
||||
let Sndr be decltype(into_variant(sndr))[.](#1.sentence-2)
|
||||
|
||||
The expression this_thread::sync_wait_with_variant(sndr) is expression-equivalent to the following,
|
||||
except sndr is evaluated only once:apply_sender(*get-domain-early*(sndr), sync_wait_with_variant, sndr)*Mandates*:
|
||||
|
||||
- [(1.1)](#1.1)
|
||||
|
||||
[sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr, *sync-wait-env*> is true[.](#1.1.sentence-1)
|
||||
|
||||
- [(1.2)](#1.2)
|
||||
|
||||
The type *sync-wait-with-variant-result-type*<Sndr> is well-formed[.](#1.2.sentence-1)
|
||||
|
||||
- [(1.3)](#1.3)
|
||||
|
||||
[same_as](concept.same#concept:same_as "18.4.2 Concept same_as [concept.same]")<decltype(e), *sync-wait-with-variant-result-type*<Sndr>> is true, where e is the apply_sender expression above[.](#1.3.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5804)
|
||||
|
||||
The expression sync_wait_with_variant.apply_sender(sndr) is equivalent to:using result_type = *sync-wait-with-variant-result-type*<Sndr>;if (auto opt_value = sync_wait(into_variant(sndr))) {return result_type(std::move(get<0>(*opt_value)));}return result_type(nullopt);
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L5814)
|
||||
|
||||
The behavior of this_thread::sync_wait_with_variant(sndr) is undefined unless:
|
||||
|
||||
- [(3.1)](#3.1)
|
||||
|
||||
It blocks the current thread of execution ([[defns.block]](defns.block "3.6 block"))
|
||||
with forward progress guarantee delegation ([[intro.progress]](intro.progress "6.10.2.3 Forward progress"))
|
||||
until the specified sender completes[.](#3.1.sentence-1)
|
||||
[*Note [1](#note-1)*:
|
||||
The default implementation of sync_wait_with_variant achieves
|
||||
forward progress guarantee delegation by relying on
|
||||
the forward progress guarantee delegation provided by sync_wait[.](#3.1.sentence-2)
|
||||
â *end note*]
|
||||
|
||||
- [(3.2)](#3.2)
|
||||
|
||||
It returns the specified sender's async results as follows:
|
||||
* [(3.2.1)](#3.2.1)
|
||||
|
||||
For a value completion,
|
||||
the result datums are returned in an engaged optional object
|
||||
that contains a variant of tuples[.](#3.2.1.sentence-1)
|
||||
|
||||
* [(3.2.2)](#3.2.2)
|
||||
|
||||
For an error completion, an exception is thrown[.](#3.2.2.sentence-1)
|
||||
|
||||
* [(3.2.3)](#3.2.3)
|
||||
|
||||
For a stopped completion, a disengaged optional object is returned[.](#3.2.3.sentence-1)
|
||||
297
cppdraft/exec/sysctxrepl.md
Normal file
297
cppdraft/exec/sysctxrepl.md
Normal file
@@ -0,0 +1,297 @@
|
||||
[exec.sysctxrepl]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.16 Namespace system_context_replaceability [exec.sysctxrepl]
|
||||
|
||||
### [33.16.1](#general) General [[exec.sysctxrepl.general]](exec.sysctxrepl.general)
|
||||
|
||||
[1](#general-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8432)
|
||||
|
||||
Facilities in the system_context_replaceability namespace
|
||||
allow users to replace the default implementation of parallel_scheduler[.](#general-1.sentence-1)
|
||||
|
||||
### [33.16.2](#query) query_parallel_scheduler_backend [[exec.sysctxrepl.query]](exec.sysctxrepl.query)
|
||||
|
||||
[ð](#lib:query_parallel_scheduler_backend)
|
||||
|
||||
`shared_ptr<parallel_scheduler_backend> query_parallel_scheduler_backend();
|
||||
`
|
||||
|
||||
[1](#query-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8443)
|
||||
|
||||
query_parallel_scheduler_backend() returns
|
||||
the implementation object for a parallel scheduler[.](#query-1.sentence-1)
|
||||
|
||||
[2](#query-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8447)
|
||||
|
||||
*Returns*: A non-null shared pointer to an object
|
||||
that implements the parallel_scheduler_backend interface[.](#query-2.sentence-1)
|
||||
|
||||
[3](#query-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8452)
|
||||
|
||||
*Remarks*: This function is replaceable ([[dcl.fct.def.replace]](dcl.fct.def.replace#term.replaceable.function "9.6.5 Replaceable function definitions"))[.](#query-3.sentence-1)
|
||||
|
||||
namespace std::execution::system_context_replaceability {struct [receiver_proxy](#lib:receiver_proxy "33.16.2 query_parallel_scheduler_backend [exec.sysctxrepl.query]") {virtual ~receiver_proxy() = default; protected:virtual bool *query-env*(*unspecified*) noexcept = 0; // *exposition only*public:virtual void set_value() noexcept = 0; virtual void set_error(exception_ptr) noexcept = 0; virtual void set_stopped() noexcept = 0; template<class P, [*class-type*](execution.syn#concept:class-type "33.4 Header <execution> synopsis [execution.syn]") Query> optional<P> try_query(Query q) noexcept; }; struct [bulk_item_receiver_proxy](#lib:bulk_item_receiver_proxy "33.16.2 query_parallel_scheduler_backend [exec.sysctxrepl.query]") : receiver_proxy {virtual void execute(size_t, size_t) noexcept = 0; };}
|
||||
|
||||
[4](#query-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8480)
|
||||
|
||||
receiver_proxy represents a receiver
|
||||
that will be notified
|
||||
by the implementations of parallel_scheduler_backend to trigger the completion operations[.](#query-4.sentence-1)
|
||||
|
||||
bulk_item_receiver_proxy is derived from receiver_proxy and
|
||||
is used for bulk_chunked and bulk_unchunked customizations
|
||||
that will also receive notifications
|
||||
from implementations of parallel_scheduler_backend corresponding to different iterations[.](#query-4.sentence-2)
|
||||
|
||||
[ð](#query-itemdecl:2)
|
||||
|
||||
`template<class P, [class-type](execution.syn#concept:class-type "33.4 Header <execution> synopsis [execution.syn]") Query>
|
||||
optional<P> [try_query](#lib:try_query "33.16.2 query_parallel_scheduler_backend [exec.sysctxrepl.query]")(Query q) noexcept;
|
||||
`
|
||||
|
||||
[5](#query-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8497)
|
||||
|
||||
*Mandates*: P is a cv-unqualified non-array object type[.](#query-5.sentence-1)
|
||||
|
||||
[6](#query-6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8501)
|
||||
|
||||
*Returns*: Let env be the environment of the receiver represented by *this[.](#query-6.sentence-1)
|
||||
|
||||
If
|
||||
|
||||
- [(6.1)](#query-6.1)
|
||||
|
||||
Query is not a member of an implementation-defined set
|
||||
of supported queries; or
|
||||
|
||||
- [(6.2)](#query-6.2)
|
||||
|
||||
P is not a member of an implementation-defined set
|
||||
of supported result types for Query; or
|
||||
|
||||
- [(6.3)](#query-6.3)
|
||||
|
||||
the expression q(env) is not well-formed or
|
||||
does not have type cv P,
|
||||
|
||||
then returns nullopt[.](#query-6.sentence-2)
|
||||
|
||||
Otherwise, returns q(env)[.](#query-6.sentence-3)
|
||||
|
||||
[7](#query-7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8519)
|
||||
|
||||
*Remarks*: get_stop_token_t is
|
||||
in the implementation-defined set of supported queries, andinplace_stop_token is a member
|
||||
of the implementation-defined set of supported result types
|
||||
for get_stop_token_t[.](#query-7.sentence-1)
|
||||
|
||||
### [33.16.3](#psb) Class parallel_scheduler_backend [[exec.sysctxrepl.psb]](exec.sysctxrepl.psb)
|
||||
|
||||
namespace std::execution::system_context_replaceability {struct [parallel_scheduler_backend](#lib:parallel_scheduler_backend "33.16.3 Class parallel_scheduler_backend [exec.sysctxrepl.psb]") {virtual ~parallel_scheduler_backend() = default; virtual void schedule(receiver_proxy&, span<byte>) noexcept = 0; virtual void schedule_bulk_chunked(size_t, bulk_item_receiver_proxy&,
|
||||
span<byte>) noexcept = 0; virtual void schedule_bulk_unchunked(size_t, bulk_item_receiver_proxy&,
|
||||
span<byte>) noexcept = 0; };}
|
||||
|
||||
[ð](#lib:schedule,parallel_scheduler_backend)
|
||||
|
||||
`virtual void schedule(receiver_proxy& r, span<byte> s) noexcept = 0;
|
||||
`
|
||||
|
||||
[1](#psb-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8550)
|
||||
|
||||
*Preconditions*: The ends of
|
||||
the lifetimes of *this,
|
||||
the object referred to by r, and
|
||||
any storage referenced by s all happen after
|
||||
the beginning of the evaluation of
|
||||
the call to set_value, set_error, or set_done on r (see below)[.](#psb-1.sentence-1)
|
||||
|
||||
[2](#psb-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8561)
|
||||
|
||||
*Effects*: A derived class shall implement this function such that:
|
||||
|
||||
- [(2.1)](#psb-2.1)
|
||||
|
||||
One of the following expressions is evaluated:
|
||||
* [(2.1.1)](#psb-2.1.1)
|
||||
|
||||
r.set_value(), if no error occurs, and the work is successful;
|
||||
|
||||
* [(2.1.2)](#psb-2.1.2)
|
||||
|
||||
r.set_error(eptr), if an error occurs,
|
||||
where eptr is an object of type exception_ptr;
|
||||
|
||||
* [(2.1.3)](#psb-2.1.3)
|
||||
|
||||
r.set_stopped(), if the work is canceled[.](#psb-2.1.sentence-1)
|
||||
|
||||
- [(2.2)](#psb-2.2)
|
||||
|
||||
Any call to r.set_value() happens on
|
||||
an execution agent of the execution context represented by *this[.](#psb-2.2.sentence-1)
|
||||
|
||||
[3](#psb-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8581)
|
||||
|
||||
*Remarks*: The storage referenced by s may be used by *this as temporary storage
|
||||
for the duration of the operation launched by this call[.](#psb-3.sentence-1)
|
||||
|
||||
[ð](#lib:schedule_bulk_chunked,parallel_scheduler_backend)
|
||||
|
||||
`virtual void schedule_bulk_chunked(size_t n, bulk_item_receiver_proxy& r,
|
||||
span<byte> s) noexcept = 0;
|
||||
`
|
||||
|
||||
[4](#psb-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8595)
|
||||
|
||||
*Preconditions*: The ends of
|
||||
the lifetimes of *this,
|
||||
the object referred to by r, and
|
||||
any storage referenced by s all happen after
|
||||
the beginning of the evaluation of one of the expressions below[.](#psb-4.sentence-1)
|
||||
|
||||
[5](#psb-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8604)
|
||||
|
||||
*Effects*: A derived class shall implement this function such that:
|
||||
|
||||
- [(5.1)](#psb-5.1)
|
||||
|
||||
Eventually, one of the following expressions is evaluated:
|
||||
* [(5.1.1)](#psb-5.1.1)
|
||||
|
||||
r.set_value(), if no error occurs, and the work is successful;
|
||||
|
||||
* [(5.1.2)](#psb-5.1.2)
|
||||
|
||||
r.set_error(eptr), if an error occurs,
|
||||
where eptr is an object of type exception_ptr;
|
||||
|
||||
* [(5.1.3)](#psb-5.1.3)
|
||||
|
||||
r.set_stopped(), if the work is canceled[.](#psb-5.1.sentence-1)
|
||||
|
||||
- [(5.2)](#psb-5.2)
|
||||
|
||||
If r.execute(b, e) is called,
|
||||
then b and e are in the range [0, n] andb < e[.](#psb-5.2.sentence-1)
|
||||
|
||||
- [(5.3)](#psb-5.3)
|
||||
|
||||
For each i in [0, n),
|
||||
there is at most one call to r.execute(b, e) such that i is in the range [b, e)[.](#psb-5.3.sentence-1)
|
||||
|
||||
- [(5.4)](#psb-5.4)
|
||||
|
||||
If r.set_value() is called,
|
||||
then for each i in [0, n),
|
||||
there is exactly one call to r.execute(b, e) such that i is in the range [b, e)[.](#psb-5.4.sentence-1)
|
||||
|
||||
- [(5.5)](#psb-5.5)
|
||||
|
||||
All calls to execute on r happen before
|
||||
the call to either set_value, set_error, or set_stopped on r[.](#psb-5.5.sentence-1)
|
||||
|
||||
- [(5.6)](#psb-5.6)
|
||||
|
||||
All calls to execute and set_value on r are made
|
||||
on execution agents of the execution context represented by *this[.](#psb-5.6.sentence-1)
|
||||
|
||||
[6](#psb-6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8641)
|
||||
|
||||
*Remarks*: The storage referenced by s may be used by *this as temporary storage for the duration of the operation launched by this call[.](#psb-6.sentence-1)
|
||||
|
||||
[ð](#lib:schedule_bulk_unchunked,parallel_scheduler_backend)
|
||||
|
||||
`virtual void schedule_bulk_unchunked(size_t n, bulk_item_receiver_proxy& r,
|
||||
span<byte> s) noexcept = 0;
|
||||
`
|
||||
|
||||
[7](#psb-7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8654)
|
||||
|
||||
*Preconditions*: The ends of
|
||||
the lifetimes of *this,
|
||||
the object referred to by r, and
|
||||
any storage referenced by s all happen after
|
||||
the beginning of the evaluation of one of the expressions below[.](#psb-7.sentence-1)
|
||||
|
||||
[8](#psb-8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8663)
|
||||
|
||||
*Effects*: A derived class shall implement this function such that:
|
||||
|
||||
- [(8.1)](#psb-8.1)
|
||||
|
||||
Eventually, one of the following expressions is evaluated:
|
||||
* [(8.1.1)](#psb-8.1.1)
|
||||
|
||||
r.set_value(), if no error occurs, and the work is successful;
|
||||
|
||||
* [(8.1.2)](#psb-8.1.2)
|
||||
|
||||
r.set_error(eptr), if an error occurs,
|
||||
where eptr is an object of type exception_ptr;
|
||||
|
||||
* [(8.1.3)](#psb-8.1.3)
|
||||
|
||||
r.set_stopped(), if the work is canceled[.](#psb-8.1.sentence-1)
|
||||
|
||||
- [(8.2)](#psb-8.2)
|
||||
|
||||
If r.execute(b, e) is called,
|
||||
then b is in the range [0, n) ande is equal to b + 1[.](#psb-8.2.sentence-1)
|
||||
For each i in [0, n),
|
||||
there is at most one call to r.execute(i, i + 1)[.](#psb-8.2.sentence-2)
|
||||
|
||||
- [(8.3)](#psb-8.3)
|
||||
|
||||
If r.set_value() is called,
|
||||
then for each i in [0, n),
|
||||
there is exactly one call to r.execute(i, i + 1)[.](#psb-8.3.sentence-1)
|
||||
|
||||
- [(8.4)](#psb-8.4)
|
||||
|
||||
All calls to execute on r happen before
|
||||
the call to either set_value, set_error, or set_stopped on r[.](#psb-8.4.sentence-1)
|
||||
|
||||
- [(8.5)](#psb-8.5)
|
||||
|
||||
All calls to execute and set_value on r are made
|
||||
on execution agents of the execution context represented by *this[.](#psb-8.5.sentence-1)
|
||||
|
||||
[9](#psb-9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8697)
|
||||
|
||||
*Remarks*: The storage referenced by s may be used by *this as temporary storage for the duration of the operation launched by this call[.](#psb-9.sentence-1)
|
||||
14
cppdraft/exec/sysctxrepl/general.md
Normal file
14
cppdraft/exec/sysctxrepl/general.md
Normal file
@@ -0,0 +1,14 @@
|
||||
[exec.sysctxrepl.general]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.16 Namespace system_context_replaceability [[exec.sysctxrepl]](exec.sysctxrepl#general)
|
||||
|
||||
### 33.16.1 General [exec.sysctxrepl.general]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8432)
|
||||
|
||||
Facilities in the system_context_replaceability namespace
|
||||
allow users to replace the default implementation of parallel_scheduler[.](#1.sentence-1)
|
||||
198
cppdraft/exec/sysctxrepl/psb.md
Normal file
198
cppdraft/exec/sysctxrepl/psb.md
Normal file
@@ -0,0 +1,198 @@
|
||||
[exec.sysctxrepl.psb]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.16 Namespace system_context_replaceability [[exec.sysctxrepl]](exec.sysctxrepl#psb)
|
||||
|
||||
### 33.16.3 Class parallel_scheduler_backend [exec.sysctxrepl.psb]
|
||||
|
||||
namespace std::execution::system_context_replaceability {struct [parallel_scheduler_backend](#lib:parallel_scheduler_backend "33.16.3 Class parallel_scheduler_backend [exec.sysctxrepl.psb]") {virtual ~parallel_scheduler_backend() = default; virtual void schedule(receiver_proxy&, span<byte>) noexcept = 0; virtual void schedule_bulk_chunked(size_t, bulk_item_receiver_proxy&,
|
||||
span<byte>) noexcept = 0; virtual void schedule_bulk_unchunked(size_t, bulk_item_receiver_proxy&,
|
||||
span<byte>) noexcept = 0; };}
|
||||
|
||||
[ð](#lib:schedule,parallel_scheduler_backend)
|
||||
|
||||
`virtual void schedule(receiver_proxy& r, span<byte> s) noexcept = 0;
|
||||
`
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8550)
|
||||
|
||||
*Preconditions*: The ends of
|
||||
the lifetimes of *this,
|
||||
the object referred to by r, and
|
||||
any storage referenced by s all happen after
|
||||
the beginning of the evaluation of
|
||||
the call to set_value, set_error, or set_done on r (see below)[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8561)
|
||||
|
||||
*Effects*: A derived class shall implement this function such that:
|
||||
|
||||
- [(2.1)](#2.1)
|
||||
|
||||
One of the following expressions is evaluated:
|
||||
* [(2.1.1)](#2.1.1)
|
||||
|
||||
r.set_value(), if no error occurs, and the work is successful;
|
||||
|
||||
* [(2.1.2)](#2.1.2)
|
||||
|
||||
r.set_error(eptr), if an error occurs,
|
||||
where eptr is an object of type exception_ptr;
|
||||
|
||||
* [(2.1.3)](#2.1.3)
|
||||
|
||||
r.set_stopped(), if the work is canceled[.](#2.1.sentence-1)
|
||||
|
||||
- [(2.2)](#2.2)
|
||||
|
||||
Any call to r.set_value() happens on
|
||||
an execution agent of the execution context represented by *this[.](#2.2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8581)
|
||||
|
||||
*Remarks*: The storage referenced by s may be used by *this as temporary storage
|
||||
for the duration of the operation launched by this call[.](#3.sentence-1)
|
||||
|
||||
[ð](#lib:schedule_bulk_chunked,parallel_scheduler_backend)
|
||||
|
||||
`virtual void schedule_bulk_chunked(size_t n, bulk_item_receiver_proxy& r,
|
||||
span<byte> s) noexcept = 0;
|
||||
`
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8595)
|
||||
|
||||
*Preconditions*: The ends of
|
||||
the lifetimes of *this,
|
||||
the object referred to by r, and
|
||||
any storage referenced by s all happen after
|
||||
the beginning of the evaluation of one of the expressions below[.](#4.sentence-1)
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8604)
|
||||
|
||||
*Effects*: A derived class shall implement this function such that:
|
||||
|
||||
- [(5.1)](#5.1)
|
||||
|
||||
Eventually, one of the following expressions is evaluated:
|
||||
* [(5.1.1)](#5.1.1)
|
||||
|
||||
r.set_value(), if no error occurs, and the work is successful;
|
||||
|
||||
* [(5.1.2)](#5.1.2)
|
||||
|
||||
r.set_error(eptr), if an error occurs,
|
||||
where eptr is an object of type exception_ptr;
|
||||
|
||||
* [(5.1.3)](#5.1.3)
|
||||
|
||||
r.set_stopped(), if the work is canceled[.](#5.1.sentence-1)
|
||||
|
||||
- [(5.2)](#5.2)
|
||||
|
||||
If r.execute(b, e) is called,
|
||||
then b and e are in the range [0, n] andb < e[.](#5.2.sentence-1)
|
||||
|
||||
- [(5.3)](#5.3)
|
||||
|
||||
For each i in [0, n),
|
||||
there is at most one call to r.execute(b, e) such that i is in the range [b, e)[.](#5.3.sentence-1)
|
||||
|
||||
- [(5.4)](#5.4)
|
||||
|
||||
If r.set_value() is called,
|
||||
then for each i in [0, n),
|
||||
there is exactly one call to r.execute(b, e) such that i is in the range [b, e)[.](#5.4.sentence-1)
|
||||
|
||||
- [(5.5)](#5.5)
|
||||
|
||||
All calls to execute on r happen before
|
||||
the call to either set_value, set_error, or set_stopped on r[.](#5.5.sentence-1)
|
||||
|
||||
- [(5.6)](#5.6)
|
||||
|
||||
All calls to execute and set_value on r are made
|
||||
on execution agents of the execution context represented by *this[.](#5.6.sentence-1)
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8641)
|
||||
|
||||
*Remarks*: The storage referenced by s may be used by *this as temporary storage for the duration of the operation launched by this call[.](#6.sentence-1)
|
||||
|
||||
[ð](#lib:schedule_bulk_unchunked,parallel_scheduler_backend)
|
||||
|
||||
`virtual void schedule_bulk_unchunked(size_t n, bulk_item_receiver_proxy& r,
|
||||
span<byte> s) noexcept = 0;
|
||||
`
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8654)
|
||||
|
||||
*Preconditions*: The ends of
|
||||
the lifetimes of *this,
|
||||
the object referred to by r, and
|
||||
any storage referenced by s all happen after
|
||||
the beginning of the evaluation of one of the expressions below[.](#7.sentence-1)
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8663)
|
||||
|
||||
*Effects*: A derived class shall implement this function such that:
|
||||
|
||||
- [(8.1)](#8.1)
|
||||
|
||||
Eventually, one of the following expressions is evaluated:
|
||||
* [(8.1.1)](#8.1.1)
|
||||
|
||||
r.set_value(), if no error occurs, and the work is successful;
|
||||
|
||||
* [(8.1.2)](#8.1.2)
|
||||
|
||||
r.set_error(eptr), if an error occurs,
|
||||
where eptr is an object of type exception_ptr;
|
||||
|
||||
* [(8.1.3)](#8.1.3)
|
||||
|
||||
r.set_stopped(), if the work is canceled[.](#8.1.sentence-1)
|
||||
|
||||
- [(8.2)](#8.2)
|
||||
|
||||
If r.execute(b, e) is called,
|
||||
then b is in the range [0, n) ande is equal to b + 1[.](#8.2.sentence-1)
|
||||
For each i in [0, n),
|
||||
there is at most one call to r.execute(i, i + 1)[.](#8.2.sentence-2)
|
||||
|
||||
- [(8.3)](#8.3)
|
||||
|
||||
If r.set_value() is called,
|
||||
then for each i in [0, n),
|
||||
there is exactly one call to r.execute(i, i + 1)[.](#8.3.sentence-1)
|
||||
|
||||
- [(8.4)](#8.4)
|
||||
|
||||
All calls to execute on r happen before
|
||||
the call to either set_value, set_error, or set_stopped on r[.](#8.4.sentence-1)
|
||||
|
||||
- [(8.5)](#8.5)
|
||||
|
||||
All calls to execute and set_value on r are made
|
||||
on execution agents of the execution context represented by *this[.](#8.5.sentence-1)
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8697)
|
||||
|
||||
*Remarks*: The storage referenced by s may be used by *this as temporary storage for the duration of the operation launched by this call[.](#9.sentence-1)
|
||||
95
cppdraft/exec/sysctxrepl/query.md
Normal file
95
cppdraft/exec/sysctxrepl/query.md
Normal file
@@ -0,0 +1,95 @@
|
||||
[exec.sysctxrepl.query]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.16 Namespace system_context_replaceability [[exec.sysctxrepl]](exec.sysctxrepl#query)
|
||||
|
||||
### 33.16.2 query_parallel_scheduler_backend [exec.sysctxrepl.query]
|
||||
|
||||
[ð](#lib:query_parallel_scheduler_backend)
|
||||
|
||||
`shared_ptr<parallel_scheduler_backend> query_parallel_scheduler_backend();
|
||||
`
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8443)
|
||||
|
||||
query_parallel_scheduler_backend() returns
|
||||
the implementation object for a parallel scheduler[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8447)
|
||||
|
||||
*Returns*: A non-null shared pointer to an object
|
||||
that implements the parallel_scheduler_backend interface[.](#2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8452)
|
||||
|
||||
*Remarks*: This function is replaceable ([[dcl.fct.def.replace]](dcl.fct.def.replace#term.replaceable.function "9.6.5 Replaceable function definitions"))[.](#3.sentence-1)
|
||||
|
||||
namespace std::execution::system_context_replaceability {struct [receiver_proxy](#lib:receiver_proxy "33.16.2 query_parallel_scheduler_backend [exec.sysctxrepl.query]") {virtual ~receiver_proxy() = default; protected:virtual bool *query-env*(*unspecified*) noexcept = 0; // *exposition only*public:virtual void set_value() noexcept = 0; virtual void set_error(exception_ptr) noexcept = 0; virtual void set_stopped() noexcept = 0; template<class P, [*class-type*](execution.syn#concept:class-type "33.4 Header <execution> synopsis [execution.syn]") Query> optional<P> try_query(Query q) noexcept; }; struct [bulk_item_receiver_proxy](#lib:bulk_item_receiver_proxy "33.16.2 query_parallel_scheduler_backend [exec.sysctxrepl.query]") : receiver_proxy {virtual void execute(size_t, size_t) noexcept = 0; };}
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8480)
|
||||
|
||||
receiver_proxy represents a receiver
|
||||
that will be notified
|
||||
by the implementations of parallel_scheduler_backend to trigger the completion operations[.](#4.sentence-1)
|
||||
|
||||
bulk_item_receiver_proxy is derived from receiver_proxy and
|
||||
is used for bulk_chunked and bulk_unchunked customizations
|
||||
that will also receive notifications
|
||||
from implementations of parallel_scheduler_backend corresponding to different iterations[.](#4.sentence-2)
|
||||
|
||||
[ð](#itemdecl:2)
|
||||
|
||||
`template<class P, [class-type](execution.syn#concept:class-type "33.4 Header <execution> synopsis [execution.syn]") Query>
|
||||
optional<P> [try_query](#lib:try_query "33.16.2 query_parallel_scheduler_backend [exec.sysctxrepl.query]")(Query q) noexcept;
|
||||
`
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8497)
|
||||
|
||||
*Mandates*: P is a cv-unqualified non-array object type[.](#5.sentence-1)
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8501)
|
||||
|
||||
*Returns*: Let env be the environment of the receiver represented by *this[.](#6.sentence-1)
|
||||
|
||||
If
|
||||
|
||||
- [(6.1)](#6.1)
|
||||
|
||||
Query is not a member of an implementation-defined set
|
||||
of supported queries; or
|
||||
|
||||
- [(6.2)](#6.2)
|
||||
|
||||
P is not a member of an implementation-defined set
|
||||
of supported result types for Query; or
|
||||
|
||||
- [(6.3)](#6.3)
|
||||
|
||||
the expression q(env) is not well-formed or
|
||||
does not have type cv P,
|
||||
|
||||
then returns nullopt[.](#6.sentence-2)
|
||||
|
||||
Otherwise, returns q(env)[.](#6.sentence-3)
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L8519)
|
||||
|
||||
*Remarks*: get_stop_token_t is
|
||||
in the implementation-defined set of supported queries, andinplace_stop_token is a member
|
||||
of the implementation-defined set of supported result types
|
||||
for get_stop_token_t[.](#7.sentence-1)
|
||||
530
cppdraft/exec/task.md
Normal file
530
cppdraft/exec/task.md
Normal file
@@ -0,0 +1,530 @@
|
||||
[exec.task]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.13 Coroutine utilities [[exec.coro.util]](exec.coro.util#exec.task)
|
||||
|
||||
### 33.13.6 execution::task [exec.task]
|
||||
|
||||
#### [33.13.6.1](#task.overview) task overview [[task.overview]](task.overview)
|
||||
|
||||
[1](#task.overview-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7171)
|
||||
|
||||
The task class template represents a sender that can
|
||||
be used as the return type of coroutines[.](#task.overview-1.sentence-1)
|
||||
|
||||
The first template parameter T defines the type of the value
|
||||
completion datum ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations")) if T is not void[.](#task.overview-1.sentence-2)
|
||||
|
||||
Otherwise, there are no value completion datums[.](#task.overview-1.sentence-3)
|
||||
|
||||
Inside coroutines returning task<T, E> the operand ofco_return (if any) becomes the argument of set_value[.](#task.overview-1.sentence-4)
|
||||
|
||||
The second template parameter Environment is used to customize
|
||||
the behavior of task[.](#task.overview-1.sentence-5)
|
||||
|
||||
#### [33.13.6.2](#task.class) Class template task [[task.class]](task.class)
|
||||
|
||||
namespace std::execution {template<class T, class Environment>class [task](#lib:task "33.13.6.2 Class template task [task.class]") {// [[task.state]](#task.state "33.13.6.4 Class template task::state")template<[receiver](exec.recv.concepts#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]") Rcvr>class *state*; // *exposition only*public:using sender_concept = sender_t; using completion_signatures = *see below*; using allocator_type = *see below*; using scheduler_type = *see below*; using stop_source_type = *see below*; using stop_token_type = decltype(declval<stop_source_type>().get_token()); using error_types = *see below*; // [[task.promise]](#task.promise "33.13.6.5 Class task::promise_type")class promise_type;
|
||||
|
||||
task(task&&) noexcept; ~task(); template<[receiver](exec.recv.concepts#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]") Rcvr>*state*<Rcvr> connect(Rcvr&& rcvr); private: coroutine_handle<promise_type> *handle*; // *exposition only*};}
|
||||
|
||||
[1](#task.class-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7216)
|
||||
|
||||
task<T, E> models [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") ([[exec.snd]](exec.snd "33.9 Senders"))
|
||||
if T is void, a reference type, or a cv-unqualified
|
||||
non-array object type and E is a class type[.](#task.class-1.sentence-1)
|
||||
|
||||
Otherwise a program that instantiates the definition of task<T, E> is ill-formed[.](#task.class-1.sentence-2)
|
||||
|
||||
[2](#task.class-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7223)
|
||||
|
||||
The nested types of task template specializations
|
||||
are determined based on the Environment parameter:
|
||||
|
||||
- [(2.1)](#task.class-2.1)
|
||||
|
||||
allocator_type is Environment::allocator_type if that [*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") is valid and denotes a type,allocator<byte> otherwise[.](#task.class-2.1.sentence-1)
|
||||
|
||||
- [(2.2)](#task.class-2.2)
|
||||
|
||||
scheduler_type is Environment::scheduler_type if that [*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") is valid and denotes a type,task_scheduler otherwise[.](#task.class-2.2.sentence-1)
|
||||
|
||||
- [(2.3)](#task.class-2.3)
|
||||
|
||||
stop_source_type is Environment::stop_source_type if that [*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") is valid and denotes a type,inplace_stop_source otherwise[.](#task.class-2.3.sentence-1)
|
||||
|
||||
- [(2.4)](#task.class-2.4)
|
||||
|
||||
error_types is Environment::error_types if
|
||||
that [*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") is valid and denotes a type,completion_signatures<set_error_t(exception_ptr)> otherwise[.](#task.class-2.4.sentence-1)
|
||||
|
||||
[3](#task.class-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7241)
|
||||
|
||||
A program is ill-formed if error_types is not a
|
||||
specialization of completion_signatures<ErrorSigs...> orErrorSigs contains an element which is not of the formset_error_t(E) for some type E[.](#task.class-3.sentence-1)
|
||||
|
||||
[4](#task.class-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7247)
|
||||
|
||||
The type alias completion_signatures is a specialization
|
||||
of execution::completion_signatures with the template
|
||||
arguments (in unspecified order):
|
||||
|
||||
- [(4.1)](#task.class-4.1)
|
||||
|
||||
set_value_t() if T is void,
|
||||
and set_value_t(T) otherwise;
|
||||
|
||||
- [(4.2)](#task.class-4.2)
|
||||
|
||||
template arguments of the specialization ofexecution::completion_signatures denoted by error_types;
|
||||
and
|
||||
|
||||
- [(4.3)](#task.class-4.3)
|
||||
|
||||
set_stopped_t()[.](#task.class-4.sentence-1)
|
||||
|
||||
[5](#task.class-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7260)
|
||||
|
||||
allocator_type shall meet the *Cpp17Allocator* requirements[.](#task.class-5.sentence-1)
|
||||
|
||||
#### [33.13.6.3](#task.members) task members [[task.members]](task.members)
|
||||
|
||||
[ð](#lib:task,constructor)
|
||||
|
||||
`task(task&& other) noexcept;
|
||||
`
|
||||
|
||||
[1](#task.members-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7271)
|
||||
|
||||
*Effects*: Initializes *handle* with exchange(other.*handle*,{})[.](#task.members-1.sentence-1)
|
||||
|
||||
[ð](#lib:task,destructor)
|
||||
|
||||
`~task();
|
||||
`
|
||||
|
||||
[2](#task.members-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7282)
|
||||
|
||||
*Effects*: Equivalent to:if (*handle*)*handle*.destroy();
|
||||
|
||||
[ð](#lib:connect,task)
|
||||
|
||||
`template<[receiver](exec.recv.concepts#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]") Rcvr>
|
||||
state<Rcvr> connect(Rcvr&& recv);
|
||||
`
|
||||
|
||||
[3](#task.members-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7297)
|
||||
|
||||
*Preconditions*: bool(*handle*) is true[.](#task.members-3.sentence-1)
|
||||
|
||||
[4](#task.members-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7301)
|
||||
|
||||
*Effects*: Equivalent to:return *state*<Rcvr>(exchange(*handle*, {}), std::forward<Rcvr>(recv));
|
||||
|
||||
#### [33.13.6.4](#task.state) Class template task::*state* [[task.state]](task.state)
|
||||
|
||||
namespace std::execution {template<class T, class Environment>template<[receiver](exec.recv.concepts#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]") Rcvr>class task<T, Environment>::*state* { // *exposition only*public:using operation_state_concept = operation_state_t; template<class R>*state*(coroutine_handle<promise_type> h, R&& rr); ~*state*(); void start() & noexcept; private:using *own-env-t* = *see below*; // *exposition only* coroutine_handle<promise_type> *handle*; // *exposition only* remove_cvref_t<Rcvr> *rcvr*; // *exposition only**own-env-t* *own-env*; // *exposition only* Environment *environment*; // *exposition only*};}
|
||||
|
||||
[1](#task.state-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7336)
|
||||
|
||||
The type *own-env-t* is Environment::template env_type<decltype(get_env(declval<Rcvr>()))> if that[*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") is valid and denotes a type, env<> otherwise[.](#task.state-1.sentence-1)
|
||||
|
||||
[ð](#lib:task::state,constructor)
|
||||
|
||||
`template<class R>
|
||||
state(coroutine_handle<promise_type> h, R&& rr);
|
||||
`
|
||||
|
||||
[2](#task.state-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7347)
|
||||
|
||||
*Effects*: Initializes
|
||||
|
||||
- [(2.1)](#task.state-2.1)
|
||||
|
||||
*handle* with std::move(h);
|
||||
|
||||
- [(2.2)](#task.state-2.2)
|
||||
|
||||
*rcvr* with std::forward<R>(rr);
|
||||
|
||||
- [(2.3)](#task.state-2.3)
|
||||
|
||||
*own-env* with *own-env-t*(get_env(*rcvr*)) if that expression
|
||||
is valid and *own-env-t*() otherwise[.](#task.state-2.3.sentence-1)
|
||||
If neither of these expressions is valid, the program is ill-formed[.](#task.state-2.3.sentence-2)
|
||||
|
||||
- [(2.4)](#task.state-2.4)
|
||||
|
||||
*environment* withEnvironment(*own-env*) if that expression is
|
||||
valid, otherwise Environment(get_env(*rcvr*)) if this expression is valid, otherwise Environment()[.](#task.state-2.4.sentence-1)
|
||||
If neither of these expressions is valid, the program is ill-formed[.](#task.state-2.4.sentence-2)
|
||||
|
||||
[ð](#lib:task::state,destructor)
|
||||
|
||||
`~state();
|
||||
`
|
||||
|
||||
[3](#task.state-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7370)
|
||||
|
||||
*Effects*: Equivalent to:if (*handle*)*handle*.destroy();
|
||||
|
||||
[ð](#lib:start,task::state)
|
||||
|
||||
`void start() & noexcept;
|
||||
`
|
||||
|
||||
[4](#task.state-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7384)
|
||||
|
||||
*Effects*: Let *prom* be the object *handle*.promise()[.](#task.state-4.sentence-1)
|
||||
|
||||
Associates *STATE*(*prom*), *RCVR*(*prom*), and *SCHED*(*prom*) with *this as follows:
|
||||
|
||||
- [(4.1)](#task.state-4.1)
|
||||
|
||||
*STATE*(*prom*) is *this[.](#task.state-4.1.sentence-1)
|
||||
|
||||
- [(4.2)](#task.state-4.2)
|
||||
|
||||
*RCVR*(*prom*) is *rcvr*[.](#task.state-4.2.sentence-1)
|
||||
|
||||
- [(4.3)](#task.state-4.3)
|
||||
|
||||
*SCHED*(*prom*) is the object initialized
|
||||
with scheduler_type(get_scheduler(get_env(*rcvr*))) if that expression is valid and scheduler_type() otherwise[.](#task.state-4.3.sentence-1)
|
||||
If neither of these expressions is valid, the program is ill-formed[.](#task.state-4.3.sentence-2)
|
||||
|
||||
Let *st* be get_stop_token(get_env(*rcvr*))[.](#task.state-4.sentence-3)
|
||||
|
||||
Initializes *prom*.*token* and*prom*.*source* such that
|
||||
|
||||
- [(4.4)](#task.state-4.4)
|
||||
|
||||
*prom*.*token*.stop_requested() returns*st*.stop_requested();
|
||||
|
||||
- [(4.5)](#task.state-4.5)
|
||||
|
||||
*prom*.*token*.stop_possible() returns*st*.stop_possible(); and
|
||||
|
||||
- [(4.6)](#task.state-4.6)
|
||||
|
||||
for types Fn and Init such that both[invocable](concept.invocable#concept:invocable "18.7.2 Concept invocable [concept.invocable]")<Fn> and[constructible_from](concept.constructible#concept:constructible_from "18.4.11 Concept constructible_from [concept.constructible]")<Fn, Init> are modeled,stop_token_type::callback_type<Fn> models[*stoppable-callback-for*](stoptoken.concepts#concept:stoppable-callback-for "32.3.3 Stop token concepts [stoptoken.concepts]")<Fn, stop_token_type, Init>[.](#task.state-4.sentence-4)
|
||||
|
||||
After that invokes *handle*.resume()[.](#task.state-4.sentence-5)
|
||||
|
||||
#### [33.13.6.5](#task.promise) Class task::promise_type [[task.promise]](task.promise)
|
||||
|
||||
namespace std::execution {template<class T, class Environment>class task<T, Environment>::promise_type {public:template<class... Args> promise_type(const Args&... args);
|
||||
|
||||
task get_return_object() noexcept; auto initial_suspend() noexcept; auto final_suspend() noexcept; void uncaught_exception();
|
||||
coroutine_handle<> unhandled_stopped(); void return_void(); // present only if is_void_v<T> is truetemplate<class V>void return_value(V&& value); // present only if is_void_v<T> is falsetemplate<class E>*unspecified* yield_value(with_error<E> error); template<class A>auto await_transform(A&& a); template<class Sch>auto await_transform(change_coroutine_scheduler<Sch> sch); *unspecified* get_env() const noexcept; template<class... Args>void* operator new(size_t size, Args&&... args); void operator delete(void* pointer, size_t size) noexcept; private:using *error-variant* = *see below*; // *exposition only* allocator_type *alloc*; // *exposition only* stop_source_type *source*; // *exposition only* stop_token_type *token*; // *exposition only* optional<T> *result*; // *exposition only*; present only if is_void_v<T> is false*error-variant* *errors*; // *exposition only*};}
|
||||
|
||||
[1](#task.promise-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7466)
|
||||
|
||||
Let *prom* be an object of promise_type and let *tsk* be the task object
|
||||
created by *prom*.get_return_object()[.](#task.promise-1.sentence-1)
|
||||
|
||||
The description below
|
||||
refers to objects *STATE*(*prom*),*RCVR*(*prom*),
|
||||
and *SCHED*(*prom*) associated with *tsk* during evaluation of task::*state*<Rcvr>::start for some receiver Rcvr[.](#task.promise-1.sentence-2)
|
||||
|
||||
[2](#task.promise-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7478)
|
||||
|
||||
*error-variant* is a variant<monostate,
|
||||
remove_cvref_t<E>...>, with duplicate types removed, where E... are the parameter types of the template arguments of the specialization ofexecution::completion_signatures denoted byerror_types[.](#task.promise-2.sentence-1)
|
||||
|
||||
[ð](#lib:task::promise_type,constructor)
|
||||
|
||||
`template<class... Args>
|
||||
promise_type(const Args&... args);
|
||||
`
|
||||
|
||||
[3](#task.promise-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7491)
|
||||
|
||||
*Mandates*: The first parameter of type allocator_arg_t (if any) is not
|
||||
the last parameter[.](#task.promise-3.sentence-1)
|
||||
|
||||
[4](#task.promise-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7496)
|
||||
|
||||
*Effects*: If Args contains an element of type allocator_arg_t then *alloc* is initialized with the corresponding next
|
||||
element of args[.](#task.promise-4.sentence-1)
|
||||
|
||||
Otherwise, *alloc* is initialized with allocator_type()[.](#task.promise-4.sentence-2)
|
||||
|
||||
[ð](#lib:get_return_object,task::promise_type)
|
||||
|
||||
`task get_return_object() noexcept;
|
||||
`
|
||||
|
||||
[5](#task.promise-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7509)
|
||||
|
||||
*Returns*: A task object whose member *handle* iscoroutine_handle<promise_type>::from_promise(*this)[.](#task.promise-5.sentence-1)
|
||||
|
||||
[ð](#lib:initial_suspend,task::promise_type)
|
||||
|
||||
`auto initial_suspend() noexcept;
|
||||
`
|
||||
|
||||
[6](#task.promise-6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7520)
|
||||
|
||||
*Returns*: An awaitable object of unspecified type ([[expr.await]](expr.await "7.6.2.4 Await")) whose
|
||||
member functions arrange for
|
||||
|
||||
- [(6.1)](#task.promise-6.1)
|
||||
|
||||
the calling coroutine to be suspended,
|
||||
|
||||
- [(6.2)](#task.promise-6.2)
|
||||
|
||||
the coroutine to be resumed on an execution agent of the
|
||||
execution resource associated with *SCHED*(*this)[.](#task.promise-6.sentence-1)
|
||||
|
||||
[ð](#lib:final_suspend,task::promise_type)
|
||||
|
||||
`auto final_suspend() noexcept;
|
||||
`
|
||||
|
||||
[7](#task.promise-7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7536)
|
||||
|
||||
*Returns*: An awaitable object of unspecified type ([[expr.await]](expr.await "7.6.2.4 Await")) whose
|
||||
member functions arrange for the completion of the asynchronous
|
||||
operation associated with *STATE*(*this) by invoking:
|
||||
|
||||
- [(7.1)](#task.promise-7.1)
|
||||
|
||||
set_error(std::move(*RCVR*(*this)), std::move(e)) if *errors*.index() is greater than zero ande is the value held by *errors*, otherwise
|
||||
|
||||
- [(7.2)](#task.promise-7.2)
|
||||
|
||||
set_value(std::move(*RCVR*(*this))) if is_void<T> is true,
|
||||
and otherwise
|
||||
|
||||
- [(7.3)](#task.promise-7.3)
|
||||
|
||||
set_value(std::move(*RCVR*(*this)), **result*)[.](#task.promise-7.sentence-1)
|
||||
|
||||
[ð](#lib:yield_value,task::promise_type)
|
||||
|
||||
`template<class Err>
|
||||
auto yield_value(with_error<Err> err);
|
||||
`
|
||||
|
||||
[8](#task.promise-8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7560)
|
||||
|
||||
*Mandates*: std::move(err.error) is convertible to exactly one of theset_error_t argument types of error_types[.](#task.promise-8.sentence-1)
|
||||
|
||||
Let *Cerr* be that type[.](#task.promise-8.sentence-2)
|
||||
|
||||
[9](#task.promise-9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7566)
|
||||
|
||||
*Returns*: An awaitable object of unspecified type ([[expr.await]](expr.await "7.6.2.4 Await")) whose
|
||||
member functions arrange for the calling coroutine to be suspended
|
||||
and then completes the asynchronous operation associated with*STATE*(*this) by invoking set_error(std::move(*RCVR*(*this)),*Cerr*(std::move(err.error)))[.](#task.promise-9.sentence-1)
|
||||
|
||||
[ð](#lib:await_transform,task::promise_type)
|
||||
|
||||
`template<[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") Sender>
|
||||
auto await_transform(Sender&& sndr) noexcept;
|
||||
`
|
||||
|
||||
[10](#task.promise-10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7581)
|
||||
|
||||
*Returns*: If [same_as](concept.same#concept:same_as "18.4.2 Concept same_as [concept.same]")<inline_scheduler, scheduler_type> is true returns as_awaitable(std::forward<Sender>(sndr), *this);
|
||||
otherwise returnsas_awaitable(affine_on(std::forward<Sender>(sndr), *SCHED*(*this)), *this)[.](#task.promise-10.sentence-1)
|
||||
|
||||
[ð](#lib:await_transform,task::promise_type_)
|
||||
|
||||
`template<class Sch>
|
||||
auto await_transform(change_coroutine_scheduler<Sch> sch) noexcept;
|
||||
`
|
||||
|
||||
[11](#task.promise-11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7595)
|
||||
|
||||
*Effects*: Equivalent to:return await_transform(just(exchange(*SCHED*(*this), scheduler_type(sch.scheduler))), *this);
|
||||
|
||||
[ð](#lib:uncaught_exception,task::promise_type)
|
||||
|
||||
`void uncaught_exception();
|
||||
`
|
||||
|
||||
[12](#task.promise-12)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7608)
|
||||
|
||||
*Effects*: If the signature set_error_t(exception_ptr) is not an element
|
||||
of error_types, calls terminate() ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#task.promise-12.sentence-1)
|
||||
|
||||
Otherwise, stores current_exception() into *errors*[.](#task.promise-12.sentence-2)
|
||||
|
||||
[ð](#lib:unhandled_stopped,task::promise_type)
|
||||
|
||||
`coroutine_handle<> unhandled_stopped();
|
||||
`
|
||||
|
||||
[13](#task.promise-13)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7620)
|
||||
|
||||
*Effects*: Completes the asynchronous operation associated with *STATE*(*this) by invoking set_stopped(std::move(*RCVR*(*this)))[.](#task.promise-13.sentence-1)
|
||||
|
||||
[14](#task.promise-14)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7626)
|
||||
|
||||
*Returns*: noop_coroutine()[.](#task.promise-14.sentence-1)
|
||||
|
||||
[ð](#lib:get_env,task::promise_type)
|
||||
|
||||
`unspecified get_env() const noexcept;
|
||||
`
|
||||
|
||||
[15](#task.promise-15)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7636)
|
||||
|
||||
*Returns*: An object env such that queries are forwarded as follows:
|
||||
|
||||
- [(15.1)](#task.promise-15.1)
|
||||
|
||||
env.query(get_scheduler) returns scheduler_type(*SCHED*(*this))[.](#task.promise-15.1.sentence-1)
|
||||
|
||||
- [(15.2)](#task.promise-15.2)
|
||||
|
||||
env.query(get_allocator) returns *alloc*[.](#task.promise-15.2.sentence-1)
|
||||
|
||||
- [(15.3)](#task.promise-15.3)
|
||||
|
||||
env.query(get_stop_token) returns *token*[.](#task.promise-15.3.sentence-1)
|
||||
|
||||
- [(15.4)](#task.promise-15.4)
|
||||
|
||||
For any other query q and arguments a... a
|
||||
call to env.query(q, a...) returns*STATE*(*this)[.](#task.promise-15.4.sentence-1)
|
||||
environment.query(q, a...) if this expression
|
||||
is well-formed and forwarding_query(q) is well-formed and is true[.](#task.promise-15.4.sentence-2)
|
||||
Otherwise env.query(q, a...) is ill-formed[.](#task.promise-15.4.sentence-3)
|
||||
|
||||
[ð](#lib:operator_new,task::promise_type)
|
||||
|
||||
`template<class... Args>
|
||||
void* operator new(size_t size, const Args&... args);
|
||||
`
|
||||
|
||||
[16](#task.promise-16)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7657)
|
||||
|
||||
If there is no parameter with type allocator_arg_t then letalloc be allocator_type()[.](#task.promise-16.sentence-1)
|
||||
|
||||
Otherwise, let arg_next be the parameter
|
||||
following the first allocator_arg_t parameter,
|
||||
and let alloc be allocator_type(arg_next)[.](#task.promise-16.sentence-2)
|
||||
|
||||
Let PAlloc be allocator_traits<allocator_type>::template rebind_alloc<U>, where U is an unspecified type
|
||||
whose size and alignment are both __STDCPP_DEFAULT_NEW_ALIGNMENT__[.](#task.promise-16.sentence-3)
|
||||
|
||||
[17](#task.promise-17)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7667)
|
||||
|
||||
*Mandates*:
|
||||
|
||||
- [(17.1)](#task.promise-17.1)
|
||||
|
||||
The first parameter of type allocator_arg_t (if any) is not the last parameter[.](#task.promise-17.1.sentence-1)
|
||||
|
||||
- [(17.2)](#task.promise-17.2)
|
||||
|
||||
allocator_type(arg_next) is a valid expression if there is a parameter
|
||||
of type allocator_arg_t[.](#task.promise-17.2.sentence-1)
|
||||
|
||||
- [(17.3)](#task.promise-17.3)
|
||||
|
||||
allocator_traits<PAlloc>::pointer is a pointer type[.](#task.promise-17.3.sentence-1)
|
||||
|
||||
[18](#task.promise-18)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7676)
|
||||
|
||||
*Effects*: Initializes an allocator palloc of type PAlloc withalloc[.](#task.promise-18.sentence-1)
|
||||
|
||||
Uses palloc to allocate storage for the
|
||||
smallest array of U sufficient to provide storage for a
|
||||
coroutine state of size size, and unspecified additional
|
||||
state necessary to ensure that operator delete can later
|
||||
deallocate this memory block with an allocator equal to palloc[.](#task.promise-18.sentence-2)
|
||||
|
||||
[19](#task.promise-19)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7686)
|
||||
|
||||
*Returns*: A pointer to the allocated storage[.](#task.promise-19.sentence-1)
|
||||
|
||||
[ð](#lib:operator_delete,task::promise_type)
|
||||
|
||||
`void operator delete(void* pointer, size_t size) noexcept;
|
||||
`
|
||||
|
||||
[20](#task.promise-20)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7696)
|
||||
|
||||
*Preconditions*: pointer was returned from an invocation of the above overload
|
||||
of operator new with a size argument equal to size[.](#task.promise-20.sentence-1)
|
||||
|
||||
[21](#task.promise-21)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7701)
|
||||
|
||||
*Effects*: Deallocates the storage pointed to by pointer using an
|
||||
allocator equal to that used to allocate it[.](#task.promise-21.sentence-1)
|
||||
138
cppdraft/exec/task/scheduler.md
Normal file
138
cppdraft/exec/task/scheduler.md
Normal file
@@ -0,0 +1,138 @@
|
||||
[exec.task.scheduler]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.13 Coroutine utilities [[exec.coro.util]](exec.coro.util#exec.task.scheduler)
|
||||
|
||||
### 33.13.5 execution::task_scheduler [exec.task.scheduler]
|
||||
|
||||
namespace std::execution {class [task_scheduler](#lib:task_scheduler "33.13.5 execution::task_scheduler [exec.task.scheduler]") {class *ts-sender*; // *exposition only*template<[receiver](exec.recv.concepts#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]") R>class *state*; // *exposition only*public:using scheduler_concept = scheduler_t; template<class Sch, class Allocator = allocator<void>>requires (<task_scheduler, remove_cvref_t<Sch>>)&& [scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]")<Sch>explicit task_scheduler(Sch&& sch, Allocator alloc = {}); *ts-sender* schedule(); friend bool operator==(const task_scheduler& lhs, const task_scheduler& rhs)noexcept; template<class Sch>requires (<task_scheduler, Sch>)&& [scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]")<Sch>friend bool operator==(const task_scheduler& lhs, const Sch& rhs) noexcept; private: shared_ptr<void> *sch_*; // *exposition only*};}
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7028)
|
||||
|
||||
task_scheduler is a class that models[scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]") ([[exec.sched]](exec.sched "33.6 Schedulers"))[.](#1.sentence-1)
|
||||
|
||||
Given an object s of type task_scheduler, let*SCHED*(s) be the object owned by s.*sch_*[.](#1.sentence-2)
|
||||
|
||||
[ð](#lib:task_scheduler,constructor)
|
||||
|
||||
`template<class Sch, class Allocator = allocator<void>>
|
||||
requires(<task_scheduler, remove_cvref_t<Sch>>) && [scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]")<Sch>
|
||||
explicit task_scheduler(Sch&& sch, Allocator alloc = {});
|
||||
`
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7041)
|
||||
|
||||
*Effects*: Initialize *sch_* withallocate_shared<remove_cvref_t<Sch>>(alloc, std::forward<Sch>(sch))[.](#2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7046)
|
||||
|
||||
*Recommended practice*: Implementations should avoid the use of dynamically
|
||||
allocated memory for small scheduler objects[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7051)
|
||||
|
||||
*Remarks*: Any allocations performed by construction of *ts-sender* or*state* objects resulting from calls on *this are
|
||||
performed using a copy of alloc[.](#4.sentence-1)
|
||||
|
||||
[ð](#lib:scheduler,task_scheduler)
|
||||
|
||||
`ts-sender schedule();
|
||||
`
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7063)
|
||||
|
||||
*Effects*: Returns an object of type *ts-sender* containing a sender
|
||||
initialized with schedule(*SCHED*(*this))[.](#5.sentence-1)
|
||||
|
||||
[ð](#lib:operator==,task_scheduler)
|
||||
|
||||
`bool operator==(const task_scheduler& lhs, const task_scheduler& rhs) noexcept;
|
||||
`
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7074)
|
||||
|
||||
*Effects*: Equivalent to: return lhs == *SCHED*(rhs);
|
||||
|
||||
[ð](#lib:operator==,task_scheduler_)
|
||||
|
||||
`template<class Sch>
|
||||
requires (<task_scheduler, Sch>)
|
||||
&& [scheduler](exec.sched#concept:scheduler "33.6 Schedulers [exec.sched]")<Sch>
|
||||
bool operator==(const task_scheduler& lhs, const Sch& rhs) noexcept;
|
||||
`
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7087)
|
||||
|
||||
*Returns*: false if the type of *SCHED*(lhs) is not Sch,
|
||||
otherwise *SCHED*(lhs) == rhs[.](#7.sentence-1)
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7093)
|
||||
|
||||
namespace std::execution {class task_scheduler::*ts-sender* { // *exposition only*public:using sender_concept = sender_t; template<[receiver](exec.recv.concepts#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]") Rcvr>*state*<Rcvr> connect(Rcvr&& rcvr); };}*ts-sender* is an exposition-only class that models[sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") ([[exec.snd]](exec.snd "33.9 Senders")) and for whichcompletion_signatures_of_t<*ts-sender*> denotes:completion_signatures< set_value_t(),
|
||||
set_error_t(error_code),
|
||||
set_error_t(exception_ptr),
|
||||
set_stopped_t()>
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7116)
|
||||
|
||||
Let *sch* be an object of type task_scheduler and let sndr be an object of type *ts-sender* obtained
|
||||
from schedule(*sch*)[.](#9.sentence-1)
|
||||
|
||||
Then get_completion_scheduler<set_value_t>(get_env(sndr)) == *sch* is true[.](#9.sentence-2)
|
||||
|
||||
The object *SENDER*(sndr) is the sender object contained bysndr or an object move constructed from it[.](#9.sentence-3)
|
||||
|
||||
[ð](#lib:connect,task_scheduler::ts-sender)
|
||||
|
||||
`template<[receiver](exec.recv.concepts#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]") Rcvr>
|
||||
state<Rcvr> connect(Rcvr&& rcvr);
|
||||
`
|
||||
|
||||
[10](#10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7131)
|
||||
|
||||
*Effects*: Let *r* be an object of a type that models [receiver](exec.recv.concepts#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]") and whose completion handlers result in invoking the corresponding
|
||||
completion handlers of rcvr or copy thereof[.](#10.sentence-1)
|
||||
|
||||
Returns an object of type *state*<Rcvr> containing
|
||||
an operation state object initialized with connect(*SENDER*(*this),
|
||||
std::move(*r*))[.](#10.sentence-2)
|
||||
|
||||
[11](#11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7141)
|
||||
|
||||
namespace std::execution {template<[receiver](exec.recv.concepts#concept:receiver "33.7.1 Receiver concepts [exec.recv.concepts]") R>class task_scheduler::*state* { // *exposition only*public:using operation_state_concept = operation_state_t; void start() & noexcept; };}*state* is an exposition-only class template whose
|
||||
specializations model [operation_state](exec.opstate.general#concept:operation_state "33.8.1 General [exec.opstate.general]") ([[exec.opstate]](exec.opstate "33.8 Operation states"))[.](#11.sentence-1)
|
||||
|
||||
[ð](#lib:start,task_scheduler::state)
|
||||
|
||||
`void start() & noexcept;
|
||||
`
|
||||
|
||||
[12](#12)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L7161)
|
||||
|
||||
*Effects*: Equivalent to start(st) where st is the operation
|
||||
state object contained by *this[.](#12.sentence-1)
|
||||
84
cppdraft/exec/then.md
Normal file
84
cppdraft/exec/then.md
Normal file
@@ -0,0 +1,84 @@
|
||||
[exec.then]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#exec.then)
|
||||
|
||||
### 33.9.12 Sender adaptors [[exec.adapt]](exec.adapt#exec.then)
|
||||
|
||||
#### 33.9.12.9 execution::then, execution::upon_error, execution::upon_stopped [exec.then]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3757)
|
||||
|
||||
then attaches an invocable as a continuation
|
||||
for an input sender's value completion operation[.](#1.sentence-1)
|
||||
|
||||
upon_error and upon_stopped do the same
|
||||
for the error and stopped completion operations, respectively,
|
||||
sending the result of the invocable as a value completion[.](#1.sentence-2)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3764)
|
||||
|
||||
The names then, upon_error, and upon_stopped denote pipeable sender adaptor objects[.](#2.sentence-1)
|
||||
|
||||
Let the expression *then-cpo* be one ofthen, upon_error, or upon_stopped[.](#2.sentence-2)
|
||||
|
||||
For subexpressions sndr and f,
|
||||
if decltype((sndr)) does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]"), ordecltype((f)) does not satisfy [*movable-value*](exec.general#concept:movable-value "33.1 General [exec.general]"),*then-cpo*(sndr, f) is ill-formed[.](#2.sentence-3)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3774)
|
||||
|
||||
Otherwise,
|
||||
the expression *then-cpo*(sndr, f) is expression-equivalent to:transform_sender(*get-domain-early*(sndr), *make-sender*(*then-cpo*, f, sndr)) except that sndr is evaluated only once[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3782)
|
||||
|
||||
For then, upon_error, and upon_stopped,
|
||||
let *set-cpo* beset_value, set_error, and set_stopped, respectively[.](#4.sentence-1)
|
||||
|
||||
The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
|
||||
is specialized for *then-cpo* as follows:
|
||||
|
||||
[ð](#lib:impls-for%3cdecayed-typeof%3cthen-cpo%3e%3e)
|
||||
|
||||
namespace std::execution {template<>struct *impls-for*<*decayed-typeof*<*then-cpo*>> : *default-impls* {static constexpr auto *complete* =[]<class Tag, class... Args>(auto, auto& fn, auto& rcvr, Tag, Args&&... args) noexcept -> void {if constexpr ([same_as](concept.same#concept:same_as "18.4.2 Concept same_as [concept.same]")<Tag, *decayed-typeof*<set-cpo>>) {*TRY-SET-VALUE*(rcvr,
|
||||
invoke(std::move(fn), std::forward<Args>(args)...)); } else { Tag()(std::move(rcvr), std::forward<Args>(args)...); }}; template<class Sndr, class... Env>static consteval void *check-types*(); };}
|
||||
|
||||
[ð](#lib:check-types,impls-for%3cdecayed-typeof%3cthen-cpo%3e%3e)
|
||||
|
||||
`template<class Sndr, class... Env>
|
||||
static consteval void check-types();
|
||||
`
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3817)
|
||||
|
||||
*Effects*: Equivalent to:auto cs = get_completion_signatures<*child-type*<Sndr>, *FWD-ENV-T*(Env)...>();auto fn = []<class... Ts>(set_value_t(*)(Ts...)) {if constexpr (<remove_cvref_t<*data-type*<Sndr>>, Ts...>)throw *unspecified-exception*();};
|
||||
cs.*for-each*(*overload-set*{fn, [](auto){}}); where *unspecified-exception* is
|
||||
a type derived from exception[.](#5.sentence-1)
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3832)
|
||||
|
||||
The expression *then-cpo*(sndr, f) has undefined behavior
|
||||
unless it returns a sender out_sndr that
|
||||
|
||||
- [(6.1)](#6.1)
|
||||
|
||||
invokes f or a copy of such
|
||||
with the value, error, or stopped result datums of sndr for then, upon_error, and upon_stopped, respectively,
|
||||
using the result value of f as out_sndr's value completion, and
|
||||
|
||||
- [(6.2)](#6.2)
|
||||
|
||||
forwards all other completion operations unchanged[.](#6.sentence-1)
|
||||
24
cppdraft/exec/unstoppable.md
Normal file
24
cppdraft/exec/unstoppable.md
Normal file
@@ -0,0 +1,24 @@
|
||||
[exec.unstoppable]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#exec.unstoppable)
|
||||
|
||||
### 33.9.12 Sender adaptors [[exec.adapt]](exec.adapt#exec.unstoppable)
|
||||
|
||||
#### 33.9.12.4 execution::unstoppable [exec.unstoppable]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3210)
|
||||
|
||||
unstoppable is a sender adaptor
|
||||
that connects its inner sender
|
||||
with a receiver that has the execution environment of the outer receiver
|
||||
but with an object of type never_stop_token as the result of the get_stop_token query[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3217)
|
||||
|
||||
For a subexpression sndr,unstoppable(sndr) is expression-equivalent towrite_env(sndr, prop(get_stop_token, never_stop_token{}))[.](#2.sentence-1)
|
||||
241
cppdraft/exec/when/all.md
Normal file
241
cppdraft/exec/when/all.md
Normal file
@@ -0,0 +1,241 @@
|
||||
[exec.when.all]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#exec.when.all)
|
||||
|
||||
### 33.9.12 Sender adaptors [[exec.adapt]](exec.adapt#exec.when.all)
|
||||
|
||||
#### 33.9.12.12 execution::when_all [exec.when.all]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4368)
|
||||
|
||||
when_all and when_all_with_variant both adapt multiple input senders into a sender
|
||||
that completes when all input senders have completed[.](#1.sentence-1)
|
||||
|
||||
when_all only accepts senders
|
||||
with a single value completion signature and
|
||||
on success concatenates all the input senders' value result datums
|
||||
into its own value completion operation[.](#1.sentence-2)
|
||||
|
||||
when_all_with_variant(sndrs...) is semantically equivalent to
|
||||
when_all(into_variant(sndrs)...),
|
||||
where sndrs is a pack of subexpressions
|
||||
whose types model [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]")[.](#1.sentence-3)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4381)
|
||||
|
||||
The names when_all and when_all_with_variant denote
|
||||
customization point objects[.](#2.sentence-1)
|
||||
|
||||
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<decltype(*get-domain-early*(sndrs))...>[.](#2.sentence-2)
|
||||
|
||||
Let CD2 be CD if CD is well-formed, anddefault_domain otherwise[.](#2.sentence-3)
|
||||
|
||||
The expressions when_all(sndrs...) andwhen_all_with_variant(sndrs...) are ill-formed
|
||||
if any of the following is true:
|
||||
|
||||
- [(2.1)](#2.1)
|
||||
|
||||
sizeof...(sndrs) is 0, or
|
||||
|
||||
- [(2.2)](#2.2)
|
||||
|
||||
([sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]")<Sndrs> && ...) is false[.](#2.sentence-4)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4400)
|
||||
|
||||
The expression when_all(sndrs...) is expression-equivalent to:transform_sender(CD2(), *make-sender*(when_all, {}, sndrs...))
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4406)
|
||||
|
||||
The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
|
||||
is specialized for when_all_t as follows:
|
||||
|
||||
[ð](#lib:impls-for%3cwhen_all_t%3e)
|
||||
|
||||
namespace std::execution {template<>struct *impls-for*<when_all_t> : *default-impls* {static constexpr auto *get-attrs* = *see below*; static constexpr auto *get-env* = *see below*; static constexpr auto *get-state* = *see below*; static constexpr auto *start* = *see below*; static constexpr auto *complete* = *see below*; template<class Sndr, class... Env>static consteval void *check-types*(); };}
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4426)
|
||||
|
||||
Let *make-when-all-env* be
|
||||
the following exposition-only function template:template<class Env>constexpr auto *make-when-all-env*(inplace_stop_source& stop_src, // *exposition only* Env&& env) noexcept {return *see below*;}
|
||||
|
||||
Returns an object e such that
|
||||
|
||||
- [(5.1)](#5.1)
|
||||
|
||||
decltype(e) models [*queryable*](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]"), and
|
||||
|
||||
- [(5.2)](#5.2)
|
||||
|
||||
e.query(get_stop_token) is expression-equivalent tostate.*stop-src*.get_token(), and
|
||||
|
||||
- [(5.3)](#5.3)
|
||||
|
||||
given a query object q with type other than cv stop_token_t and
|
||||
whose type satisfies *forwarding-query*,e.query(q) is expression-equivalent to get_env(rcvr).query(q)[.](#5.sentence-2)
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4452)
|
||||
|
||||
Let *when-all-env* be an alias template such that*when-all-env*<Env> denotes the typedecltype(*make-
|
||||
when-all-env*(declval<inplace_stop_source&>(), declval<Env>()))[.](#6.sentence-1)
|
||||
|
||||
[ð](#lib:check-types,impls-for%3cwhen_all_t%3e)
|
||||
|
||||
`template<class Sndr, class... Env>
|
||||
static consteval void check-types();
|
||||
`
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4464)
|
||||
|
||||
Let Is be the pack of integral template arguments of
|
||||
the integer_sequence specialization denoted by*indices-for*<Sndr>[.](#7.sentence-1)
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4469)
|
||||
|
||||
*Effects*: Equivalent to:auto fn = []<class Child>() {auto cs = get_completion_signatures<Child, *when-all-env*<Env>...>(); if constexpr (cs.*count-of*(set_value) >= 2)throw *unspecified-exception*(); *decay-copyable-result-datums*(cs); // see [[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities")};(fn.template operator()<*child-type*<Sndr, Is>>(), ...); where *unspecified-exception* is
|
||||
a type derived from exception[.](#8.sentence-1)
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4484)
|
||||
|
||||
*Throws*: Any exception thrown as a result of evaluating the *Effects*, or
|
||||
an exception of an unspecified type
|
||||
derived from exception when CD is ill-formed[.](#9.sentence-1)
|
||||
|
||||
[10](#10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4491)
|
||||
|
||||
The member *impls-for*<when_all_t>::*get-attrs* is initialized with a callable object
|
||||
equivalent to the following lambda expression:[](auto&&, auto&&... child) noexcept {if constexpr ([same_as](concept.same#concept:same_as "18.4.2 Concept same_as [concept.same]")<CD, default_domain>) {return env<>(); } else {return *MAKE-ENV*(get_domain, CD()); }}
|
||||
|
||||
[11](#11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4505)
|
||||
|
||||
The member *impls-for*<when_all_t>::*get-env* is initialized with a callable object
|
||||
equivalent to the following lambda expression:[]<class State, class Rcvr>(auto&&, State& state, const Receiver& rcvr) noexcept {return *make-when-all-env*(state.*stop-src*, get_env(rcvr));}
|
||||
|
||||
[12](#12)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4515)
|
||||
|
||||
The member *impls-for*<when_all_t>::*get-state* is initialized with a callable object
|
||||
equivalent to the following lambda expression:[]<class Sndr, class Rcvr>(Sndr&& sndr, Rcvr& rcvr) noexcept(noexcept(e)) -> decltype(e) {return e;} where e is the expressionstd::forward<Sndr>(sndr).*apply*(*make-state*<Rcvr>()) and where *make-state* is the following exposition-only class template:enum class *disposition* { *started*, *error*, *stopped* }; // *exposition only*template<class Rcvr>struct *make-state* {template<class... Sndrs>auto operator()(auto, auto, Sndrs&&... sndrs) const {using values_tuple = *see below*; using errors_variant = *see below*; using stop_callback = stop_callback_for_t<stop_token_of_t<env_of_t<Rcvr>>, *on-stop-request*>; struct *state-type* {void *arrive*(Rcvr& rcvr) noexcept { // *exposition only*if (0 == --count) {*complete*(rcvr); }}void *complete*(Rcvr& rcvr) noexcept; // *exposition only* atomic<size_t> *count*{sizeof...(sndrs)}; // *exposition only* inplace_stop_source *stop_src*{}; // *exposition only* atomic<*disposition*> disp{*disposition*::*started*}; // *exposition only* errors_variant *errors*{}; // *exposition only* values_tuple *values*{}; // *exposition only* optional<stop_callback> *on_stop*{nullopt}; // *exposition only*}; return *state-type*{}; }};
|
||||
|
||||
[13](#13)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4562)
|
||||
|
||||
Let *copy-fail* be exception_ptr if decay-copying any of the child senders' result datums can potentially throw;
|
||||
otherwise, *none-such*,
|
||||
where *none-such* is an unspecified empty class type[.](#13.sentence-1)
|
||||
|
||||
[14](#14)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4568)
|
||||
|
||||
The alias values_tuple denotes the typetuple<value_types_of_t<Sndrs, *FWD-ENV-T*(env_of_t<Rcvr>), *decayed-tuple*, optional>...> if that type is well-formed; otherwise, tuple<>[.](#14.sentence-1)
|
||||
|
||||
[15](#15)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4575)
|
||||
|
||||
The alias errors_variant denotes
|
||||
the type variant<*none-such*, *copy-fail*, Es...> with duplicate types removed,
|
||||
where Es is the pack of the decayed types
|
||||
of all the child senders' possible error result datums[.](#15.sentence-1)
|
||||
|
||||
[16](#16)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4582)
|
||||
|
||||
The membervoid *state-type*::*complete*(Rcvr& rcvr) noexcept behaves as follows:
|
||||
|
||||
- [(16.1)](#16.1)
|
||||
|
||||
If disp is equal to *disposition*::*started*,
|
||||
evaluates:auto tie = []<class... T>(tuple<T...>& t) noexcept { return tuple<T&...>(t); };auto set = [&](auto&... t) noexcept { set_value(std::move(rcvr), std::move(t)...); };
|
||||
|
||||
*on_stop*.reset();
|
||||
apply([&](auto&... opts) noexcept { apply(set, tuple_cat(tie(*opts)...)); },
|
||||
values);
|
||||
|
||||
- [(16.2)](#16.2)
|
||||
|
||||
Otherwise,
|
||||
if disp is equal to *disposition*::*error*,
|
||||
evaluates:*on_stop*.reset();
|
||||
visit([&]<class Error>(Error& error) noexcept {if constexpr (<Error, *none-such*>) { set_error(std::move(rcvr), std::move(error)); }},
|
||||
errors);
|
||||
|
||||
- [(16.3)](#16.3)
|
||||
|
||||
Otherwise, evaluates:*on_stop*.reset();
|
||||
set_stopped(std::move(rcvr));
|
||||
|
||||
[17](#17)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4623)
|
||||
|
||||
The member *impls-for*<when_all_t>::*start* is initialized with a callable object
|
||||
equivalent to the following lambda expression:[]<class State, class Rcvr, class... Ops>( State& state, Rcvr& rcvr, Ops&... ops) noexcept -> void { state.*on_stop*.emplace( get_stop_token(get_env(rcvr)), *on-stop-request*{state.*stop_src*}); if (state.*stop_src*.stop_requested()) { state.*on_stop.*reset();
|
||||
set_stopped(std::move(rcvr)); } else {(start(ops), ...); }}
|
||||
|
||||
[18](#18)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4642)
|
||||
|
||||
The member *impls-for<when_all_t>::*complete** is initialized with a callable object
|
||||
equivalent to the following lambda expression:[]<class Index, class State, class Rcvr, class Set, class... Args>(this auto& complete, Index, State& state, Rcvr& rcvr, Set, Args&&... args) noexcept -> void {if constexpr ([same_as](concept.same#concept:same_as "18.4.2 Concept same_as [concept.same]")<Set, set_error_t>) {if (*disposition*::*error* != state.disp.exchange(*disposition*::*error*)) { state.*stop_src*.request_stop(); *TRY-EMPLACE-ERROR*(state.errors, std::forward<Args>(args)...); }} else if constexpr ([same_as](concept.same#concept:same_as "18.4.2 Concept same_as [concept.same]")<Set, set_stopped_t>) {auto expected = *disposition*::*started*; if (state.disp.compare_exchange_strong(expected, *disposition*::*stopped*)) { state.*stop_src*.request_stop(); }} else if constexpr (<decltype(State::values), tuple<>>) {if (state.disp == *disposition*::*started*) {auto& opt = get<Index::value>(state.values); *TRY-EMPLACE-VALUE*(complete, opt, std::forward<Args>(args)...); }} state.*arrive*(rcvr);} where *TRY-EMPLACE-ERROR*(v, e),
|
||||
for subexpressions v and e, is equivalent to:try { v.template emplace<decltype(auto(e))>(e);} catch (...) { v.template emplace<exception_ptr>(current_exception());} if the expression decltype(auto(e))(e) is potentially throwing;
|
||||
otherwise, v.template emplace<decltype(auto(e))>(e);
|
||||
and where *TRY-EMPLACE-VALUE*(c, o, as...),
|
||||
for subexpressions c, o, and pack of subexpressions as,
|
||||
is equivalent to:try { o.emplace(as...);} catch (...) { c(Index(), state, rcvr, set_error, current_exception()); return;} if the expression *decayed-tuple*<decltype(as)...>{as...} is potentially throwing;
|
||||
otherwise, o.emplace(as...)[.](#18.sentence-1)
|
||||
|
||||
[19](#19)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4694)
|
||||
|
||||
The expression when_all_with_variant(sndrs...) is expression-equivalent to:transform_sender(CD2(), *make-sender*(when_all_with_variant, {}, sndrs...));
|
||||
|
||||
[20](#20)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4701)
|
||||
|
||||
Given subexpressions sndr and env,
|
||||
if[*sender-for*](exec.snd.concepts#concept:sender-for "33.9.3 Sender concepts [exec.snd.concepts]")<decltype((sndr)), when_all_with_variant_t> is false,
|
||||
then the expression when_all_with_variant.transform_sender(sndr, env) is ill-formed;
|
||||
otherwise, it is equivalent to:auto&& [_, _, ...child] = sndr;return when_all(into_variant(std::forward_like<decltype((sndr))>(child))...);
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
This causes the when_all_with_variant(sndrs...) sender
|
||||
to become when_all(into_variant(sndrs)...) when it is connected with a receiver
|
||||
whose execution domain does not customize when_all_with_variant[.](#20.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
55
cppdraft/exec/with/awaitable/senders.md
Normal file
55
cppdraft/exec/with/awaitable/senders.md
Normal file
@@ -0,0 +1,55 @@
|
||||
[exec.with.awaitable.senders]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.13 Coroutine utilities [[exec.coro.util]](exec.coro.util#exec.with.awaitable.senders)
|
||||
|
||||
### 33.13.2 execution::with_awaitable_senders [exec.with.awaitable.senders]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6793)
|
||||
|
||||
with_awaitable_senders,
|
||||
when used as the base class of a coroutine promise type,
|
||||
makes senders awaitable in that coroutine type[.](#1.sentence-1)
|
||||
|
||||
In addition, it provides a default implementation of unhandled_stopped such that if a sender completes by calling set_stopped,
|
||||
it is treated as if an uncatchable "stopped" exception were thrown
|
||||
from the [*await-expression*](expr.await#nt:await-expression "7.6.2.4 Await [expr.await]")[.](#1.sentence-2)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
The coroutine is never resumed, and
|
||||
the unhandled_stopped of the coroutine caller's promise type is called[.](#1.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
namespace std::execution {template<[*class-type*](execution.syn#concept:class-type "33.4 Header <execution> synopsis [execution.syn]") Promise>struct [with_awaitable_senders](#lib:with_awaitable_senders "33.13.2 execution::with_awaitable_senders [exec.with.awaitable.senders]") {template<class OtherPromise>requires (<OtherPromise, void>)void set_continuation(coroutine_handle<OtherPromise> h) noexcept;
|
||||
|
||||
coroutine_handle<> [continuation](#lib:with_awaitable_senders,continuation "33.13.2 execution::with_awaitable_senders [exec.with.awaitable.senders]")() const noexcept { return *continuation*; } coroutine_handle<> [unhandled_stopped](#lib:with_awaitable_senders,unhandled_stopped "33.13.2 execution::with_awaitable_senders [exec.with.awaitable.senders]")() noexcept {return *stopped-handler*(*continuation*.address()); }template<class Value>*see below* await_transform(Value&& value); private:[[noreturn]] static coroutine_handle<>*default-unhandled-stopped*(void*) noexcept { // *exposition only* terminate(); } coroutine_handle<> *continuation*{}; // *exposition only* coroutine_handle<> (**stopped-handler*)(void*) noexcept = // *exposition only*&*default-unhandled-stopped*; };}
|
||||
|
||||
[ð](#lib:set_continuation,with_awaitable_senders)
|
||||
|
||||
`template<class OtherPromise>
|
||||
requires (<OtherPromise, void>)
|
||||
void set_continuation(coroutine_handle<OtherPromise> h) noexcept;
|
||||
`
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6844)
|
||||
|
||||
*Effects*: Equivalent to:*continuation* = h;if constexpr ( requires(OtherPromise& other) { other.unhandled_stopped(); } ) {*stopped-handler* = [](void* p) noexcept -> coroutine_handle<> {return coroutine_handle<OtherPromise>::from_address(p).promise().unhandled_stopped(); };} else {*stopped-handler* = &*default-unhandled-stopped*;}
|
||||
|
||||
[ð](#lib:await_transform,with_awaitable_senders)
|
||||
|
||||
`template<class Value>
|
||||
call-result-t<as_awaitable_t, Value, Promise&> await_transform(Value&& value);
|
||||
`
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L6867)
|
||||
|
||||
*Effects*: Equivalent to:return as_awaitable(std::forward<Value>(value), static_cast<Promise&>(*this));
|
||||
77
cppdraft/exec/write/env.md
Normal file
77
cppdraft/exec/write/env.md
Normal file
@@ -0,0 +1,77 @@
|
||||
[exec.write.env]
|
||||
|
||||
# 33 Execution control library [[exec]](./#exec)
|
||||
|
||||
## 33.9 Senders [[exec.snd]](exec.snd#exec.write.env)
|
||||
|
||||
### 33.9.12 Sender adaptors [[exec.adapt]](exec.adapt#exec.write.env)
|
||||
|
||||
#### 33.9.12.3 execution::write_env [exec.write.env]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3143)
|
||||
|
||||
write_env is a sender adaptor
|
||||
that accepts a sender and a queryable object, and
|
||||
that returns a sender that,
|
||||
when connected with a receiver rcvr,
|
||||
connects the adapted sender with a receiver
|
||||
whose execution environment is the result of
|
||||
joining the [*queryable*](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]") object
|
||||
to the result of get_env(rcvr)[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3153)
|
||||
|
||||
write_env is a customization point object[.](#2.sentence-1)
|
||||
|
||||
For some subexpressions sndr and env,
|
||||
if decltype((sndr)) does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3 Sender concepts [exec.snd.concepts]") or
|
||||
if decltype((env)) does not satisfy [*queryable*](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]"),
|
||||
the expression write_env(sndr, env) is ill-formed[.](#2.sentence-2)
|
||||
|
||||
Otherwise, it is expression-equivalent to*make-sender*(write_env, env, sndr)[.](#2.sentence-3)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3162)
|
||||
|
||||
Let *write-env-t* denote the type decltype(auto(write_env))[.](#3.sentence-1)
|
||||
|
||||
The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2 Exposition-only entities"))
|
||||
is specialized for *write-env-t* as follows:
|
||||
|
||||
[ð](#lib:impls-for%3cwrite-env-t%3e)
|
||||
|
||||
template<>struct *impls-for*<*write-env-t*> : *default-impls* {static constexpr auto *join-env*(const auto& state, const auto& env) noexcept {return *see below*; }static constexpr auto *get-env* =[](auto, const auto& state, const auto& rcvr) noexcept {return *join-env*(state, *FWD-ENV*(get_env(rcvr))); }; template<class Sndr, class... Env>static consteval void *check-types*();};
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3184)
|
||||
|
||||
Invocation of*impls-for*<*write-env-t*>::*join-env* returns an object e such that
|
||||
|
||||
- [(4.1)](#4.1)
|
||||
|
||||
decltype(e) models [*queryable*](exec.queryable.concept#concept:queryable "33.2.2 queryable concept [exec.queryable.concept]") and
|
||||
|
||||
- [(4.2)](#4.2)
|
||||
|
||||
given a query object q,
|
||||
the expression e.query(q) is expression-equivalent
|
||||
to state.query(q) if that expression is valid,
|
||||
otherwise, e.query(q) is expression-equivalent
|
||||
to env.query(q)[.](#4.sentence-1)
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L3199)
|
||||
|
||||
For a type Sndr and a pack of types Env,
|
||||
let State be *data-type*<Sndr> and
|
||||
let JoinEnv be the packdecltype(*join-env*(declval<State>(), *FWD-ENV*(declval<Env>())))[.](#5.sentence-1)
|
||||
|
||||
Then *impls-for*<*write-env-t*>::*check-types*<Sndr, Env...>() is expression-equivalent toget_completion_signatures<*child-
|
||||
type*<Sndr>, JoinEnv...>()[.](#5.sentence-2)
|
||||
Reference in New Issue
Block a user