This commit is contained in:
2025-10-25 03:02:53 +03:00
commit 043225d523
3416 changed files with 681196 additions and 0 deletions

View 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.3Sender concepts[exec.snd.concepts]")<Sndr>,[scope_token](exec.scope.concepts#concept:scope_token "33.14.1Execution scope concepts[exec.scope.concepts]")<Token>, or[*queryable*](exec.queryable.concept#concept:queryable "33.2.2queryable 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.3Stop 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.3Sender 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.1Execution scope concepts[exec.scope.concepts]") Token, [sender](exec.snd.concepts#concept:sender "33.9.3Sender 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.1Receiver 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.2Multi-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.1Receiver 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 (![same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<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.2Exposition-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)