From Jason Turner

[exec.counting.scopes.general]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmp3mg4ng3b/{from.md → to.md} +128 -0
tmp/tmp3mg4ng3b/{from.md → to.md} RENAMED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #### General <a id="exec.counting.scopes.general">[[exec.counting.scopes.general]]</a>
2
+
3
+ Scopes of type `simple_counting_scope` and `counting_scope` maintain
4
+ counts of associations. Let:
5
+
6
+ - `Scope` be either `simple_counting_scope` or `counting_scope`,
7
+ - `scope` be an object of type `Scope`,
8
+ - `tkn` be an object of type `Scope::token` obtained from
9
+ `scope.get_token()`,
10
+ - `jsndr` be a sender obtained from `scope.join()`, and
11
+ - `op` be an operation state obtained from connecting `jsndr` to a
12
+ receiver.
13
+
14
+ During its lifetime `scope` goes through different states which govern
15
+ what operations are allowed and the result of these operations:
16
+
17
+ - *`unused`*: a newly constructed object starts in the *`unused`* state.
18
+ - *`open`*: when `tkn.try_associate()` is called while `scope` is in the
19
+ *`unused`* state, `scope` moves to the *`open`* state.
20
+ - *`open-and-joining`*: when the operation state `op` is started while
21
+ `scope` is in the *`unused`* or *`open`* state, `scope` moves to the
22
+ *`open-and-joining`* state.
23
+ - *`closed`*: when `scope.close()` is called while `scope` is in the
24
+ *`open`* state, `scope` moves to the *`closed`* state.
25
+ - *`unused-and-closed`*: when `scope.close()` is called while `scope` is
26
+ in the *`unused`* state, `scope` moves to the *`unused-and-closed`*
27
+ state.
28
+ - *`closed-and-joining`*: when `scope.close()` is called while `scope`
29
+ is in the *`open-and-joining`* state or the operation state `op` is
30
+ started while `scope` is in the *`closed`* or *`unused-and-closed`*
31
+ state, `scope` moves to the *`closed-and-joining`* state.
32
+ - *`joined`*: when the count of associations drops to zero while `scope`
33
+ is in the *`open-and-joining`* or *`closed-and-joining`* state,
34
+ `scope` moves to the *`joined`* state.
35
+
36
+ *Recommended practice:* For `simple_counting_scope` and
37
+ `counting_scope`, implementations should store the state and the count
38
+ of associations in a single member of type `size_t`.
39
+
40
+ Subclause [[exec.counting.scopes]] makes use of the following
41
+ exposition-only entities:
42
+
43
+ ``` cpp
44
+ struct scope-join-t {}; // exposition only
45
+
46
+ enum scope-state-type { // exposition only
47
+ unused, // exposition only
48
+ open, // exposition only
49
+ closed, // exposition only
50
+ open-and-joining, // exposition only
51
+ closed-and-joining, // exposition only
52
+ unused-and-closed, // exposition only
53
+ joined, // exposition only
54
+ };
55
+ ```
56
+
57
+ The exposition-only class template *`impls-for`* [[exec.snd.expos]] is
58
+ specialized for *`scope-join-t`* as follows:
59
+
60
+ ``` cpp
61
+ namespace std::execution {
62
+ template<>
63
+ struct impls-for<scope-join-t> : default-impls {
64
+ template<class Scope, class Rcvr>
65
+ struct state { // exposition only
66
+ struct rcvr-t { // exposition only
67
+ using receiver_concept = receiver_t;
68
+
69
+ Rcvr& rcvr; // exposition only
70
+
71
+ void set_value() && noexcept {
72
+ execution::set_value(std::move(rcvr));
73
+ }
74
+
75
+ template<class E>
76
+ void set_error(E&& e) && noexcept {
77
+ execution::set_error(std::move(rcvr), std::forward<E>(e));
78
+ }
79
+
80
+ void set_stopped() && noexcept {
81
+ execution::set_stopped(std::move(rcvr));
82
+ }
83
+
84
+ decltype(auto) get_env() const noexcept {
85
+ return execution::get_env(rcvr);
86
+ }
87
+ };
88
+
89
+ using sched-sender = // exposition only
90
+ decltype(schedule(get_scheduler(get_env(declval<Rcvr&>()))));
91
+ using op-t = // exposition only
92
+ connect_result_t<sched-sender, rcvr-t>;
93
+
94
+ Scope* scope; // exposition only
95
+ Rcvr& receiver; // exposition only
96
+ op-t op; // exposition only
97
+
98
+ state(Scope* scope, Rcvr& rcvr) // exposition only
99
+ noexcept(nothrow-callable<connect_t, sched-sender, rcvr-t>)
100
+ : scope(scope),
101
+ receiver(rcvr),
102
+ op(connect(schedule(get_scheduler(get_env(rcvr))), rcvr-t(rcvr))) {}
103
+
104
+ void complete() noexcept { // exposition only
105
+ start(op);
106
+ }
107
+
108
+ void complete-inline() noexcept { // exposition only
109
+ set_value(std::move(receiver));
110
+ }
111
+ };
112
+
113
+ static constexpr auto get-state = // exposition only
114
+ []<class Rcvr>(auto&& sender, Rcvr& receiver)
115
+ noexcept(is_nothrow_constructible_v<state<Rcvr>, data-type<decltype(sender)>, Rcvr&>) {
116
+ auto[_, self] = sender;
117
+ return state(self, receiver);
118
+ };
119
+
120
+ static constexpr auto start = // exposition only
121
+ [](auto& s, auto&) noexcept {
122
+ if (s.scope->start-join-sender(s))
123
+ s.complete-inline();
124
+ };
125
+ };
126
+ }
127
+ ```
128
+