|
2202 | 2202 | \tcode{noexcept(\exposid{final-sndr})}.
|
2203 | 2203 | \end{itemdescr}
|
2204 | 2204 |
|
| 2205 | +\rSec2[exec.snd.transform.env]{\tcode{execution::transform_env}} |
| 2206 | + |
| 2207 | +\begin{itemdecl} |
| 2208 | +namespace std::execution { |
| 2209 | + template<class Domain, @\libconcept{sender}@ Sndr, @\exposconcept{queryable}@ Env> |
| 2210 | + constexpr @\exposconcept{queryable}@ decltype(auto) transform_env(Domain dom, Sndr&& sndr, Env&& env) noexcept; |
| 2211 | +} |
| 2212 | +\end{itemdecl} |
| 2213 | + |
| 2214 | +\begin{itemdescr} |
| 2215 | +\pnum |
| 2216 | +Let \tcode{e} be the expression |
| 2217 | +\begin{codeblock} |
| 2218 | +dom.transform_env(std::forward<Sndr>(sndr), std::forward<Env>(env)) |
| 2219 | +\end{codeblock} |
| 2220 | +if that expression is well-formed; otherwise, |
| 2221 | +\begin{codeblock} |
| 2222 | +default_domain().transform_env(std::forward<Sndr>(sndr), std::forward<Env>(env)) |
| 2223 | +\end{codeblock} |
| 2224 | + |
| 2225 | +\pnum |
| 2226 | +\mandates |
| 2227 | +\tcode{noexcept(e)} is \tcode{true}. |
| 2228 | + |
| 2229 | +\pnum |
| 2230 | +\returns |
| 2231 | +\tcode{e} |
| 2232 | +\end{itemdescr} |
| 2233 | + |
| 2234 | +\rSec2[exec.snd.apply]{\tcode{execution::apply_sender}} |
| 2235 | + |
| 2236 | +\begin{itemdecl} |
| 2237 | +namespace std::execution { |
| 2238 | + template<class Domain, class Tag, @\libconcept{sender}@ Sndr, class... Args> |
| 2239 | + constexpr decltype(auto) apply_sender(Domain dom, Tag, Sndr&& sndr, Args&&... args) |
| 2240 | + noexcept(see below); |
| 2241 | +} |
| 2242 | +\end{itemdecl} |
| 2243 | + |
| 2244 | +\begin{itemdescr} |
| 2245 | +\pnum |
| 2246 | +Let $e$ be the expression |
| 2247 | +\begin{codeblock} |
| 2248 | +dom.apply_sender(Tag(), std::forward<Sndr>(sndr), std::forward<Args>(args)...) |
| 2249 | +\end{codeblock} |
| 2250 | +if that expression is well-formed; otherwise, |
| 2251 | +\begin{codeblock} |
| 2252 | +default_domain().apply_sender(Tag(), std::forward<Sndr>(sndr), std::forward<Args>(args)...) |
| 2253 | +\end{codeblock} |
| 2254 | + |
| 2255 | +\pnum |
| 2256 | +\constraints |
| 2257 | +The expression $e$ is well-formed. |
| 2258 | + |
| 2259 | +\pnum |
| 2260 | +\returns |
| 2261 | +$e$ |
| 2262 | + |
| 2263 | +\pnum |
| 2264 | +\remarks |
| 2265 | +The exception specification is equivalent to \tcode{noexcept($e$)}. |
| 2266 | +\end{itemdescr} |
| 2267 | + |
| 2268 | +\rSec2[exec.getcomplsigs]{\tcode{execution::get_completion_signatures}} |
| 2269 | + |
| 2270 | +\pnum |
| 2271 | +\tcode{get_completion_signatures} is a customization point object. |
| 2272 | +Let \tcode{sndr} be an expression |
| 2273 | +such that \tcode{decltype((sndr))} is \tcode{Sndr}, and |
| 2274 | +let \tcode{env} be an expression |
| 2275 | +such that \tcode{decltype((env))} is \tcode{Env}. |
| 2276 | +Let \tcode{new_sndr} be the expression |
| 2277 | +\tcode{transform_sender(decltype(\exposid{get-domain-late}(sndr, env)){}, sndr, env)}, and |
| 2278 | +let \tcode{NewSndr} be \tcode{decltype((new_sndr))}. |
| 2279 | +Then \tcode{get_completion_signatures(sndr, env)} is expression-equivalent to |
| 2280 | +\tcode{(void(sndr), void(env), CS())} |
| 2281 | +except that \tcode{void(sndr)} and \tcode{void(env)} are |
| 2282 | +indeterminately sequenced, |
| 2283 | +where \tcode{CS} is: |
| 2284 | +\begin{itemize} |
| 2285 | +\item |
| 2286 | +\tcode{decltype(new_sndr.get_completion_signatures(env))} |
| 2287 | +if that type is well-formed, |
| 2288 | + |
| 2289 | +\item |
| 2290 | +Otherwise, \tcode{remove_cvref_t<NewSndr>::completion_signatures} |
| 2291 | +if that type is well-formed, |
| 2292 | + |
| 2293 | +\item |
| 2294 | +Otherwise, |
| 2295 | +if \tcode{\exposid{is-awaitable}<NewSndr, env-promise<Env>>} is \tcode{true}, |
| 2296 | +then: |
| 2297 | +\begin{codeblock} |
| 2298 | +completion_signatures< |
| 2299 | + @\exposid{SET-VALUE-SIG}@(@\exposid{await-result-type}@<NewSndr, @\exposid{env-promise}@<Env>>), // \iref{exec.snd.concepts} |
| 2300 | + set_error_t(exception_ptr), |
| 2301 | + set_stopped_t()> |
| 2302 | +\end{codeblock} |
| 2303 | + |
| 2304 | +\item |
| 2305 | +Otherwise, \tcode{CS} is ill-formed. |
| 2306 | +\end{itemize} |
| 2307 | + |
| 2308 | +\pnum |
| 2309 | +Let \tcode{rcvr} be an rvalue |
| 2310 | +whose type \tcode{Rcvr} models \libconcept{receiver}, and |
| 2311 | +let \tcode{Sndr} be the type of a sender |
| 2312 | +such that \tcode{\libconcept{sender_in}<Sndr, env_of_t<Rcvr>>} is \tcode{true}. |
| 2313 | +Let \tcode{Sigs...} be the template arguments of |
| 2314 | +the \tcode{completion_signatures} specialization |
| 2315 | +named by \tcode{completion_signatures_of_t<Sndr, env_of_t<Rcvr>>}. |
| 2316 | +Let \tcode{CSO} be a completion function. |
| 2317 | +If sender \tcode{Sndr} or its operation state cause |
| 2318 | +the expression \tcode{CSO(rcvr, args...)} |
| 2319 | +to be potentially evaluated\iref{basic.def.odr} |
| 2320 | +then there shall be a signature \tcode{Sig} in \tcode{Sigs...} |
| 2321 | +such that |
| 2322 | +\begin{codeblock} |
| 2323 | +@\exposid{MATCHING-SIG}@(@\exposid{decayed-typeof}@<CSO>(decltype(args)...), Sig) |
| 2324 | +\end{codeblock} |
| 2325 | +is \tcode{true}\iref{exec.general}. |
| 2326 | + |
| 2327 | +\rSec2[exec.connect]{\tcode{execution::connect}} |
| 2328 | + |
| 2329 | +\pnum |
| 2330 | +\tcode{connect} connects\iref{exec.async.ops} a sender with a receiver. |
| 2331 | + |
| 2332 | +\pnum |
| 2333 | +The name \tcode{connect} denotes a customization point object. |
| 2334 | +For subexpressions \tcode{sndr} and \tcode{rcvr}, |
| 2335 | +let \tcode{Sndr} be \tcode{decltype((sndr))} and |
| 2336 | +\tcode{Rcvr} be \tcode{decltype((rcvr))}, |
| 2337 | +let \tcode{new_sndr} be the expression |
| 2338 | +\begin{codeblock} |
| 2339 | +transform_sender(decltype(@\exposid{get-domain-late}@(sndr, get_env(rcvr))){}, sndr, get_env(rcvr)) |
| 2340 | +\end{codeblock} |
| 2341 | +and let \tcode{DS} and \tcode{DR} be |
| 2342 | +\tcode{decay_t<decltype((new_sndr))>} and \tcode{decay_t<Rcvr>}, respectively. |
| 2343 | + |
| 2344 | +\pnum |
| 2345 | +Let \exposid{connect-awaitable-promise} be the following exposition-only class: |
| 2346 | + |
| 2347 | +\begin{codeblock} |
| 2348 | +namespace std::execution { |
| 2349 | + struct @\exposid{connect-awaitable-promise}@ : @\exposid{with-await-transform}@<@\exposid{connect-awaitable-promise}@> { |
| 2350 | + |
| 2351 | + @\exposid{connect-awaitable-promise}@(DS&, DR& rcvr) noexcept : @\exposid{rcvr}@(rcvr) {} |
| 2352 | + |
| 2353 | + suspend_always initial_suspend() noexcept { return {}; } |
| 2354 | + [[noreturn]] suspend_always final_suspend() noexcept { terminate(); } |
| 2355 | + [[noreturn]] void unhandled_exception() noexcept { terminate(); } |
| 2356 | + [[noreturn]] void return_void() noexcept { terminate(); } |
| 2357 | + |
| 2358 | + coroutine_handle<> unhandled_stopped() noexcept { |
| 2359 | + set_stopped(std::move(@\exposid{rcvr}@)); |
| 2360 | + return noop_coroutine(); |
| 2361 | + } |
| 2362 | + |
| 2363 | + @\exposid{operation-state-task}@ get_return_object() noexcept { |
| 2364 | + return @\exposid{operation-state-task}@{ |
| 2365 | + coroutine_handle<@\exposid{connect-awaitable-promise}@>::from_promise(*this)}; |
| 2366 | + } |
| 2367 | + |
| 2368 | + env_of_t<DR> get_env() const noexcept { |
| 2369 | + return execution::get_env(@\exposid{rcvr}@); |
| 2370 | + } |
| 2371 | + |
| 2372 | + private: |
| 2373 | + DR& @\exposid{rcvr}@; // \expos |
| 2374 | + }; |
| 2375 | +} |
| 2376 | +\end{codeblock} |
| 2377 | + |
| 2378 | +\pnum |
| 2379 | +Let \exposid{operation-state-task} be the following exposition-only class: |
| 2380 | +\begin{codeblock} |
| 2381 | +namespace std::execution { |
| 2382 | + struct @\exposid{operation-state-task}@ { |
| 2383 | + using operation_state_concept = operation_state_t; |
| 2384 | + using promise_type = @\exposid{connect-awaitable-promise}@; |
| 2385 | + |
| 2386 | + explicit @\exposid{operation-state-task}@(coroutine_handle<> h) noexcept : coro(h) {} |
| 2387 | + @\exposid{operation-state-task}@(@\exposid{operation-state-task}@&& o) noexcept |
| 2388 | + : @\exposid{coro}@(exchange(o.@\exposid{coro}@, {})) {} |
| 2389 | + ~@\exposid{operation-state-task}@() { if (@\exposid{coro}@) @\exposid{coro}@.destroy(); } |
| 2390 | + |
| 2391 | + void start() & noexcept { |
| 2392 | + @\exposid{coro}@.resume(); |
| 2393 | + } |
| 2394 | + |
| 2395 | + private: |
| 2396 | + coroutine_handle<> @\exposid{coro}@; // \expos |
| 2397 | + }; |
| 2398 | +} |
| 2399 | +\end{codeblock} |
| 2400 | + |
| 2401 | +\pnum |
| 2402 | +Let \tcode{V} name the type |
| 2403 | +\tcode{\exposid{await-result-type}<DS, \exposid{connect-awaitable-promise}>}, |
| 2404 | +let \tcode{Sigs} name the type |
| 2405 | +\begin{codeblock} |
| 2406 | +completion_signatures< |
| 2407 | + @\exposid{SET-VALUE-SIG}@(V), // see \iref{exec.snd.concepts} |
| 2408 | + set_error_t(exception_ptr), |
| 2409 | + set_stopped_t()> |
| 2410 | +\end{codeblock} |
| 2411 | +and let \exposid{connect-awaitable} be an exposition-only coroutine |
| 2412 | +defined as follows: |
| 2413 | +\begin{codeblock} |
| 2414 | +namespace std::execution { |
| 2415 | + template<class Fun, class... Ts> |
| 2416 | + auto @\exposid{suspend-complete}@(Fun fun, Ts&&... as) noexcept { // \expos |
| 2417 | + auto fn = [&, fun]() noexcept { fun(std::forward<Ts>(as)...); }; |
| 2418 | + |
| 2419 | + struct awaiter { |
| 2420 | + decltype(@\exposid{fn}@) @\exposid{fn}@; // \expos |
| 2421 | + |
| 2422 | + static constexpr bool await_ready() noexcept { return false; } |
| 2423 | + void await_suspend(coroutine_handle<>) noexcept { @\exposid{fn}@(); } |
| 2424 | + [[noreturn]] void await_resume() noexcept { unreachable(); } |
| 2425 | + }; |
| 2426 | + return awaiter{@\exposid{fn}@}; |
| 2427 | + } |
| 2428 | + |
| 2429 | + @\exposid{operation-state-task}@ @\exposid{connect-awaitable}@(DS sndr, DR rcvr) requires @\libconcept{receiver_of}@<DR, Sigs> { |
| 2430 | + exception_ptr ep; |
| 2431 | + try { |
| 2432 | + if constexpr (@\libconcept{same_as}@<V, void>) { |
| 2433 | + co_await std::move(sndr); |
| 2434 | + co_await @\exposid{suspend-complete}@(set_value, std::move(rcvr)); |
| 2435 | + } else { |
| 2436 | + co_await @\exposid{suspend-complete}@(set_value, std::move(rcvr), co_await std::move(sndr)); |
| 2437 | + } |
| 2438 | + } catch(...) { |
| 2439 | + ep = current_exception(); |
| 2440 | + } |
| 2441 | + co_await @\exposid{suspend-complete}@(set_error, std::move(rcvr), std::move(ep)); |
| 2442 | + } |
| 2443 | +} |
| 2444 | +\end{codeblock} |
| 2445 | + |
| 2446 | +\pnum |
| 2447 | +The expression \tcode{connect(sndr, rcvr)} is expression-equivalent to: |
| 2448 | +\begin{itemize} |
| 2449 | +\item |
| 2450 | +\tcode{new_sndr.connect(rcvr)} if that expression is well-formed. |
| 2451 | + |
| 2452 | +\mandates |
| 2453 | +The type of the expression above satisfies \libconcept{operation_state}. |
| 2454 | + |
| 2455 | +\item |
| 2456 | +Otherwise, \tcode{\exposid{connect-awaitable}(new_sndr, rcvr)}. |
| 2457 | +\end{itemize} |
| 2458 | + |
| 2459 | +\mandates |
| 2460 | +\tcode{\libconcept{sender}<Sndr> \&\& \libconcept{receiver}<Rcvr>} is \tcode{true}. |
| 2461 | + |
| 2462 | + |
2205 | 2463 | \rSec1[exec.util]{Sender/receiver utilities}
|
2206 | 2464 |
|
2207 | 2465 | \rSec1[exec.ctx]{Execution contexts}
|
|
0 commit comments