[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*(); }; };}
