From Jason Turner

[exec.associate]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmpllbcsua_/{from.md → to.md} +213 -0
tmp/tmpllbcsua_/{from.md → to.md} RENAMED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #### `execution::associate` <a id="exec.associate">[[exec.associate]]</a>
2
+
3
+ `associate` tries to associate a sender with an async scope such that
4
+ the scope can track the lifetime of any asynchronous operations created
5
+ with the sender.
6
+
7
+ Let *`associate-data`* be the following exposition-only class template:
8
+
9
+ ``` cpp
10
+ namespace std::execution {
11
+ template<scope_token Token, sender Sender>
12
+ struct associate-data { // exposition only
13
+ using wrap-sender = // exposition only
14
+ remove_cvref_t<decltype(declval<Token&>().wrap(declval<Sender>()))>;
15
+
16
+ explicit associate-data(Token t, Sender&& s)
17
+ : sndr(t.wrap(std::forward<Sender>(s))),
18
+ token(t) {
19
+ if (!token.try_associate())
20
+ sndr.reset();
21
+ }
22
+
23
+ associate-data(const associate-data& other)
24
+ noexcept(is_nothrow_copy_constructible_v<wrap-sender> &&
25
+ noexcept(other.token.try_associate()));
26
+
27
+ associate-data(associate-data&& other)
28
+ noexcept(is_nothrow_move_constructible_v<wrap-sender>);
29
+
30
+ ~associate-data();
31
+
32
+ optional<pair<Token, wrap-sender>>
33
+ release() && noexcept(is_nothrow_move_constructible_v<wrap-sender>);
34
+
35
+ private:
36
+ optional<wrap-sender> sndr; // exposition only
37
+ Token token; // exposition only
38
+ };
39
+
40
+ template<scope_token Token, sender Sender>
41
+ associate-data(Token, Sender&&) -> associate-data<Token, Sender>;
42
+ }
43
+ ```
44
+
45
+ For an *`associate-data`* object `a`, `a.sndr.has_value()` is `true` if
46
+ and only if an association was successfully made and is owned by `a`.
47
+
48
+ ``` cpp
49
+ associate-data(const associate-data& other)
50
+ noexcept(is_nothrow_copy_constructible_v<wrap-sender> &&
51
+ noexcept(other.token.try_associate()));
52
+ ```
53
+
54
+ *Constraints:* `copy_constructible<`*`wrap-sender`*`>` is `true`.
55
+
56
+ *Effects:* Value-initializes *sndr* and initializes *token* with
57
+ `other.`*`token`*. If `other.`*`sndr`*`.has_value()` is `false`, no
58
+ further effects; otherwise, calls *`token`*`.try_associate()` and, if
59
+ that returns `true`, calls *`sndr`*`.emplace(*other.`*`sndr`*`)` and, if
60
+ that exits with an exception, calls *`token`*`.disassociate()` before
61
+ propagating the exception.
62
+
63
+ ``` cpp
64
+ associate-data(associate-data&& other)
65
+ noexcept(is_nothrow_move_constructible_v<wrap-sender>);
66
+ ```
67
+
68
+ *Effects:* Initializes *sndr* with `std::move(other.`*`sndr`*`)` and
69
+ initializes *token* with `std::move(other.`*`token`*`)` and then calls
70
+ `other.`*`sndr`*`.reset()`.
71
+
72
+ ``` cpp
73
+ ~associate-data();
74
+ ```
75
+
76
+ *Effects:* If *`sndr`*`.has_value()` returns `false` then no effect;
77
+ otherwise, invokes *`sndr`*`.reset()` before invoking
78
+ *`token`*`.disassociate()`.
79
+
80
+ ``` cpp
81
+ optional<pair<Token, wrap-sender>>
82
+ release() && noexcept(is_nothrow_move_constructible_v<wrap-sender>);
83
+ ```
84
+
85
+ *Effects:* If *`sndr`*`.has_value()` returns `false` then returns an
86
+ `optional` that does not contain a value; otherwise returns an
87
+ `optional` containing a value of type `pair<Token, `*`wrap-sender`*`>`
88
+ as if by:
89
+
90
+ ``` cpp
91
+ return optional(pair(token, std::move(*sndr)));
92
+ ```
93
+
94
+ *Ensures:* *sndr* does not contain a value.
95
+
96
+ The name `associate` denotes a pipeable sender adaptor object. For
97
+ subexpressions `sndr` and `token`:
98
+
99
+ - If `decltype((sndr))` does not satisfy `sender`, or
100
+ `remove_cvref_t<decltype((token))>` does not satisfy `scope_token`,
101
+ then `associate(sndr, token)` is ill-formed.
102
+ - Otherwise, the expression `associate(sndr, token)` is
103
+ expression-equivalent to:
104
+ ``` cpp
105
+ transform_sender(get-domain-early(sndr),
106
+ make-sender(associate, associate-data(token, sndr)))
107
+ ```
108
+
109
+ except that `sndr` is evaluated only once.
110
+
111
+ The exposition-only class template *`impls-for`* [[exec.snd.expos]] is
112
+ specialized for `associate_t` as follows:
113
+
114
+ ``` cpp
115
+ namespace std::execution {
116
+ template<>
117
+ struct impls-for<associate_t> : default-impls {
118
+ static constexpr auto get-state = see below; // exposition only
119
+ static constexpr auto start = see below; // exposition only
120
+
121
+ template<class Sndr, class... Env>
122
+ static consteval void check-types() { // exposition only
123
+ using associate_data_t = remove_cvref_t<data-type<Sndr>>;
124
+ using child_type_t = associate_data_t::wrap-sender;
125
+ (void)get_completion_signatures<child_type_t, FWD-ENV-T(Env)...>();
126
+ }
127
+ };
128
+ }
129
+ ```
130
+
131
+ The member `impls-for<associate_t>::get-state` is initialized with a
132
+ callable object equivalent to the following lambda:
133
+
134
+ ``` cpp
135
+ []<class Sndr, class Rcvr>(Sndr&& sndr, Rcvr& rcvr) noexcept(see below) {
136
+ auto [_, data] = std::forward<Sndr>(sndr);
137
+ auto dataParts = std::move(data).release();
138
+
139
+ using scope_tkn = decltype(dataParts->first);
140
+ using wrap_sender = decltype(dataParts->second);
141
+ using op_t = connect_result_t<wrap_sender, Rcvr>;
142
+
143
+ struct op_state {
144
+ bool associated = false; // exposition only
145
+ union {
146
+ Rcvr* rcvr; // exposition only
147
+ struct {
148
+ scope_tkn token; // exposition only
149
+ op_t op; // exposition only
150
+ } assoc; // exposition only
151
+ };
152
+
153
+ explicit op_state(Rcvr& r) noexcept
154
+ : rcvr(addressof(r)) {}
155
+
156
+ explicit op_state(scope_tkn tkn, wrap_sender&& sndr, Rcvr& r) try
157
+ : associated(true),
158
+ assoc(tkn, connect(std::move(sndr), std::move(r))) {
159
+ }
160
+ catch (...) {
161
+ tkn.disassociate();
162
+ throw;
163
+ }
164
+
165
+ op_state(op_state&&) = delete;
166
+
167
+ ~op_state() {
168
+ if (associated) {
169
+ assoc.op.~op_t();
170
+ assoc.token.disassociate();
171
+ assoc.token.~scope_tkn();
172
+ }
173
+ }
174
+
175
+ void run() noexcept { // exposition only
176
+ if (associated)
177
+ start(assoc.op);
178
+ else
179
+ set_stopped(std::move(*rcvr));
180
+ }
181
+ };
182
+
183
+ if (dataParts)
184
+ return op_state{std::move(dataParts->first), std::move(dataParts->second), rcvr};
185
+ else
186
+ return op_state{rcvr};
187
+ }
188
+ ```
189
+
190
+ The expression in the `noexcept` clause of
191
+ `impls-for<associate_t>::get-state` is
192
+
193
+ ``` cpp
194
+ is_nothrow_constructible_v<remove_cvref_t<Sndr>, Sndr> &&
195
+ is_nothrow_move_constructible_v<wrap-sender> &&
196
+ nothrow-callable<connect_t, wrap-sender, Rcvr>
197
+ ```
198
+
199
+ where *`wrap-sender`* is the type
200
+ `remove_cvref_t<data-type<Sndr>>::wrap-sender`.
201
+
202
+ The member `impls-for<associate_t>::start` is initialized with a
203
+ callable object equivalent to the following lambda:
204
+
205
+ ``` cpp
206
+ [](auto& state, auto&) noexcept -> void {
207
+ state.run();
208
+ }
209
+ ```
210
+
211
+ The evaluation of `associate(sndr, token)` may cause side effects
212
+ observable via `token`'s associated async scope object.
213
+