Files
cppdraft_translate/cppdraft/exec/spawn/future.md
2025-10-25 03:02:53 +03:00

277 lines
12 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[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)