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