Skip to content

Commit 05d84e5

Browse files
authored
Merge pull request #237 from cplusplus/LWG-feedback-2024-05-22
feedback from the 2024-05-22 LWG telecon
2 parents be36fbf + 49b0b74 commit 05d84e5

File tree

1 file changed

+154
-65
lines changed

1 file changed

+154
-65
lines changed

execution.bs

Lines changed: 154 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1497,6 +1497,22 @@ concurrency, including:
14971497

14981498
# Revision history # {#revisions}
14991499

1500+
## R10 ## {#r10}
1501+
1502+
The changes since R9 are as follows:
1503+
1504+
<b>Fixes:</b>
1505+
1506+
1507+
<b>Enhancements:</b>
1508+
1509+
* The `get_delegatee_scheduler` query has been renamed to
1510+
`get_delegation_scheduler`.
1511+
1512+
* An exposition-only <i>`simple-allocator`</i> concept is added to the
1513+
Library introduction ([library]), and the specification of the
1514+
`get_allocator` query is expressed in terms of it.
1515+
15001516
## R9 ## {#r9}
15011517

15021518
The changes since R8 are as follows:
@@ -3185,8 +3201,8 @@ execution::sender auto read(auto tag);
31853201
execution::sender auto get_scheduler() {
31863202
return read(execution::get_scheduler);
31873203
}
3188-
execution::sender auto get_delegatee_scheduler() {
3189-
return read(execution::get_delegatee_scheduler);
3204+
execution::sender auto get_delegation_scheduler() {
3205+
return read(execution::get_delegation_scheduler);
31903206
}
31913207
execution::sender auto get_allocator() {
31923208
return read(execution::get_allocator);
@@ -4020,6 +4036,72 @@ a new bullet as follows:</span>
40204036
</div>
40214037
</div>
40224038

4039+
<div class="hidden">
4040+
<h3 class="heading no-toc" id="hidden.d.2"> </h3>
4041+
<h3 class="heading no-toc" id="hidden.d.3"> </h3>
4042+
<h3 class="heading no-toc" id="hidden.d.4"> </h3>
4043+
<h3 class="heading no-toc" id="hidden.d.4a"> </h3>
4044+
<h4 class="heading no-toc" id="hidden.d.5"> </h4>
4045+
<h4 class="heading no-toc" id="hidden.d.6"> </h4>
4046+
<h4 class="heading no-toc" id="hidden.d.7"> </h4>
4047+
<h4 class="heading no-toc" id="hidden.d.7a"> </h4>
4048+
<h5 class="heading no-toc" id="hidden.d.8"> </h5>
4049+
<h5 class="heading no-toc" id="hidden.d.9"> </h5>
4050+
<h5 class="heading no-toc" id="hidden.d.10"> </h5>
4051+
<h5 class="heading no-toc" id="hidden.d.11"> </h5>
4052+
<h5 class="heading no-toc" id="hidden.d.12"> </h5>
4053+
<h5 class="heading no-toc" id="hidden.d.13"> </h5>
4054+
</div>
4055+
4056+
4057+
<div class="standardeze">
4058+
<h6 class="heading" id="allocator.requirements.general">General <b>[allocator.requirements.general]</b> </h6>
4059+
4060+
<span class="ed-note">At the end of [allocator.requirements.general], add the
4061+
following new paragraph:</span>
4062+
4063+
98. [*Example 2*: The following is an allocator class template supporting the
4064+
minimal interface that meets the requirements of
4065+
[allocator.requirements.general]:
4066+
4067+
<pre highlight="c++">
4068+
template&lt;class T>
4069+
struct SimpleAllocator {
4070+
using value_type = T;
4071+
SimpleAllocator(<i>ctor args</i>);
4072+
4073+
template&lt;class U> SimpleAllocator(const SimpleAllocator&lt;U>& other);
4074+
4075+
T* allocate(std::size_t n);
4076+
void deallocate(T* p, std::size_t n);
4077+
4078+
template&lt;class U> bool operator==(const SimpleAllocator&lt;U>& rhs) const;
4079+
};
4080+
</pre>
4081+
4082+
-- *end example*]
4083+
4084+
<div class="block-insert">
4085+
99. The following exposition-only concept defines the minimal requirements on an
4086+
<i>Allocator</i> type.
4087+
4088+
<pre highlight="c++">
4089+
template&lt;class Alloc>
4090+
concept <i>simple-allocator</i> =
4091+
requires(Alloc alloc, size_t n) {
4092+
{ *alloc.allocate(n) } -> same_as&lt;typename Alloc::value_type&>;
4093+
{ alloc.deallocate(alloc.allocate(n), n) };
4094+
} &&
4095+
copy_constructible&lt;Alloc> &&
4096+
equality_comparable&lt;Alloc>;
4097+
</pre>
4098+
4099+
1. A type `Alloc` models <i>`simple-allocator`</i> if it meets the requirements of
4100+
[allocator.requirements.general].
4101+
4102+
</div>
4103+
</div>
4104+
40234105
<div class="hidden">
40244106
<h2 class="heading no-toc" id="hidden.e.1"> </h2>
40254107
<h2 class="heading no-toc" id="hidden.e.2"> </h2>
@@ -5252,7 +5334,7 @@ template&lt;class Initializer>
52525334
<td>
52535335
<ul>
52545336
<li>general queries (e.g., `get_allocator`, `get_stop_token`)</li>
5255-
<li>environment queries (e.g., `get_scheduler`, `get_delegatee_scheduler`)</li>
5337+
<li>environment queries (e.g., `get_scheduler`, `get_delegation_scheduler`)</li>
52565338
<li>scheduler queries (e.g., `get_forward_progress_guarantee`, `execute_may_block_caller`)</li>
52575339
<li>sender attribute queries (e.g., `get_completion_scheduler`)</li>
52585340
</ul>
@@ -5572,14 +5654,14 @@ namespace std::execution {
55725654
};
55735655
struct get_domain_t { <i>see below</i> };
55745656
struct get_scheduler_t { <i>see below</i> };
5575-
struct get_delegatee_scheduler_t { <i>see below</i> };
5657+
struct get_delegation_scheduler_t { <i>see below</i> };
55765658
struct get_forward_progress_guarantee_t { <i>see below</i> };
55775659
template&lt;class CPO>
55785660
struct get_completion_scheduler_t { <i>see below</i> };
55795661

55805662
inline constexpr get_domain_t get_domain{};
55815663
inline constexpr get_scheduler_t get_scheduler{};
5582-
inline constexpr get_delegatee_scheduler_t get_delegatee_scheduler{};
5664+
inline constexpr get_delegation_scheduler_t get_delegation_scheduler{};
55835665
inline constexpr get_forward_progress_guarantee_t get_forward_progress_guarantee{};
55845666
template&lt;class CPO>
55855667
inline constexpr get_completion_scheduler_t&lt;CPO> get_completion_scheduler{};
@@ -5849,12 +5931,9 @@ namespace std::execution {
58495931
}
58505932
</pre>
58515933

5852-
5853-
<!-- LWG stopped here -->
5854-
58555934
## Queries <b>[exec.queries]</b> ## {#spec-execution.queries}
58565935

5857-
### `std::forwarding_query` <b>[exec.fwd.env]</b> ### {#spec-execution.forwarding_query}
5936+
### `forwarding_query` <b>[exec.fwd.env]</b> ### {#spec-execution.forwarding_query}
58585937

58595938
1. `forwarding_query` asks a query object whether it should be forwarded
58605939
through queryable adaptors.
@@ -5867,33 +5946,35 @@ namespace std::execution {
58675946
expression is well-formed.
58685947

58695948
* <i>Mandates:</i> The expression above has type `bool` and is a core
5870-
constant expressions if `q` is a core constant expression.
5949+
constant expression if `q` is a core constant expression.
58715950

58725951
2. Otherwise, `true` if `derived_from<Q, forwarding_query_t>` is
58735952
`true`.
58745953

58755954
3. Otherwise, `false`.
58765955

5877-
### `std::get_allocator` <b>[exec.get.allocator]</b> ### {#spec-execution.get_allocator}
5956+
### `get_allocator` <b>[exec.get.allocator]</b> ### {#spec-execution.get_allocator}
58785957

5879-
1. `get_allocator` asks an object for its associated allocator.
5958+
1. `get_allocator` asks a queryable object for its associated allocator.
58805959

58815960
2. The name `get_allocator` denotes a query object. For a subexpression `env`,
58825961
`get_allocator(env)` is expression-equivalent to
58835962
<code><i>MANDATE-NOTHROW</i>(as_const(env).query(get_allocator))</code>.
58845963

58855964
* <i>Mandates:</i> If the expression above is well-formed, its type
5886-
satisfies <i>Allocator</i>.
5965+
satisfies *`simple-allocator`* ([allocator.requirements.general]).
58875966

5888-
3. `forwarding_query(get_allocator)` is a core constant
5889-
expression and has value `true`.
5967+
3. `forwarding_query(get_allocator)` is a core constant expression and has value
5968+
`true`.
58905969

58915970
4. `get_allocator()` (with no arguments) is expression-equivalent to
58925971
`execution::read(get_allocator)` ([exec.read]).
58935972

5894-
### `std::get_stop_token` <b>[exec.get.stop.token]</b> ### {#spec-execution.get_stop_token}
58955973

5896-
1. `get_stop_token` asks an object for an associated stop token.
5974+
5975+
### `get_stop_token` <b>[exec.get.stop.token]</b> ### {#spec-execution.get_stop_token}
5976+
5977+
1. `get_stop_token` asks a queryable object for an associated stop token.
58975978

58985979
2. The name `get_stop_token` denotes a query object. For a subexpression `env`,
58995980
`get_stop_token(env)` is expression-equivalent to:
@@ -5917,23 +5998,23 @@ namespace std::execution {
59175998
1. `execution::get_env` is a customization point object. For a subexpression
59185999
`o`, `execution::get_env(o)` is expression-equivalent to:
59196000

5920-
1. `as_const(o).get_env()` if that expression is
6001+
1. <code><i>MANDATE-NOTHROW</i>(as_const(o).get_env())</code> if that expression is
59216002
well-formed.
59226003

5923-
* <i>Mandates:</i> The expression above is not potentially throwing, and
5924-
its type satisfies <i>`queryable`</i> ([exec.queryable]).
6004+
* <i>Mandates:</i> The type of the expression above satisfies
6005+
<i>`queryable`</i> ([exec.queryable]).
59256006

59266007
2. Otherwise, `empty_env{}`.
59276008

59286009
2. The value of `get_env(o)` shall be valid while `o` is valid.
59296010

59306011
3. <span class="wg21note">When passed a sender object, `get_env` returns the
5931-
sender's attributes. When passed a receiver, `get_env` returns the
5932-
receiver's environment.</span>
6012+
sender's associated attributes. When passed a receiver, `get_env` returns the
6013+
receiver's associated execution environment.</span>
59336014

59346015
### `execution::get_domain` <b>[exec.get.domain]</b> ### {#spec-execution.get_domain}
59356016

5936-
1. `get_domain` asks an object for an associated execution domain tag.
6017+
1. `get_domain` asks a queryable object for its associated execution domain tag.
59376018

59386019
2. The name `get_domain` denotes a query object. For a subexpression `env`,
59396020
`get_domain(env)` is expression-equivalent to
@@ -5947,7 +6028,7 @@ namespace std::execution {
59476028

59486029
### `execution::get_scheduler` <b>[exec.get.scheduler]</b> ### {#spec-execution.get_scheduler}
59496030

5950-
1. `get_scheduler` asks an object for its associated scheduler.
6031+
1. `get_scheduler` asks a queryable object for its associated scheduler.
59516032

59526033
2. The name `get_scheduler` denotes a query object. For a
59536034
subexpression `env`, `get_scheduler(env)` is expression-equivalent to
@@ -5962,23 +6043,24 @@ namespace std::execution {
59626043
4. `get_scheduler()` (with no arguments) is expression-equivalent to
59636044
`execution::read(get_scheduler)` ([exec.read]).
59646045

5965-
### `execution::get_delegatee_scheduler` <b>[exec.get.delegatee.scheduler]</b> ### {#spec-execution.get_delegatee_scheduler}
6046+
### `execution::get_delegation_scheduler` <b>[exec.get.delegation.scheduler]</b> ### {#spec-execution.get_delegation_scheduler}
59666047

5967-
1. `get_delegatee_scheduler` asks an object for a scheduler that can be used to
5968-
delegate work to for the purpose of forward progress delegation.
6048+
1. `get_delegation_scheduler` asks a queryable object for a scheduler that can be
6049+
used to delegate work to for the purpose of forward progress delegation
6050+
([intro.progress]).
59696051

5970-
2. The name `get_delegatee_scheduler` denotes a query object. For a
5971-
subexpression `env`, `get_delegatee_scheduler(env)` is expression-equivalent to
5972-
<code><i>MANDATE-NOTHROW</i>(as_const(env).query(get_delegatee_scheduler))</code>.
6052+
2. The name `get_delegation_scheduler` denotes a query object. For a
6053+
subexpression `env`, `get_delegation_scheduler(env)` is expression-equivalent to
6054+
<code><i>MANDATE-NOTHROW</i>(as_const(env).query(get_delegation_scheduler))</code>.
59736055

59746056
* <i>Mandates:</i> If the expression above is well-formed, its type
59756057
satisfies `scheduler`.
59766058

5977-
3. `forwarding_query(execution::get_delegatee_scheduler)` is a core
6059+
3. `forwarding_query(execution::get_delegation_scheduler)` is a core
59786060
constant expression and has value `true`.
59796061

5980-
4. `get_delegatee_scheduler()` (with no arguments) is expression-equivalent to
5981-
`execution::read(get_delegatee_scheduler)` ([exec.read]).
6062+
4. `get_delegation_scheduler()` (with no arguments) is expression-equivalent to
6063+
`execution::read(get_delegation_scheduler)` ([exec.read]).
59826064

59836065
### `execution::get_forward_progress_guarantee` <b>[exec.get.forward.progress.guarantee]</b> ### {#spec-execution.get_forward_progress_guarantee}
59846066

@@ -5993,7 +6075,8 @@ namespace std::execution {
59936075
</pre>
59946076

59956077
1. `get_forward_progress_guarantee` asks a scheduler about the forward progress
5996-
guarantee of execution agents created by that scheduler.
6078+
guarantee of execution agents created by that scheduler's associated
6079+
execution resource ([intro.progress]).
59976080

59986081
2. The name `get_forward_progress_guarantee` denotes a query object. For a
59996082
subexpression `sch`, let `Sch` be `decltype((sch))`. If `Sch` does not
@@ -6002,7 +6085,7 @@ namespace std::execution {
60026085
to:
60036086

60046087
1. <code><i>MANDATE-NOTHROW</i>(as_const(sch).query(get_forward_progress_guarantee))</code>,
6005-
if this expression is well-formed.
6088+
if that expression is well-formed.
60066089

60076090
* <i>Mandates:</i> The type of the expression above is
60086091
`forward_progress_guarantee`.
@@ -6011,33 +6094,33 @@ namespace std::execution {
60116094

60126095
3. If `get_forward_progress_guarantee(sch)` for some scheduler `sch` returns
60136096
`forward_progress_guarantee::concurrent`, all execution agents created by
6014-
that scheduler shall provide the concurrent forward progress guarantee. If
6015-
it returns `forward_progress_guarantee::parallel`, all execution agents
6016-
created by that scheduler shall provide at least the parallel forward
6017-
progress guarantee.
6097+
that scheduler's associated execution resource shall provide the concurrent
6098+
forward progress guarantee. If it returns
6099+
`forward_progress_guarantee::parallel`, all such execution agents shall
6100+
provide at least the parallel forward progress guarantee.
60186101

60196102
### `this_thread::execute_may_block_caller` <b>[exec.execute.may.block.caller]</b> ### {#spec-execution.execute_may_block_caller}
60206103

6021-
1. `this_thread::execute_may_block_caller` asks a scheduler `sch` whether a call
6022-
`execute(sch, f)` with any invocable `f` may block the thread where such a
6023-
call occurs.
6104+
1. `execute_may_block_caller` asks a scheduler `sch` whether any invocation of
6105+
the `execute` algorithm ([exec.execute]) with `sch` may block the current
6106+
thread of execution ([defns.block]).
60246107

6025-
2. The name `this_thread::execute_may_block_caller` denotes a query object. For
6108+
2. The name `execute_may_block_caller` denotes a query object. For
60266109
a subexpression `sch`, let `Sch` be `decltype((sch))`. If `Sch` does not
6027-
satisfy `scheduler`, `this_thread::execute_may_block_caller` is ill-formed.
6028-
Otherwise, `this_thread::execute_may_block_caller(sch)` is
6110+
satisfy `scheduler`, `execute_may_block_caller(sch)` is ill-formed.
6111+
Otherwise, `execute_may_block_caller(sch)` is
60296112
expression-equivalent to:
60306113

6031-
1. <code><i>MANDATE-NOTHROW</i>(as_const(sch).query(this_thread::execute_may_block_caller))</code>,
6032-
if this expression is well-formed.
6114+
1. <code><i>MANDATE-NOTHROW</i>(as_const(sch).query(execute_may_block_caller))</code>,
6115+
if that expression is well-formed.
60336116

60346117
* <i>Mandates:</i> The type of the expression above is `bool`.
60356118

60366119
2. Otherwise, `true`.
60376120

6038-
3. If `this_thread::execute_may_block_caller(sch)` for some scheduler `sch`
6039-
returns `false`, no `execute(sch, f)` call with some invocable `f` shall
6040-
block the calling thread.
6121+
3. If `execute_may_block_caller(sch)` returns `false` for some scheduler `sch`,
6122+
no invocation of the `execute` algorithm with `sch` shall block the calling
6123+
thread.
60416124

60426125
### `execution::get_completion_scheduler` <b>[exec.completion.scheduler]</b> ### {#spec-execution.get_completion_scheduler}
60436126

@@ -6046,27 +6129,33 @@ namespace std::execution {
60466129
attributes.
60476130

60486131
2. The name `get_completion_scheduler` denotes a query object template. For a
6049-
subexpression `q`, let `Q` be `decltype((q))`. If the template argument
6050-
`Tag` in `get_completion_scheduler<Tag>(q)` is not one of `set_value_t`,
6051-
`set_error_t`, or `set_stopped_t`, `get_completion_scheduler<Tag>(q)` is
6052-
ill-formed. Otherwise, `get_completion_scheduler<Tag>(q)` is
6132+
subexpression `q`, the expression
6133+
<code>get_completion_scheduler&lt;<i>completion-tag</i>>(q)</code> is
6134+
ill-formed if <i>`completion-tag`</i> is not one of `set_value_t`,
6135+
`set_error_t`, or `set_stopped_t`. Otherwise,
6136+
<code>get_completion_scheduler&lt;<i>completion-tag</i>>(q)</code> is
60536137
expression-equivalent to
6054-
<code><i>MANDATE-NOTHROW</i>(as_const(q).query(get_completion_scheduler&lt;Tag>))</code>.
6138+
<code><i>MANDATE-NOTHROW</i>(as_const(q).query(get_completion_scheduler&lt;<i>completion-tag</i>>))</code>.
60556139

60566140
* <i>Mandates:</i> If the expression above is well-formed, its type
60576141
satisfies `scheduler`.
60586142

6059-
3. If, for some sender `sndr` and completion function `C` that has an associated
6060-
completion tag `Tag`, `get_completion_scheduler<Tag>(get_env(sndr))` is
6061-
well-formed and results in a scheduler `sch`, and the sender `sndr` invokes
6062-
`C(rcvr, args...)`, for some receiver `rcvr` that has been connected to `sndr`, with
6063-
additional arguments `args...`, on an execution agent that does not
6064-
belong to the associated execution resource of `sch`, the behavior is
6065-
undefined.
6143+
3. Let <i>`completion-fn`</i> be a completion function ([async.ops]); let
6144+
<i>`completion-tag`</i> be the associated completion tag of
6145+
<i>`completion-fn`</i>; let `args` be a pack of subexpressions; and let
6146+
`sndr` be a subexpression such that `sender<decltype((sndr))>` is `true` and
6147+
<code>get_completion_scheduler&lt;<i>completion-tag</i>>(get_env(sndr))</code>
6148+
is well-formed and denotes a scheduler `sch`. If an asynchronous operation
6149+
created by connecting `sndr` with a receiver `rcvr` causes the evaluation of
6150+
<code><i>completion-fn</i>(rcvr, args...)</code>, the behavior is undefined
6151+
unless it happens on an execution agent that belongs to `sch`'s associated
6152+
execution resource.
60666153

6067-
4. The expression `forwarding_query(get_completion_scheduler<CPO>)`
6154+
4. The expression <code>forwarding_query(get_completion_scheduler&lt;<i>completion-tag</i>>)</code>
60686155
is a core constant expression and has value `true`.
60696156

6157+
<!-- LWG stopped here -->
6158+
60706159
## Schedulers <b>[exec.sched] </b> ## {#spec-execution.schedulers}
60716160

60726161
1. The `scheduler` concept defines the requirements of a scheduler type
@@ -8857,7 +8946,7 @@ namespace std::execution {
88578946
execution::run_loop* <em>loop</em>; // <i>exposition only</i>
88588947

88598948
auto query(execution::get_scheduler_t) const noexcept { <em>loop</em>->get_scheduler(); }
8860-
auto query(execution::get_delegatee_scheduler_t) const noexcept { <em>loop</em>->get_scheduler(); }
8949+
auto query(execution::get_delegation_scheduler_t) const noexcept { <em>loop</em>->get_scheduler(); }
88618950
};
88628951
}
88638952
</pre>
@@ -8987,7 +9076,7 @@ namespace std::execution {
89879076
progress guarantee delegation ([intro.progress]) until the specified
89889077
sender completes. <span class="wg21note">The default implementation of
89899078
`sync_wait` achieves forward progress guarantee delegation by providing
8990-
a `run_loop` scheduler via the `get_delegatee_scheduler` query on the
9079+
a `run_loop` scheduler via the `get_delegation_scheduler` query on the
89919080
<i>`sync-wait-receiver`</i>'s environment. The `run_loop` is
89929081
driven by the current thread of execution.</span>
89939082

0 commit comments

Comments
 (0)