1 /*
2 * Copyright (c) 2021-2024 NVIDIA Corporation
3 *
4 * Licensed under the Apache License Version 2.0 with LLVM Exceptions
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * https://llvm.org/LICENSE.txt
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #pragma once
17
18 #include "__execution_fwd.hpp"
19
20 // include these after __execution_fwd.hpp
21 #include "__completion_signatures.hpp"
22 #include "__concepts.hpp"
23 #include "__debug.hpp"
24 #include "__diagnostics.hpp"
25 #include "__meta.hpp"
26 #include "__senders_core.hpp"
27
28 #include <tuple>
29 #include <variant>
30
31 namespace stdexec
32 {
33 #if STDEXEC_ENABLE_EXTRA_TYPE_CHECKING()
34 // __checked_completion_signatures is for catching logic bugs in a sender's
35 // metadata. If sender<S> and sender_in<S, Ctx> are both true, then they had
36 // better report the same metadata. This completion signatures wrapper enforces
37 // that at compile time.
38 template <class _Sender, class... _Env>
__checked_completion_signatures(_Sender && __sndr,_Env &&...__env)39 auto __checked_completion_signatures(_Sender&& __sndr, _Env&&... __env) noexcept
40 {
41 using __completions_t = __completion_signatures_of_t<_Sender, _Env...>;
42 stdexec::__debug_sender(static_cast<_Sender&&>(__sndr), __env...);
43 return __completions_t{};
44 }
45
46 template <class _Sender, class... _Env>
47 requires sender_in<_Sender, _Env...>
48 using completion_signatures_of_t =
49 decltype(stdexec::__checked_completion_signatures(__declval<_Sender>(),
50 __declval<_Env>()...));
51 #else
52 template <class _Sender, class... _Env>
53 requires sender_in<_Sender, _Env...>
54 using completion_signatures_of_t =
55 __completion_signatures_of_t<_Sender, _Env...>;
56 #endif
57
58 struct __not_a_variant
59 {
60 __not_a_variant() = delete;
61 };
62
63 template <class... _Ts>
64 using __std_variant = //
65 __minvoke_if_c<sizeof...(_Ts) != 0,
66 __mtransform<__q1<__decay_t>, __munique<__qq<std::variant>>>,
67 __mconst<__not_a_variant>, _Ts...>;
68
69 template <class... _Ts>
70 using __nullable_std_variant =
71 __mcall<__munique<__mbind_front<__qq<std::variant>, std::monostate>>,
72 __decay_t<_Ts>...>;
73
74 template <class... _Ts>
75 using __decayed_std_tuple = __meval<std::tuple, __decay_t<_Ts>...>;
76
77 namespace __sigs
78 {
79 // The following code is used to normalize completion signatures.
80 // "Normalization" means that that rvalue-references are stripped from the types
81 // in the completion signatures. For example, the completion signature
82 // `set_value_t(int &&)` would be normalized to `set_value_t(int)`, but
83 // `set_value_t(int)` and `set_value_t(int &)` would remain unchanged.
84 template <class _Tag, class... _Args>
85 auto __normalize_sig_impl(_Args&&...) -> _Tag (*)(_Args...);
86
87 template <class _Tag, class... _Args>
88 auto __normalize_sig(_Tag (*)(_Args...))
89 -> decltype(__sigs::__normalize_sig_impl<_Tag>(__declval<_Args>()...));
90
91 template <class... _Sigs>
92 auto __repack_completions(_Sigs*...) -> completion_signatures<_Sigs...>;
93
94 template <class... _Sigs>
95 auto __normalize_completions(completion_signatures<_Sigs...>*)
96 -> decltype(__sigs::__repack_completions(
97 __sigs::__normalize_sig(static_cast<_Sigs*>(nullptr))...));
98
99 template <class _Completions>
100 using __normalize_completions_t = decltype(__sigs::__normalize_completions(
101 static_cast<_Completions*>(nullptr)));
102 } // namespace __sigs
103
104 template <class... _SigPtrs>
105 using __completion_signature_ptrs = //
106 decltype(__sigs::__repack_completions(static_cast<_SigPtrs>(nullptr)...));
107
108 template <class... _Sigs>
109 using __concat_completion_signatures = //
110 __mconcat<__qq<completion_signatures>>::__f<
111 __mconcat<__qq<__mmake_set>>::__f<_Sigs...>>;
112
113 namespace __sigs
114 {
115 //////////////////////////////////////////////////////////////////////////////////////////////////
116 template <template <class...> class _Tuple, class _Tag, class... _Args>
117 auto __for_each_sig(_Tag (*)(_Args...)) -> _Tuple<_Tag, _Args...>;
118
119 template <class _Sig, template <class...> class _Tuple>
120 using __for_each_sig_t =
121 decltype(__sigs::__for_each_sig<_Tuple>(static_cast<_Sig*>(nullptr)));
122
123 template <template <class...> class _Tuple, template <class...> class _Variant,
124 class... _More, class _What, class... _With>
125 auto __for_each_completion_signature_fn(_ERROR_<_What, _With...>**)
126 -> _ERROR_<_What, _With...>;
127
128 template <template <class...> class _Tuple, template <class...> class _Variant,
129 class... _More, class... _Sigs>
130 auto __for_each_completion_signature_fn(completion_signatures<_Sigs...>**)
131 -> _Variant<__for_each_sig_t<_Sigs, _Tuple>..., _More...>;
132 } // namespace __sigs
133
134 template <class _Sigs, template <class...> class _Tuple,
135 template <class...> class _Variant, class... _More>
136 using __for_each_completion_signature =
137 decltype(__sigs::__for_each_completion_signature_fn<
138 _Tuple, _Variant, _More...>(static_cast<_Sigs**>(nullptr)));
139
140 namespace __sigs
141 {
142 ////////////////////////////////////////////////////////////////////////////////////////////////
143 template <template <class...> class _SetVal, template <class...> class _SetErr,
144 class _SetStp, class... _Values>
145 auto __transform_sig(set_value_t (*)(_Values...)) -> _SetVal<_Values...>;
146
147 template <template <class...> class _SetVal, template <class...> class _SetErr,
148 class _SetStp, class _Error>
149 auto __transform_sig(set_error_t (*)(_Error)) -> _SetErr<_Error>;
150
151 template <template <class...> class _SetVal, template <class...> class _SetErr,
152 class _SetStp>
153 auto __transform_sig(set_stopped_t (*)()) -> _SetStp;
154
155 template <class _Sig, template <class...> class _SetVal,
156 template <class...> class _SetErr, class _SetStp>
157 using __transform_sig_t =
158 decltype(__sigs::__transform_sig<_SetVal, _SetErr, _SetStp>(
159 static_cast<_Sig*>(nullptr)));
160
161 template <template <class...> class _SetVal, template <class...> class _SetErr,
162 class _SetStp, template <class...> class _Variant, class... _More,
163 class _What, class... _With>
164 auto __transform_sigs_fn(_ERROR_<_What, _With...>**)
165 -> _ERROR_<_What, _With...>;
166
167 template <template <class...> class _SetVal, template <class...> class _SetErr,
168 class _SetStp, template <class...> class _Variant, class... _More,
169 class... _Sigs>
170 auto __transform_sigs_fn(completion_signatures<_Sigs...>**) //
171 -> _Variant<__transform_sig_t<_Sigs, _SetVal, _SetErr, _SetStp>...,
172 _More...>;
173 } // namespace __sigs
174
175 template <class _Sigs, template <class...> class _SetVal,
176 template <class...> class _SetErr, class _SetStp,
177 template <class...> class _Variant,
178 class... _More>
179 using __transform_completion_signatures = //
180 decltype(__sigs::__transform_sigs_fn<_SetVal, _SetErr, _SetStp, _Variant,
181 _More...>(
182 static_cast<_Sigs**>(nullptr)));
183
184 namespace __sigs
185 {
186 ////////////////////////////////////////////////////////////////////////////////////////////////
187 template <class _WantedTag>
188 struct __gather_sigs_fn;
189
190 template <>
191 struct __gather_sigs_fn<set_value_t>
192 {
193 template <class _Sigs, template <class...> class _Then,
194 template <class...> class _Else,
195 template <class...> class _Variant, class... _More>
196 using __f = __transform_completion_signatures<
197 _Sigs, _Then, __mbind_front_q<_Else, set_error_t>::template __f,
198 _Else<set_stopped_t>, _Variant, _More...>;
199 };
200
201 template <>
202 struct __gather_sigs_fn<set_error_t>
203 {
204 template <class _Sigs, template <class...> class _Then,
205 template <class...> class _Else,
206 template <class...> class _Variant, class... _More>
207 using __f = __transform_completion_signatures<
208 _Sigs, __mbind_front_q<_Else, set_value_t>::template __f, _Then,
209 _Else<set_stopped_t>, _Variant, _More...>;
210 };
211
212 template <>
213 struct __gather_sigs_fn<set_stopped_t>
214 {
215 template <class _Sigs, template <class...> class _Then,
216 template <class...> class _Else,
217 template <class...> class _Variant, class... _More>
218 using __f = __transform_completion_signatures<
219 _Sigs, __mbind_front_q<_Else, set_value_t>::template __f,
220 __mbind_front_q<_Else, set_error_t>::template __f, _Then<>, _Variant,
221 _More...>;
222 };
223
224 template <class... _Values>
225 using __default_set_value = completion_signatures<set_value_t(_Values...)>;
226
227 template <class... _Error>
228 using __default_set_error = completion_signatures<set_error_t(_Error...)>;
229
230 template <class _Tag, class... _Args>
231 using __default_completion = completion_signatures<_Tag(_Args...)>;
232 } // namespace __sigs
233
234 template <class _Sigs, class _WantedTag, template <class...> class _Then,
235 template <class...> class _Else, template <class...> class _Variant,
236 class... _More>
237 using __gather_completion_signatures = typename __sigs::__gather_sigs_fn<
238 _WantedTag>::template __f<_Sigs, _Then, _Else, _Variant, _More...>;
239
240 /////////////////////////////////////////////////////////////////////////////
241 // transform_completion_signatures
242 // ==========================
243 //
244 // `transform_completion_signatures` takes a sender, and environment, and a
245 // bunch of other template arguments for munging the completion signatures of a
246 // sender in interesting ways.
247 //
248 // ```c++
249 // template <class... Args>
250 // using __default_set_value = completion_signatures<set_value_t(Args...)>;
251 //
252 // template <class Err>
253 // using __default_set_error = completion_signatures<set_error_t(Err)>;
254 //
255 // template <
256 // class Completions,
257 // class AdditionalSigs = completion_signatures<>,
258 // template <class...> class SetValue = __default_set_value,
259 // template <class> class SetError = __default_set_error,
260 // class SetStopped = completion_signatures<set_stopped_t()>>
261 // using transform_completion_signatures =
262 // completion_signatures< ... >;
263 // ```
264 //
265 // * `SetValue` : an alias template that accepts a set of value types and
266 // returns an instance of
267 // `completion_signatures`.
268 //
269 // * `SetError` : an alias template that accepts an error types and returns a
270 // an instance of
271 // `completion_signatures`.
272 //
273 // * `SetStopped` : an instantiation of `completion_signatures` with a list of
274 // completion
275 // signatures `Sigs...` to the added to the list if the sender can complete
276 // with a stopped signal.
277 //
278 // * `AdditionalSigs` : an instantiation of `completion_signatures` with a list
279 // of completion
280 // signatures `Sigs...` to the added to the list unconditionally.
281 //
282 // `transform_completion_signatures` does the following:
283 //
284 // * Let `VCs...` be a pack of the `completion_signatures` types in the
285 // `__typelist` named by
286 // `value_types_of_t<Sndr, Env, SetValue, __typelist>`, and let `Vs...` be
287 // the concatenation of the packs that are template arguments to each
288 // `completion_signature` in `VCs...`.
289 //
290 // * Let `ECs...` be a pack of the `completion_signatures` types in the
291 // `__typelist` named by
292 // `error_types_of_t<Sndr, Env, __errorlist>`, where `__errorlist` is an
293 // alias template such that `__errorlist<Ts...>` names
294 // `__typelist<SetError<Ts>...>`, and let `Es...` be the concatenation of the
295 // packs that are the template arguments to each `completion_signature` in
296 // `ECs...`.
297 //
298 // * Let `Ss...` be an empty pack if `sends_stopped<Sndr, Env>` is `false`;
299 // otherwise, a pack
300 // containing the template arguments of the `completion_signatures`
301 // instantiation named by `SetStopped`.
302 //
303 // * Let `MoreSigs...` be a pack of the template arguments of the
304 // `completion_signatures`
305 // instantiation named by `AdditionalSigs`.
306 //
307 // Then `transform_completion_signatures<Completions, AdditionalSigs, SetValue,
308 // SetError, SendsStopped>` names the type `completion_signatures< Sigs... >`
309 // where `Sigs...` is the unique set of types in `[Vs..., Es..., Ss...,
310 // MoreSigs...]`.
311 //
312 // If any of the above type computations are ill-formed,
313 // `transform_completion_signatures<Sndr, Env, AdditionalSigs, SetValue,
314 // SetError, SendsStopped>` is ill-formed.
315 template <
316 class _Sigs, class _MoreSigs = completion_signatures<>,
317 template <class...> class _ValueTransform = __sigs::__default_set_value,
318 template <class...> class _ErrorTransform = __sigs::__default_set_error,
319 class _StoppedSigs = completion_signatures<set_stopped_t()>>
320 using transform_completion_signatures = //
321 __transform_completion_signatures<
322 _Sigs, _ValueTransform, _ErrorTransform, _StoppedSigs,
323 __mtry_q<__concat_completion_signatures>::__f, _MoreSigs>;
324
325 template <
326 class _Sndr, class _Env = empty_env,
327 class _MoreSigs = completion_signatures<>,
328 template <class...> class _ValueTransform = __sigs::__default_set_value,
329 template <class...> class _ErrorTransform = __sigs::__default_set_error,
330 class _StoppedSigs = completion_signatures<set_stopped_t()>>
331 using transform_completion_signatures_of = //
332 transform_completion_signatures<completion_signatures_of_t<_Sndr, _Env>,
333 _MoreSigs, _ValueTransform, _ErrorTransform,
334 _StoppedSigs>;
335
336 using __eptr_completion =
337 completion_signatures<set_error_t(std::exception_ptr)>;
338
339 template <class _NoExcept>
340 using __eptr_completion_if_t =
341 __if<_NoExcept, completion_signatures<>, __eptr_completion>;
342
343 template <bool _NoExcept>
344 using __eptr_completion_if = __eptr_completion_if_t<__mbool<_NoExcept>>;
345
346 template < //
347 class _Sender, //
348 class _Env = empty_env, //
349 class _More = completion_signatures<>, //
350 class _SetValue = __qq<__sigs::__default_set_value>, //
351 class _SetError = __qq<__sigs::__default_set_error>, //
352 class _SetStopped = completion_signatures<set_stopped_t()>> //
353 using __try_make_completion_signatures = //
354 __transform_completion_signatures<
355 __completion_signatures_of_t<_Sender, _Env>, _SetValue::template __f,
356 _SetError::template __f, _SetStopped,
357 __mtry_q<__concat_completion_signatures>::__f, _More>;
358
359 template <class _SetTag, class _Completions, class _Tuple,
360 class _Variant>
361 using __gather_completions = //
362 __gather_completion_signatures<
363 _Completions, _SetTag,
364 __mcompose_q<__types, _Tuple::template __f>::template __f,
365 __mconst<__types<>>::__f, __mconcat<_Variant>::template __f>;
366
367 template <class _SetTag, class _Sender, class _Env, class _Tuple,
368 class _Variant>
369 using __gather_completions_of = //
370 __gather_completions<_SetTag, __completion_signatures_of_t<_Sender, _Env>,
371 _Tuple, _Variant>;
372
373 template < //
374 class _Sender, //
375 class _Env = empty_env, //
376 class _Sigs = completion_signatures<>, //
377 template <class...> class _SetValue = __sigs::__default_set_value, //
378 template <class...> class _SetError = __sigs::__default_set_error, //
379 class _SetStopped = completion_signatures<set_stopped_t()>>
380 using make_completion_signatures =
381 transform_completion_signatures_of<_Sender, _Env, _Sigs, _SetValue,
382 _SetError, _SetStopped>;
383
384 template < //
385 class _Sigs, //
386 class _Tuple = __q<__decayed_std_tuple>, //
387 class _Variant = __q<__std_variant>>
388 using __value_types_t = //
389 __gather_completions<set_value_t, _Sigs, _Tuple, _Variant>;
390
391 template < //
392 class _Sender, //
393 class _Env = empty_env, //
394 class _Tuple = __q<__decayed_std_tuple>, //
395 class _Variant = __q<__std_variant>>
396 using __value_types_of_t = //
397 __value_types_t<__completion_signatures_of_t<_Sender, _Env>, _Tuple,
398 _Variant>;
399
400 template <class _Sigs, class _Variant = __q<__std_variant>>
401 using __error_types_t =
402 __gather_completions<set_error_t, _Sigs, __q<__midentity>, _Variant>;
403
404 template <class _Sender, class _Env = empty_env,
405 class _Variant = __q<__std_variant>>
406 using __error_types_of_t =
407 __error_types_t<__completion_signatures_of_t<_Sender, _Env>, _Variant>;
408
409 template < //
410 class _Sender, //
411 class _Env = empty_env, //
412 template <class...> class _Tuple = __decayed_std_tuple, //
413 template <class...> class _Variant = __std_variant>
414 using value_types_of_t =
415 __value_types_of_t<_Sender, _Env, __q<_Tuple>, __q<_Variant>>;
416
417 template <class _Sender, class _Env = empty_env,
418 template <class...> class _Variant = __std_variant>
419 using error_types_of_t = __error_types_of_t<_Sender, _Env, __q<_Variant>>;
420
421 template <class _Tag, class _Sender, class... _Env>
422 using __count_of = //
423 __gather_completion_signatures<
424 __completion_signatures_of_t<_Sender, _Env...>, _Tag,
425 __mconst<__msize_t<1>>::__f, __mconst<__msize_t<0>>::__f, __mplus_t>;
426
427 template <class _Tag, class _Sender, class... _Env>
428 requires sender_in<_Sender, _Env...>
429 inline constexpr bool __sends = //
430 __v<__gather_completion_signatures<
431 __completion_signatures_of_t<_Sender, _Env...>, _Tag,
432 __mconst<__mtrue>::__f, __mconst<__mfalse>::__f, __mor_t>>;
433
434 template <class _Sender, class... _Env>
435 concept sends_stopped = //
436 sender_in<_Sender, _Env...> && __sends<set_stopped_t, _Sender, _Env...>;
437
438 template <class _Sender, class... _Env>
439 using __single_sender_value_t =
440 __value_types_t<__completion_signatures_of_t<_Sender, _Env...>,
441 __msingle_or<void>, __q<__msingle>>;
442
443 template <class _Sender, class... _Env>
444 concept __single_value_sender = //
445 sender_in<_Sender, _Env...> && //
446 requires { typename __single_sender_value_t<_Sender, _Env...>; };
447
448 template <class _Sender, class... _Env>
449 using __single_value_variant_sender_t =
450 __value_types_t<__completion_signatures_of_t<_Sender, _Env...>,
451 __qq<__types>, __q<__msingle>>;
452
453 template <class _Sender, class... _Env>
454 concept __single_value_variant_sender = //
455 sender_in<_Sender, _Env...> && //
456 requires { typename __single_value_variant_sender_t<_Sender, _Env...>; };
457
458 // The following utilities are needed fairly often:
459 template <class _Fun, class... _Args>
460 requires __invocable<_Fun, _Args...>
461 using __nothrow_invocable_t = __mbool<__nothrow_invocable<_Fun, _Args...>>;
462
463 template <class _Catch, class _Tag, class _Fun, class _Sender, class... _Env>
464 using __with_error_invoke_t = //
465 __if<__gather_completion_signatures<
466 __completion_signatures_of_t<_Sender, _Env...>, _Tag,
467 __mbind_front<__mtry_catch_q<__nothrow_invocable_t, _Catch>,
468 _Fun>::template __f,
469 __mconst<__mbool<true>>::__f, __mand>,
470 completion_signatures<>, __eptr_completion>;
471
472 template <class _Fun, class... _Args>
473 requires __invocable<_Fun, _Args...>
474 using __set_value_invoke_t = //
475 completion_signatures<__minvoke<__mremove<void, __qf<set_value_t>>,
476 __invoke_result_t<_Fun, _Args...>>>;
477 } // namespace stdexec
478