[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* {templatestruct *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*)); }templatevoid set_error(E&& e) && noexcept { execution::set_error(std::move(*rcvr*), std::forward(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())))); 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 synopsis [functional.syn]")): *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*[](auto&& sender, Rcvr& receiver)noexcept(is_nothrow_constructible_v<*state*, *data-type*, 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*(); }; };}