1 /*
2 * Copyright (c) 2021-2022 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 "../concepts.hpp"
19 #include "__concepts.hpp"
20 #include "__config.hpp"
21 #include "__env.hpp"
22 #include "__execution_fwd.hpp"
23 #include "__meta.hpp"
24 #include "__tuple.hpp"
25 #include "__type_traits.hpp"
26
27 #include <cstddef>
28 #include <type_traits>
29 #include <utility> // for tuple_size/tuple_element
30
31 namespace stdexec
32 {
33 /////////////////////////////////////////////////////////////////////////////
34 // Generic __sender type
35 namespace __detail
36 {
37 template <class _Sender>
38 using __impl_of = decltype((__declval<_Sender>().__impl_));
39
40 struct __get_tag
41 {
42 template <class _Tag, class... _Rest>
43 STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__detail::__get_tag44 _Tag operator()(_Tag, _Rest&&...) const noexcept
45 {
46 return {};
47 }
48 };
49
50 struct __get_data
51 {
52 template <class _Data, class... _Rest>
53 STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__detail::__get_data54 _Data&& operator()(__ignore, _Data&& __data, _Rest&&...) const noexcept
55 {
56 return static_cast<_Data&&>(__data);
57 }
58 };
59
60 template <class _Continuation>
61 struct __get_children
62 {
63 template <class... _Child>
64 STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__detail::__get_children65 auto operator()(__ignore, __ignore, _Child&&...) const noexcept
66 -> __mtype<__minvoke<_Continuation, _Child...>> (*)()
67 {
68 return nullptr;
69 }
70 };
71
72 template <class _Tag, class _Data, class... _Child>
73 struct __desc
74 {
75 using __tag = _Tag;
76 using __data = _Data;
77 using __children = __types<_Child...>;
78
79 template <class _Fn>
80 using __f = __minvoke<_Fn, _Tag, _Data, _Child...>;
81 };
82
83 template <class _Fn>
84 struct __sexpr_uncurry_fn
85 {
86 template <class _Tag, class _Data, class... _Child>
87 requires __minvocable<_Fn, _Tag, _Data, _Child...>
88 constexpr auto operator()(_Tag, _Data&&, _Child&&...) const noexcept
89 -> __minvoke<_Fn, _Tag, _Data, _Child...>;
90 };
91
92 template <class _Sender, class _Fn>
93 using __sexpr_uncurry =
94 __call_result_t<__impl_of<_Sender>, __copy_cvref_fn<_Sender>,
95 __sexpr_uncurry_fn<_Fn>>;
96
97 template <class _Sender>
98 using __desc_of = __sexpr_uncurry<_Sender, __q<__desc>>;
99
100 using __get_desc = __sexpr_uncurry_fn<__q<__desc>>;
101
102 template <class _Sender>
103 extern __q<__midentity> __name_of_v;
104
105 template <class _Sender>
106 using __name_of_fn = decltype(__name_of_v<_Sender>);
107
108 template <class _Sender>
109 using __name_of = __minvoke<__name_of_fn<_Sender>, _Sender>;
110 } // namespace __detail
111
112 template <class _Sender>
113 using tag_of_t = typename __detail::__desc_of<_Sender>::__tag;
114
115 template <class _Sender>
116 using __data_of = typename __detail::__desc_of<_Sender>::__data;
117
118 template <class _Sender, class _Continuation = __q<__types>>
119 using __children_of = //
120 __mapply<_Continuation, typename __detail::__desc_of<_Sender>::__children>;
121
122 template <class _Ny, class _Sender>
123 using __nth_child_of = __children_of<_Sender, __mbind_front_q<__m_at, _Ny>>;
124
125 template <std::size_t _Ny, class _Sender>
126 using __nth_child_of_c =
127 __children_of<_Sender, __mbind_front_q<__m_at, __msize_t<_Ny>>>;
128
129 template <class _Sender>
130 using __child_of = __children_of<_Sender, __q<__mfront>>;
131
132 template <class _Sender>
133 inline constexpr std::size_t __nbr_children_of =
134 __v<__children_of<_Sender, __msize>>;
135
136 template <class _Fn, class _Tp>
137 requires __mvalid<tag_of_t, _Tp> &&
138 __mvalid<__detail::__sexpr_uncurry, _Tp, _Fn>
139 struct __uncurry_<_Fn, _Tp>
140 {
141 using __t = __detail::__sexpr_uncurry<_Tp, _Fn>;
142 };
143
144 template <class _Tag>
145 struct __sexpr_impl;
146
147 template <class _Sender>
148 using __name_of = __detail::__name_of<_Sender>;
149
150 namespace __detail
151 {
152 template <class _Sexpr, class _Receiver>
153 struct __op_state;
154
155 template <class _Sexpr, class _Receiver>
156 struct __connect_fn;
157
158 template <class _Tag, class _Sexpr, class _Receiver>
159 using __state_type_t =
160 __decay_t<__result_of<__sexpr_impl<_Tag>::get_state, _Sexpr, _Receiver&>>;
161
162 template <class _Tag, class _Index, class _Sexpr, class _Receiver>
163 using __env_type_t =
164 __result_of<__sexpr_impl<_Tag>::get_env, _Index,
165 __state_type_t<_Tag, _Sexpr, _Receiver>&, _Receiver&>;
166
167 template <class _Sexpr, class _Receiver>
168 concept __connectable =
169 __callable<__impl_of<_Sexpr>, __copy_cvref_fn<_Sexpr>,
170 __connect_fn<_Sexpr, _Receiver>> &&
171 __mvalid<__state_type_t, tag_of_t<_Sexpr>, _Sexpr, _Receiver>;
172
173 // // Note: This is UB. UBSAN allows it for now.
174 // template <class _Parent, class _Child>
175 // _Parent* __parent_from_child(_Child* __child, _Child _Parent::*__mbr_ptr)
176 // noexcept {
177 // alignas(_Parent) char __buf[sizeof(_Parent)];
178 // _Parent* __parent = (_Parent*) &__buf;
179 // const std::ptrdiff_t __offset = (char*) &(__parent->*__mbr_ptr) - __buf;
180 // return (_Parent*) (static_cast<char*>(__child) - __offset);
181 // }
182
183 inline constexpr auto __get_attrs = //
184 [](__ignore, const auto&... __child) noexcept -> decltype(auto) {
185 if constexpr (sizeof...(__child) == 1)
186 {
187 return stdexec::get_env(
188 __child...); // BUGBUG: should be only the forwarding queries
189 }
190 else
191 {
192 return empty_env();
193 }
194 };
195
196 inline constexpr auto __get_env = //
197 []<class _Receiver>(__ignore, __ignore, const _Receiver& __rcvr) noexcept
198 -> env_of_t<const _Receiver&> { return stdexec::get_env(__rcvr); };
199
200 inline constexpr auto __get_state = //
201 []<class _Sender>(_Sender&& __sndr, __ignore) noexcept -> decltype(auto) {
202 return STDEXEC_CALL_EXPLICIT_THIS_MEMFN(static_cast<_Sender&&>(__sndr),
203 apply)(__get_data());
204 };
205
206 inline constexpr auto __connect = //
207 []<class _Sender, class _Receiver>(
208 _Sender&& __sndr, _Receiver __rcvr) -> __op_state<_Sender, _Receiver>
209 requires __connectable<_Sender, _Receiver>
210 {
211 return __op_state<_Sender, _Receiver>{static_cast<_Sender&&>(__sndr),
212 static_cast<_Receiver&&>(__rcvr)};
213 };
214
215 inline constexpr auto __start = //
216 []<class _StartTag = start_t, class... _ChildOps>(
217 __ignore, __ignore, _ChildOps&... __ops) noexcept
218 {
219 (_StartTag()(__ops), ...);
220 };
221
222 inline constexpr auto __complete = //
223 []<class _Index, class _Receiver, class _SetTag, class... _Args>(
224 _Index, __ignore, _Receiver& __rcvr, _SetTag,
225 _Args&&... __args) noexcept {
226 static_assert(__v<_Index> == 0,
227 "I don't know how to complete this operation.");
228 _SetTag()(std::move(__rcvr), static_cast<_Args&&>(__args)...);
229 };
230
231 inline constexpr auto __get_completion_signatures = //
__anon673c7d0f0102(__ignore, __ignore) 232 [](__ignore, __ignore) noexcept { return void(); };
233
234 template <class _ReceiverId, class _Sexpr, class _Idx>
235 struct __receiver
236 {
237 struct __t
238 {
239 using receiver_concept = receiver_t;
240 using _Receiver = stdexec::__t<_ReceiverId>;
241 using __sexpr = _Sexpr;
242 using __index = _Idx;
243 using __id = __receiver;
244 using __parent_op_t = __op_state<_Sexpr, _Receiver>;
245 using __tag_t = tag_of_t<_Sexpr>;
246
247 // A pointer to the parent operation state, which contains the one
248 // created with this receiver.
249 __parent_op_t* __op_;
250
251 // template <class _ChildSexpr, class _ChildReceiver>
252 // static __t __from_op_state(__op_state<_ChildSexpr, _ChildReceiver>*
253 // __child) noexcept {
254 // using __parent_op_t = __op_state<_Sexpr, _Receiver>;
255 // std::ptrdiff_t __offset = __parent_op_t::template
256 // __get_child_op_offset<__v<_Idx>>();
257 // __parent_op_t* __parent = (__parent_op_t*)
258 // (static_cast<char*>(__child) - __offset); return __t{__parent};
259 // }
260
261 template <__completion_tag _Tag, class... _Args>
262 STDEXEC_ATTRIBUTE((always_inline))
tag_invokestdexec::__detail::__receiver263 friend void tag_invoke(_Tag, __t&& __self, _Args&&... __args) noexcept
264 {
265 __self.__op_->__complete(_Idx(), _Tag(),
266 static_cast<_Args&&>(__args)...);
267 }
268
269 template <same_as<get_env_t> _Tag, class _SexprTag = __tag_t>
270 STDEXEC_ATTRIBUTE((always_inline))
tag_invokestdexec::__detail::__receiver271 friend auto tag_invoke(_Tag, const __t& __self) noexcept
272 -> __env_type_t<_SexprTag, _Idx, _Sexpr, _Receiver>
273 {
274 return __self.__op_->__get_env(_Idx());
275 }
276 };
277 };
278
279 template <class _Receiver>
280 using __sexpr_connected_with =
281 __mapply<__mbind_front_q<__m_at, typename _Receiver::__index>,
282 typename __call_result_t<__impl_of<typename _Receiver::__sexpr>,
283 __cp, __get_desc>::__children>;
284
285 template <class _Sexpr, class _Receiver>
286 struct __op_base : __immovable
287 {
288 using __tag_t = typename __decay_t<_Sexpr>::__tag_t;
289 using __state_t = __state_type_t<__tag_t, _Sexpr, _Receiver>;
290
291 STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS _Receiver __rcvr_;
292 STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS __state_t __state_;
293
__op_basestdexec::__detail::__op_base294 __op_base(_Sexpr&& __sndr, _Receiver&& __rcvr) :
295 __rcvr_(static_cast<_Receiver&&>(__rcvr)),
296 __state_(__sexpr_impl<__tag_t>::get_state(static_cast<_Sexpr&&>(__sndr),
297 __rcvr_))
298 {}
299
__rcvrstdexec::__detail::__op_base300 auto __rcvr() & noexcept -> _Receiver&
301 {
302 return __rcvr_;
303 }
304 };
305
306 // template <class _Sexpr, class _Receiver>
307 // requires __is_instance_of<__id<_Receiver>, __receiver>
308 // && __decays_to<_Sexpr, __sexpr_connected_with<_Receiver>>
309 // struct __op_base<_Sexpr, _Receiver> : __immovable {
310 // using __tag_t = typename __decay_t<_Sexpr>::__tag_t;
311 // using __state_t = __state_type_t<__tag_t, _Sexpr, _Receiver>;
312
313 // STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS __state_t __state_;
314
315 // __op_base(_Sexpr&& __sndr, _Receiver&& __rcvr)
316 // :
317 // __state_(__sexpr_impl<__tag_t>::get_state(static_cast<_Sexpr&&>(__sndr),
318 // __rcvr)) { STDEXEC_ASSERT(this->__rcvr().__op_ == __rcvr.__op_);
319 // }
320
321 // _Receiver __rcvr() const noexcept {
322 // return _Receiver::__from_op_state( //
323 // static_cast<__op_state<_Sexpr, _Receiver>*>( //
324 // const_cast<__op_base*>(this)));
325 // }
326 // };
327
328 STDEXEC_PRAGMA_PUSH()
329 STDEXEC_PRAGMA_IGNORE_GNU("-Winvalid-offsetof")
330 STDEXEC_PRAGMA_IGNORE_EDG(offset_in_non_POD_nonstandard)
331
332 template <class _Sexpr, class _Receiver>
333 struct __enable_receiver_from_this
334 {
335 using __op_base_t = __op_base<_Sexpr, _Receiver>;
336
__receiverstdexec::__detail::__enable_receiver_from_this337 auto __receiver() noexcept -> decltype(auto)
338 {
339 using __derived_t = decltype(__op_base_t::__state_);
340 auto* __derived = static_cast<__derived_t*>(this);
341 constexpr std::size_t __offset = offsetof(__op_base_t, __state_);
342 auto* __base = reinterpret_cast<__op_base_t*>(
343 reinterpret_cast<char*>(__derived) - __offset);
344 return __base->__rcvr();
345 }
346 };
347
348 STDEXEC_PRAGMA_POP()
349
350 STDEXEC_PRAGMA_PUSH()
351 STDEXEC_PRAGMA_IGNORE_GNU("-Wmissing-braces")
352
353 template <class _Sexpr, class _Receiver>
354 struct __connect_fn
355 {
356 template <std::size_t _Idx>
357 using __receiver_t =
358 __t<__receiver<__id<_Receiver>, _Sexpr, __mconstant<_Idx>>>;
359
360 __op_state<_Sexpr, _Receiver>* __op_;
361
362 struct __impl
363 {
364 __op_state<_Sexpr, _Receiver>* __op_;
365
366 template <std::size_t... _Is, class _Tag, class _Data, class... _Child>
operator ()stdexec::__detail::__connect_fn::__impl367 auto operator()(__indices<_Is...>, _Tag, _Data&&,
368 _Child&&... __child) const
369 -> __tup::__tuple<__indices<_Is...>,
370 connect_result_t<_Child, __receiver_t<_Is>>...>
371 {
372 return __tuple{connect(static_cast<_Child&&>(__child),
373 __receiver_t<_Is>{__op_})...};
374 }
375 };
376
377 template <class _Tag, class _Data, class... _Child>
operator ()stdexec::__detail::__connect_fn378 auto operator()(_Tag, _Data&& __data, _Child&&... __child) const
379 -> __call_result_t<__impl, __indices_for<_Child...>, _Tag, _Data,
380 _Child...>
381 {
382 return __impl{__op_}(__indices_for<_Child...>(), _Tag(),
383 static_cast<_Data&&>(__data),
384 static_cast<_Child&&>(__child)...);
385 }
386 };
387 STDEXEC_PRAGMA_POP()
388
389 template <class _Sexpr, class _Receiver>
390 struct __op_state : __op_base<_Sexpr, _Receiver>
391 {
392 using __desc_t = typename __decay_t<_Sexpr>::__desc_t;
393 using __tag_t = typename __desc_t::__tag;
394 using __data_t = typename __desc_t::__data;
395 using __children_t = typename __desc_t::__children;
396 using __state_t = typename __op_state::__state_t;
397 using __inner_ops_t =
398 __result_of<__sexpr_apply, _Sexpr, __connect_fn<_Sexpr, _Receiver>>;
399
400 __inner_ops_t __inner_ops_;
401
402 // template <std::size_t _Idx>
403 // static std::ptrdiff_t __get_child_op_offset() noexcept {
404 // __op_state* __self = (__op_state*) &__self;
405 // return (std::ptrdiff_t)((char*)
406 // &__tup::__get<_Idx>(__self->__inner_ops_) -
407 // static_cast<char*>(__self));
408 // }
409
__op_statestdexec::__detail::__op_state410 __op_state(_Sexpr&& __sexpr, _Receiver __rcvr) :
411 __op_state::__op_base{static_cast<_Sexpr&&>(__sexpr),
412 static_cast<_Receiver&&>(__rcvr)},
413 __inner_ops_(__sexpr_apply(static_cast<_Sexpr&&>(__sexpr),
414 __connect_fn<_Sexpr, _Receiver>{this}))
415 {}
416
417 template <same_as<start_t> _Tag2>
418 STDEXEC_ATTRIBUTE((always_inline))
tag_invoke(_Tag2,__op_state & __self)419 friend void tag_invoke(_Tag2, __op_state& __self) noexcept
420 {
421 using __tag_t = typename __op_state::__tag_t;
422 auto&& __rcvr = __self.__rcvr();
423 __tup::__apply(
424 [&](auto&... __ops) noexcept {
425 __sexpr_impl<__tag_t>::start(__self.__state_, __rcvr, __ops...);
426 },
427 __self.__inner_ops_);
428 }
429
430 template <class _Index, class _Tag2, class... _Args>
431 STDEXEC_ATTRIBUTE((always_inline))
__completestdexec::__detail::__op_state432 void __complete(_Index, _Tag2, _Args&&... __args) noexcept
433 {
434 using __tag_t = typename __op_state::__tag_t;
435 auto&& __rcvr = this->__rcvr();
436 __sexpr_impl<__tag_t>::complete(_Index(), this->__state_, __rcvr,
437 _Tag2(),
438 static_cast<_Args&&>(__args)...);
439 }
440
441 template <class _Index>
442 STDEXEC_ATTRIBUTE((always_inline))
__get_envstdexec::__detail::__op_state443 auto __get_env(_Index) noexcept
444 -> __env_type_t<__tag_t, _Index, _Sexpr, _Receiver>
445 {
446 const auto& __rcvr = this->__rcvr();
447 return __sexpr_impl<__tag_t>::get_env(_Index(), this->__state_, __rcvr);
448 }
449 };
450
451 inline constexpr auto __drop_front = //
452 []<class _Fn>(_Fn __fn) noexcept {
453 return
454 [__fn = std::move(__fn)]<class... _Rest>(
455 auto&&, _Rest&&... __rest) noexcept(__nothrow_callable<const _Fn&,
456 _Rest...>)
457 -> __call_result_t<const _Fn&, _Rest...> {
458 return __fn(static_cast<_Rest&&>(__rest)...);
459 };
460 };
461
462 template <class _Tag, class... _Captures>
463 STDEXEC_ATTRIBUTE((host, device, always_inline))
__captures(_Tag,_Captures &&...__captures2)464 constexpr auto __captures(_Tag, _Captures&&... __captures2)
465 {
466 return
467 [... __captures3 = static_cast<_Captures&&>(
468 __captures2)]<class _Cvref, class _Fun>(_Cvref,
469 _Fun&& __fun) mutable //
470 noexcept(
471 __nothrow_callable<_Fun, _Tag, __minvoke<_Cvref, _Captures>...>) //
472 -> __call_result_t<_Fun, _Tag, __minvoke<_Cvref, _Captures>...>
473 requires __callable<_Fun, _Tag, __minvoke<_Cvref, _Captures>...>
474 {
475 // The use of decltype(__captures3) here instead of _Captures is a
476 // workaround for a codegen bug in nvc++.
477 return static_cast<_Fun&&>(__fun)(
478 _Tag(), const_cast<__minvoke<_Cvref, decltype(__captures3)>&&>(
479 __captures3)...);
480 };
481 }
482
483 template <class _Sender>
484 concept __non_dependent_sender = //
485 requires { typename _Sender::completion_signatures; } ||
486 requires { requires _Sender::__is_non_dependent(); };
487
488 template <class _Tag, class... _Child>
489 concept __is_non_dependent_sexpr = //
490 !requires { typename __sexpr_impl<_Tag>::is_dependent; } &&
491 (__non_dependent_sender<_Child> && ...);
492
493 template <class _Tag, class _Data, class... _Child>
494 using __is_non_dependent_t = __mbool<__is_non_dependent_sexpr<_Tag, _Child...>>;
495
496 template <class _Tag, class _Data, class... _Child>
497 using __captures_t = decltype(__detail::__captures(_Tag(), __declval<_Data>(),
498 __declval<_Child>()...));
499
500 template <class, class, class... _Child>
501 using __tuple_size_t = char[sizeof...(_Child) + 2];
502
503 template <std::size_t _Idx, class _Descriptor>
504 concept __in_range =
505 (_Idx < sizeof(__minvoke<_Descriptor, __q<__tuple_size_t>>));
506
507 } // namespace __detail
508
509 struct __sexpr_defaults
510 {
511 static constexpr auto get_attrs = __detail::__get_attrs;
512 static constexpr auto get_env = __detail::__get_env;
513 static constexpr auto get_state = __detail::__get_state;
514 static constexpr auto connect = __detail::__connect;
515 static constexpr auto start = __detail::__start;
516 static constexpr auto complete = __detail::__complete;
517 static constexpr auto get_completion_signatures =
518 __detail::__get_completion_signatures;
519 };
520
521 template <class _Tag>
522 struct __sexpr_impl : __sexpr_defaults
523 {};
524
525 using __detail::__enable_receiver_from_this;
526
527 template <class _Tag>
528 using __get_attrs_fn = __result_of<__detail::__drop_front,
529 __mtypeof<__sexpr_impl<_Tag>::get_attrs>>;
530
531 //////////////////////////////////////////////////////////////////////////////////////////////////
532 // __basic_sender
533 template <class...>
534 struct __basic_sender
535 {
536 using __id = __basic_sender;
537 using __t = __basic_sender;
538 };
539
540 template <auto _DescriptorFn, class = __anon>
541 struct __sexpr
542 {
543 using sender_concept = sender_t;
544
545 using __id = __sexpr;
546 using __t = __sexpr;
547 using __desc_t = decltype(_DescriptorFn());
548 using __tag_t = typename __desc_t::__tag;
549 using __captures_t = __minvoke<__desc_t, __q<__detail::__captures_t>>;
550
__is_non_dependentstdexec::__sexpr551 static constexpr auto __is_non_dependent() noexcept -> bool
552 {
553 return __v<__minvoke<__desc_t, __q<__detail::__is_non_dependent_t>>>;
554 }
555
556 mutable __captures_t __impl_;
557
558 template <class _Tag, class _Data, class... _Child>
559 STDEXEC_ATTRIBUTE((host, device, always_inline))
__sexprstdexec::__sexpr560 explicit __sexpr(_Tag, _Data&& __data, _Child&&... __child) :
561 __impl_(__detail::__captures(_Tag(), static_cast<_Data&&>(__data),
562 static_cast<_Child&&>(__child)...))
563 {}
564
565 template <class _Tag>
566 using __impl = __sexpr_impl<__meval<__msecond, _Tag, __tag_t>>;
567
568 template <same_as<get_env_t> _Tag, same_as<__sexpr> _Self>
569 STDEXEC_ATTRIBUTE((always_inline))
tag_invoke(_Tag,const _Self & __self)570 friend auto tag_invoke(_Tag, const _Self& __self) noexcept //
571 -> __msecond<
572 __if_c<same_as<_Tag, get_env_t> && same_as<_Self, __sexpr>>, //
573 __result_of<__sexpr_apply, const _Self&, __get_attrs_fn<__tag_t>>>
574 {
575 return __sexpr_apply(__self,
576 __detail::__drop_front(__impl<_Tag>::get_attrs));
577 }
578
579 template <same_as<get_completion_signatures_t> _Tag,
580 __decays_to<__sexpr> _Self, class _Env>
581 STDEXEC_ATTRIBUTE((always_inline))
tag_invoke(_Tag,_Self && __self,_Env && __env)582 friend auto tag_invoke(_Tag, _Self&& __self, _Env&& __env) noexcept //
583 -> __msecond<
584 __if_c<same_as<_Tag, get_completion_signatures_t> &&
585 __decays_to<_Self, __sexpr>>,
586 __result_of<__impl<_Tag>::get_completion_signatures, _Self, _Env>>
587 {
588 return {};
589 }
590
591 // BUGBUG fix receiver constraint here:
592 template <same_as<connect_t> _Tag, __decays_to<__sexpr> _Self,
593 /*receiver*/ class _Receiver>
594 STDEXEC_ATTRIBUTE((always_inline))
tag_invoke(_Tag,_Self && __self,_Receiver && __rcvr)595 friend auto tag_invoke(_Tag, _Self&& __self, _Receiver&& __rcvr) //
596 noexcept(noexcept(__impl<_Tag>::connect(
597 static_cast<_Self&&>(__self), static_cast<_Receiver&&>(__rcvr)))) //
598 -> __msecond<
599 __if_c<same_as<_Tag, connect_t> && __decays_to<_Self, __sexpr>>,
600 __result_of<__impl<_Tag>::connect, _Self, _Receiver>>
601 {
602 return __impl<_Tag>::connect(static_cast<_Self&&>(__self),
603 static_cast<_Receiver&&>(__rcvr));
604 }
605
606 template <class _Sender, class _ApplyFn>
607 STDEXEC_ATTRIBUTE((always_inline))
STDEXEC_DEFINE_EXPLICIT_THIS_MEMFNstdexec::__sexpr608 STDEXEC_DEFINE_EXPLICIT_THIS_MEMFN(auto apply)(
609 this _Sender&& __sndr,
610 _ApplyFn&&
611 __fun) noexcept(__nothrow_callable<__detail::__impl_of<_Sender>,
612 __copy_cvref_fn<_Sender>,
613 _ApplyFn>) //
614 -> __call_result_t<__detail::__impl_of<_Sender>,
615 __copy_cvref_fn<_Sender>, _ApplyFn>
616 { //
617 return static_cast<_Sender&&>(__sndr).__impl_(
618 __copy_cvref_fn<_Sender>(), static_cast<_ApplyFn&&>(__fun)); //
619 }
620
621 template <std::size_t _Idx, __decays_to_derived_from<__sexpr> _Self>
622 STDEXEC_ATTRIBUTE((always_inline))
get(_Self && __self)623 friend decltype(auto) get(_Self&& __self) noexcept
624 requires __detail::__in_range<_Idx, __desc_t>
625 {
626 if constexpr (_Idx == 0)
627 {
628 return __tag_t();
629 }
630 else
631 {
632 return __self.__impl_(__copy_cvref_fn<_Self>(),
633 __nth_pack_element<_Idx>);
634 }
635 }
636 };
637
638 namespace
639 {
640 template <class _Descriptor, auto _DescriptorFn = [] { return _Descriptor(); }>
641 inline constexpr auto __descriptor_fn_v = _DescriptorFn;
642
643 template <class _Tag, class _Data, class... _Child>
__descriptor_fn()644 inline constexpr auto __descriptor_fn()
645 {
646 return __descriptor_fn_v<__detail::__desc<_Tag, _Data, _Child...>>;
647 }
648 } // namespace
649
650 #if STDEXEC_NVHPC()
651 #define STDEXEC_SEXPR_DESCRIPTOR(_Tag, _Data, _Child) \
652 stdexec::__descriptor_fn<_Tag, _Data, _Child>()
653 #else
654 #define STDEXEC_SEXPR_DESCRIPTOR(_Tag, _Data, _Child) \
655 stdexec::__descriptor_fn_v<stdexec::__detail::__desc<_Tag, _Data, _Child>>
656 #endif
657
658 template <class _Tag, class _Data, class... _Child>
659 STDEXEC_ATTRIBUTE((host, device))
660 __sexpr(_Tag, _Data, _Child...)
661 -> __sexpr<STDEXEC_SEXPR_DESCRIPTOR(_Tag, _Data, _Child...)>;
662
663 template <class _Tag, class _Data, class... _Child>
664 using __sexpr_t = __sexpr<STDEXEC_SEXPR_DESCRIPTOR(_Tag, _Data, _Child...)>;
665
666 //////////////////////////////////////////////////////////////////////////////////////////////////
667 // __make_sexpr
668 namespace __detail
669 {
670 template <class _Tag>
671 struct __make_sexpr_t
672 {
673 template <class _Data = __, class... _Child>
operator ()stdexec::__detail::__make_sexpr_t674 constexpr auto operator()(_Data __data = {}, _Child... __child) const
675 {
676 return __sexpr_t<_Tag, _Data, _Child...>{
677 _Tag(), static_cast<_Data&&>(__data),
678 static_cast<_Child&&>(__child)...};
679 }
680 };
681 } // namespace __detail
682
683 template <class _Tag>
684 inline constexpr __detail::__make_sexpr_t<_Tag> __make_sexpr{};
685
686 namespace __detail
687 {
688 struct __sexpr_apply_t
689 {
690 template <class _Sender, class _ApplyFn>
691 STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__detail::__sexpr_apply_t692 auto operator()(_Sender&& __sndr, _ApplyFn&& __fun) const
693 noexcept(noexcept(STDEXEC_CALL_EXPLICIT_THIS_MEMFN(
694 (static_cast<_Sender&&>(__sndr)),
695 apply)(static_cast<_ApplyFn&&>(__fun)))) //
696 -> decltype(STDEXEC_CALL_EXPLICIT_THIS_MEMFN(
697 (static_cast<_Sender&&>(__sndr)),
698 apply)(static_cast<_ApplyFn&&>(__fun)))
699 {
700 return STDEXEC_CALL_EXPLICIT_THIS_MEMFN(
701 (static_cast<_Sender&&>(__sndr)),
702 apply)(static_cast<_ApplyFn&&>(__fun)); //
703 }
704 };
705 } // namespace __detail
706
707 using __detail::__sexpr_apply_t;
708 inline constexpr __sexpr_apply_t __sexpr_apply{};
709
710 template <class _Sender, class _ApplyFn>
711 using __sexpr_apply_result_t =
712 __call_result_t<__sexpr_apply_t, _Sender, _ApplyFn>;
713
714 template <class _Sender>
715 concept sender_expr = //
716 __mvalid<tag_of_t, _Sender>;
717
718 template <class _Sender, class _Tag>
719 concept sender_expr_for = //
720 sender_expr<_Sender> && same_as<tag_of_t<_Sender>, _Tag>;
721
722 // The __name_of utility defined below is used to pretty-print the type names of
723 // senders in compiler diagnostics.
724 namespace __detail
725 {
726 struct __basic_sender_name
727 {
728 template <class _Tag, class _Data, class... _Child>
729 using __result = __basic_sender<_Tag, _Data, __name_of<_Child>...>;
730
731 template <class _Sender>
732 using __f = __minvoke<typename __decay_t<_Sender>::__desc_t, __q<__result>>;
733 };
734
735 struct __id_name
736 {
737 template <class _Sender>
738 using __f = __name_of<__id<_Sender>>;
739 };
740
741 template <class _Sender>
742 extern __mcompose<__cplr, __name_of_fn<_Sender>> __name_of_v<_Sender&>;
743
744 template <class _Sender>
745 extern __mcompose<__cprr, __name_of_fn<_Sender>> __name_of_v<_Sender&&>;
746
747 template <class _Sender>
748 extern __mcompose<__cpclr, __name_of_fn<_Sender>> __name_of_v<const _Sender&>;
749
750 template <auto _Descriptor>
751 extern __basic_sender_name __name_of_v<__sexpr<_Descriptor>>;
752
753 template <__has_id _Sender>
754 requires(!same_as<__id<_Sender>, _Sender>)
755 extern __id_name __name_of_v<_Sender>;
756 } // namespace __detail
757 } // namespace stdexec
758
759 namespace std
760 {
761 template <auto _Descriptor>
762 struct tuple_size<stdexec::__sexpr<_Descriptor>> :
763 integral_constant<size_t,
764 stdexec::__v<stdexec::__minvoke<
765 stdexec::__result_of<_Descriptor>, stdexec::__msize>>>
766 {};
767
768 template <size_t _Idx, auto _Descriptor>
769 struct tuple_element<_Idx, stdexec::__sexpr<_Descriptor>>
770 {
771 using type = //
772 stdexec::__remove_rvalue_reference_t< //
773 stdexec::__call_result_t< //
774 stdexec::__detail::__impl_of<stdexec::__sexpr<_Descriptor>>,
775 stdexec::__cp, stdexec::__nth_pack_element_t<_Idx>>>;
776 };
777 } // namespace std
778