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 "__concepts.hpp"
19 #include "__diagnostics.hpp"
20 #include "__env.hpp"
21 #include "__execution_fwd.hpp"
22 #include "__manual_lifetime.hpp"
23 #include "__meta.hpp"
24 #include "__sender_introspection.hpp"
25 #include "__senders_core.hpp"
26 #include "__tuple.hpp"
27 #include "__type_traits.hpp"
28
29 #include <cstddef>
30 #include <type_traits>
31 #include <utility> // for tuple_size/tuple_element
32
33 namespace stdexec
34 {
35 /////////////////////////////////////////////////////////////////////////////
36 // Generic __sender type
37 namespace __detail
38 {
39 template <class _Sender>
40 using __impl_of = decltype((__declval<_Sender>().__impl_));
41
42 struct __get_data
43 {
44 template <class _Data>
45 STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__detail::__get_data46 _Data&& operator()(__ignore, _Data&& __data, auto&&...) const noexcept
47 {
48 return static_cast<_Data&&>(__data);
49 }
50 };
51 } // namespace __detail
52
53 namespace
54 {
55 template <class _Descriptor, auto _DescriptorFn = [] { return _Descriptor(); }>
56 inline constexpr auto __descriptor_fn_v = _DescriptorFn;
57
58 template <class _Tag, class _Data, class... _Child>
__descriptor_fn()59 inline constexpr auto __descriptor_fn()
60 {
61 return __descriptor_fn_v<__detail::__desc<_Tag, _Data, _Child...>>;
62 }
63 } // namespace
64
65 #if STDEXEC_EDG()
66 #define STDEXEC_SEXPR_DESCRIPTOR(_Tag, _Data, _Child) \
67 stdexec::__descriptor_fn<_Tag, _Data, _Child>()
68 #else
69 #define STDEXEC_SEXPR_DESCRIPTOR(_Tag, _Data, _Child) \
70 stdexec::__descriptor_fn_v<stdexec::__detail::__desc<_Tag, _Data, _Child>>
71 #endif
72
73 template <class _Tag>
74 struct __sexpr_impl;
75
76 namespace __detail
77 {
78 template <class _Sexpr, class _Receiver>
79 struct __op_state;
80
81 template <class _Sexpr, class _Receiver>
82 struct __connect_fn;
83
84 template <class _Tag, class _Sexpr, class _Receiver>
85 using __state_type_t =
86 __decay_t<__result_of<__sexpr_impl<_Tag>::get_state, _Sexpr, _Receiver&>>;
87
88 template <class _Self, class _Tag, class _Index, class _Sexpr, class _Receiver>
89 using __env_type_t = __result_of<
90 __sexpr_impl<__meval<__msecond, _Self, _Tag>>::get_env, _Index,
91 __state_type_t<__meval<__msecond, _Self, _Tag>, _Sexpr, _Receiver>&,
92 _Receiver&>;
93
94 template <class _Sexpr, class _Receiver>
95 concept __connectable =
96 __callable<__impl_of<_Sexpr>, __copy_cvref_fn<_Sexpr>,
97 __connect_fn<_Sexpr, _Receiver>> &&
98 __mvalid<__state_type_t, tag_of_t<_Sexpr>, _Sexpr, _Receiver>;
99
100 // // Note: This is UB. UBSAN allows it for now.
101 // template <class _Parent, class _Child>
102 // _Parent* __parent_from_child(_Child* __child, _Child _Parent::*__mbr_ptr)
103 // noexcept {
104 // alignas(_Parent) char __buf[sizeof(_Parent)];
105 // _Parent* __parent = (_Parent*) &__buf;
106 // const std::ptrdiff_t __offset = (char*) &(__parent->*__mbr_ptr) - __buf;
107 // return (_Parent*) (static_cast<char*>(__child) - __offset);
108 // }
109
110 inline constexpr auto __get_attrs = //
111 [](__ignore, const auto&... __child) noexcept -> decltype(auto) {
112 if constexpr (sizeof...(__child) == 1)
113 {
114 return stdexec::get_env(
115 __child...); // BUGBUG: should be only the forwarding queries
116 }
117 else
118 {
119 return empty_env();
120 }
121 };
122
123 inline constexpr auto __get_env = //
124 []<class _Receiver>(__ignore, __ignore, const _Receiver& __rcvr) noexcept
125 -> env_of_t<const _Receiver&> { return stdexec::get_env(__rcvr); };
126
127 inline constexpr auto __get_state = //
128 []<class _Sender>(_Sender&& __sndr, __ignore) noexcept -> decltype(auto) {
129 return __sndr.apply(static_cast<_Sender&&>(__sndr), __get_data());
130 };
131
132 inline constexpr auto __connect = //
133 []<class _Sender, class _Receiver>(_Sender&& __sndr, _Receiver __rcvr) //
134 noexcept(__nothrow_constructible_from<__op_state<_Sender, _Receiver>,
135 _Sender, _Receiver>)
136 -> __op_state<_Sender, _Receiver>
137 requires __connectable<_Sender, _Receiver>
138 {
139 return __op_state<_Sender, _Receiver>{static_cast<_Sender&&>(__sndr),
140 static_cast<_Receiver&&>(__rcvr)};
141 };
142
143 inline constexpr auto __start = //
144 []<class _StartTag = start_t, class... _ChildOps>(
145 __ignore, __ignore, _ChildOps&... __ops) noexcept {
146 (_StartTag()(__ops), ...);
147 };
148
149 inline constexpr auto __complete = //
150 []<class _Index, class _Receiver, class _SetTag, class... _Args>(
151 _Index, __ignore, _Receiver& __rcvr, _SetTag,
152 _Args&&... __args) noexcept {
153 static_assert(__v<_Index> == 0,
154 "I don't know how to complete this operation.");
155 _SetTag()(std::move(__rcvr), static_cast<_Args&&>(__args)...);
156 };
157
158 inline constexpr auto __sigs = //
159 []<class _Sender>(_Sender&& __sndr, __ignore = {}) noexcept {
160 static_assert(
161 __mnever<tag_of_t<_Sender>>,
162 "No customization of get_completion_signatures for this sender tag type.");
163 };
164
165 template <class _ReceiverId, class _Sexpr, class _Idx>
166 struct __receiver
167 {
168 struct __t
169 {
170 using receiver_concept = receiver_t;
171 using _Receiver = stdexec::__t<_ReceiverId>;
172 using __sexpr = _Sexpr;
173 using __index = _Idx;
174 using __id = __receiver;
175 using __parent_op_t = __op_state<_Sexpr, _Receiver>;
176 using __tag_t = tag_of_t<_Sexpr>;
177
178 // A pointer to the parent operation state, which contains the one
179 // created with this receiver.
180 __parent_op_t* __op_;
181
182 // template <class _ChildSexpr, class _ChildReceiver>
183 // static __t __from_op_state(__op_state<_ChildSexpr, _ChildReceiver>*
184 // __child) noexcept {
185 // using __parent_op_t = __op_state<_Sexpr, _Receiver>;
186 // std::ptrdiff_t __offset = __parent_op_t::template
187 // __get_child_op_offset<__v<_Idx>>();
188 // __parent_op_t* __parent = (__parent_op_t*)
189 // (static_cast<char*>(__child) - __offset); return __t{__parent};
190 // }
191
192 template <class... _Args>
193 STDEXEC_ATTRIBUTE((always_inline))
set_valuestdexec::__detail::__receiver::__t194 void set_value(_Args&&... __args) noexcept
195 {
196 __op_->__complete(_Idx(), stdexec::set_value,
197 static_cast<_Args&&>(__args)...);
198 }
199
200 template <class _Error>
201 STDEXEC_ATTRIBUTE((always_inline))
set_errorstdexec::__detail::__receiver::__t202 void set_error(_Error&& __err) noexcept
203 {
204 __op_->__complete(_Idx(), stdexec::set_error,
205 static_cast<_Error&&>(__err));
206 }
207
208 STDEXEC_ATTRIBUTE((always_inline))
set_stoppedstdexec::__detail::__receiver::__t209 void set_stopped() noexcept
210 {
211 __op_->__complete(_Idx(), stdexec::set_stopped);
212 }
213
214 template <__same_as<__t> _Self = __t>
215 STDEXEC_ATTRIBUTE((always_inline))
get_envstdexec::__detail::__receiver::__t216 auto get_env() const noexcept
217 -> __env_type_t<_Self, __tag_t, _Idx, _Sexpr, _Receiver>
218 {
219 return __op_->__get_env(_Idx());
220 }
221 };
222 };
223
224 // template <class _Receiver>
225 // using __sexpr_connected_with = __mapply<
226 // __mbind_front_q<__m_at, typename _Receiver::__index>,
227 // typename __call_result_t<__impl_of<typename _Receiver::__sexpr>, __cp,
228 // __get_desc>::__children>;
229
230 template <class _Sexpr, class _Receiver>
231 using __state_t = //
232 __state_type_t<typename __decay_t<_Sexpr>::__tag_t, _Sexpr, _Receiver>;
233
234 template <class _Sexpr, class _Receiver>
235 struct __op_base;
236
237 template <class _Receiver>
238 struct __receiver_box
239 {
240 _Receiver __rcvr_;
241
242 STDEXEC_ATTRIBUTE((always_inline))
__rcvrstdexec::__detail::__receiver_box243 auto __rcvr() & noexcept -> _Receiver&
244 {
245 return this->__rcvr_;
246 }
247
248 STDEXEC_ATTRIBUTE((always_inline))
__rcvrstdexec::__detail::__receiver_box249 auto __rcvr() const& noexcept -> const _Receiver&
250 {
251 return this->__rcvr_;
252 }
253 };
254
255 template <class _Sexpr, class _Receiver>
256 struct __state_box
257 {
258 using __tag_t = typename __decay_t<_Sexpr>::__tag_t;
259 using __state_t = __state_type_t<__tag_t, _Sexpr, _Receiver>;
260
__state_boxstdexec::__detail::__state_box261 __state_box(_Sexpr&& __sndr, _Receiver& __rcvr) //
262 noexcept(__nothrow_callable<decltype(__sexpr_impl<__tag_t>::get_state),
263 _Sexpr, _Receiver>) :
264 __state_(__sexpr_impl<__tag_t>::get_state(static_cast<_Sexpr&&>(__sndr),
265 __rcvr))
266 {}
267
268 __state_t __state_;
269 };
270
271 template <class _Sexpr, class _Receiver, class _State>
272 struct __enable_receiver_from_this
273 {
274 #if STDEXEC_HAS_FEATURE(undefined_behavior_sanitizer) && STDEXEC_CLANG()
275 // See https://github.com/llvm/llvm-project/issues/101276
276 [[clang::noinline]]
277 #endif
__receiverstdexec::__detail::__enable_receiver_from_this278 auto __receiver() noexcept -> decltype(auto)
279 {
280 void* __state = static_cast<_State*>(this);
281 auto* __sbox = static_cast<__state_box<_Sexpr, _Receiver>*>(__state);
282 return (static_cast<__op_base<_Sexpr, _Receiver>*>(__sbox)->__rcvr_);
283 }
284 };
285
286 template <class _Sexpr, class _Receiver>
287 concept __state_uses_receiver = //
288 derived_from<__state_t<_Sexpr, _Receiver>,
289 __enable_receiver_from_this<_Sexpr, _Receiver,
290 __state_t<_Sexpr, _Receiver>>>;
291
292 template <class _Sexpr, class _Receiver>
293 struct __op_base : __immovable
294 {
295 using __tag_t = typename __decay_t<_Sexpr>::__tag_t;
296 using __state_t = __state_type_t<__tag_t, _Sexpr, _Receiver>;
297
298 STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS
299 _Receiver __rcvr_;
300 STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS
301 __state_t __state_;
302
__op_basestdexec::__detail::__op_base303 __op_base(_Sexpr&& __sndr, _Receiver&& __rcvr) //
304 noexcept(__nothrow_decay_copyable<_Receiver> &&
305 __nothrow_callable<decltype(__sexpr_impl<__tag_t>::get_state),
306 _Sexpr, _Receiver>) :
307 __rcvr_(static_cast<_Receiver&&>(__rcvr)),
308 __state_(__sexpr_impl<__tag_t>::get_state(static_cast<_Sexpr&&>(__sndr),
309 __rcvr_))
310 {}
311
312 STDEXEC_ATTRIBUTE((always_inline))
__rcvrstdexec::__detail::__op_base313 auto __rcvr() & noexcept -> _Receiver&
314 {
315 return __rcvr_;
316 }
317
318 STDEXEC_ATTRIBUTE((always_inline))
__rcvrstdexec::__detail::__op_base319 auto __rcvr() const& noexcept -> const _Receiver&
320 {
321 return __rcvr_;
322 }
323 };
324
325 template <class _Sexpr, class _Receiver>
326 requires __state_uses_receiver<_Sexpr, _Receiver>
327 struct __op_base<_Sexpr, _Receiver> :
328 __receiver_box<_Receiver>,
329 __state_box<_Sexpr, _Receiver>
330 {
331 using __tag_t = typename __decay_t<_Sexpr>::__tag_t;
332 using __state_t = __state_type_t<__tag_t, _Sexpr, _Receiver>;
333
334 STDEXEC_IMMOVABLE(__op_base);
335
__op_basestdexec::__detail::__op_base336 __op_base(_Sexpr&& __sndr, _Receiver&& __rcvr) //
337 noexcept(__nothrow_decay_copyable<_Receiver> &&
338 __nothrow_move_constructible<__state_t>) :
339 __receiver_box<_Receiver>{static_cast<_Receiver&&>(__rcvr)},
340 __state_box<_Sexpr, _Receiver>{static_cast<_Sexpr&&>(__sndr),
341 this->__rcvr_}
342 {}
343 };
344
345 // template <class _Sexpr, class _Receiver>
346 // requires __is_instance_of<__id<_Receiver>, __receiver>
347 // && __decays_to<_Sexpr, __sexpr_connected_with<_Receiver>>
348 // struct __op_base<_Sexpr, _Receiver> : __immovable {
349 // using __tag_t = typename __decay_t<_Sexpr>::__tag_t;
350 // using __state_t = __state_type_t<__tag_t, _Sexpr, _Receiver>;
351
352 // STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS __state_t __state_;
353
354 // __op_base(_Sexpr&& __sndr, _Receiver&& __rcvr)
355 // :
356 // __state_(__sexpr_impl<__tag_t>::get_state(static_cast<_Sexpr&&>(__sndr),
357 // __rcvr)) { STDEXEC_ASSERT(this->__rcvr().__op_ == __rcvr.__op_);
358 // }
359
360 // _Receiver __rcvr() const noexcept {
361 // return _Receiver::__from_op_state( //
362 // static_cast<__op_state<_Sexpr, _Receiver>*>( //
363 // const_cast<__op_base*>(this)));
364 // }
365 // };
366
367 STDEXEC_PRAGMA_PUSH()
368 STDEXEC_PRAGMA_IGNORE_GNU("-Wmissing-braces")
369
370 template <class _Sexpr, class _Receiver>
371 struct __connect_fn
372 {
373 template <std::size_t _Idx>
374 using __receiver_t =
375 __t<__receiver<__id<_Receiver>, _Sexpr, __msize_t<_Idx>>>;
376
377 __op_state<_Sexpr, _Receiver>* __op_;
378
379 struct __impl
380 {
381 __op_state<_Sexpr, _Receiver>* __op_;
382
383 template <std::size_t... _Is, class... _Child>
operator ()stdexec::__detail::__connect_fn::__impl384 auto operator()(__indices<_Is...>, _Child&&... __child) const
385 noexcept((__nothrow_connectable<_Child, __receiver_t<_Is>> && ...))
386 -> __tuple_for<connect_result_t<_Child, __receiver_t<_Is>>...>
387 {
388 return __tuple{connect(static_cast<_Child&&>(__child),
389 __receiver_t<_Is>{__op_})...};
390 }
391 };
392
393 template <class... _Child>
operator ()stdexec::__detail::__connect_fn394 auto operator()(__ignore, __ignore, _Child&&... __child) const noexcept(
395 __nothrow_callable<__impl, __indices_for<_Child...>, _Child...>)
396 -> __call_result_t<__impl, __indices_for<_Child...>, _Child...>
397 {
398 return __impl{__op_}(__indices_for<_Child...>(),
399 static_cast<_Child&&>(__child)...);
400 }
401
operator ()stdexec::__detail::__connect_fn402 auto operator()(__ignore, __ignore) const noexcept -> __tuple_for<>
403 {
404 return {};
405 }
406 };
407 STDEXEC_PRAGMA_POP()
408
409 template <class _Sexpr, class _Receiver>
410 struct __op_state : __op_base<_Sexpr, _Receiver>
411 {
412 using __desc_t = typename __decay_t<_Sexpr>::__desc_t;
413 using __tag_t = typename __desc_t::__tag;
414 using __data_t = typename __desc_t::__data;
415 // using __children_t = typename __desc_t::__children;
416 using __state_t = typename __op_state::__state_t;
417 using __inner_ops_t =
418 __result_of<__sexpr_apply, _Sexpr, __connect_fn<_Sexpr, _Receiver>>;
419
420 __inner_ops_t __inner_ops_;
421
422 // template <std::size_t _Idx>
423 // static std::ptrdiff_t __get_child_op_offset() noexcept {
424 // __op_state* __self = (__op_state*) &__self;
425 // return (std::ptrdiff_t)((char*) &__tup::get<_Idx>(__self->__inner_ops_)
426 // - static_cast<char*>(__self));
427 // }
428
__op_statestdexec::__detail::__op_state429 __op_state(_Sexpr&& __sexpr, _Receiver __rcvr) //
430 noexcept(__nothrow_constructible_from<__op_base<_Sexpr, _Receiver>,
431 _Sexpr&&, _Receiver&&> &&
432 __nothrow_callable<__sexpr_apply_t, _Sexpr&&,
433 __connect_fn<_Sexpr, _Receiver>>) :
434 __op_state::__op_base{static_cast<_Sexpr&&>(__sexpr),
435 static_cast<_Receiver&&>(__rcvr)},
436 __inner_ops_(__sexpr_apply(static_cast<_Sexpr&&>(__sexpr),
437 __connect_fn<_Sexpr, _Receiver>{this}))
438 {}
439
440 STDEXEC_ATTRIBUTE((always_inline))
startstdexec::__detail::__op_state441 void start() & noexcept
442 {
443 using __tag_t = typename __op_state::__tag_t;
444 auto&& __rcvr = this->__rcvr();
445 __inner_ops_.apply(
446 [&](auto&... __ops) noexcept {
447 __sexpr_impl<__tag_t>::start(this->__state_, __rcvr, __ops...);
448 },
449 __inner_ops_);
450 }
451
452 template <class _Index, class _Tag2, class... _Args>
453 STDEXEC_ATTRIBUTE((always_inline))
__completestdexec::__detail::__op_state454 void __complete(_Index, _Tag2, _Args&&... __args) noexcept
455 {
456 using __tag_t = typename __op_state::__tag_t;
457 auto&& __rcvr = this->__rcvr();
458 using _CompleteFn = __mtypeof<__sexpr_impl<__tag_t>::complete>;
459 if constexpr (__callable<_CompleteFn, _Index, __op_state&, _Tag2,
460 _Args...>)
461 {
462 __sexpr_impl<__tag_t>::complete(_Index(), *this, _Tag2(),
463 static_cast<_Args&&>(__args)...);
464 }
465 else
466 {
467 __sexpr_impl<__tag_t>::complete(_Index(), this->__state_, __rcvr,
468 _Tag2(),
469 static_cast<_Args&&>(__args)...);
470 }
471 }
472
473 template <class _Index>
474 STDEXEC_ATTRIBUTE((always_inline))
__get_envstdexec::__detail::__op_state475 auto __get_env(_Index) const noexcept
476 -> __env_type_t<_Index, __tag_t, _Index, _Sexpr, _Receiver>
477 {
478 const auto& __rcvr = this->__rcvr();
479 return __sexpr_impl<__tag_t>::get_env(_Index(), this->__state_, __rcvr);
480 }
481 };
482
483 inline constexpr auto __drop_front = //
484 []<class _Fn>(_Fn __fn) noexcept {
485 return [__fn = std::move(__fn)]<class... _Rest>(auto&&,
486 _Rest&&... __rest) //
487 noexcept(__nothrow_callable<const _Fn&, _Rest...>)
488 -> __call_result_t<const _Fn&, _Rest...> {
489 return __fn(static_cast<_Rest&&>(__rest)...);
490 };
491 };
492
493 template <class _Tag, class... _Captures>
494 STDEXEC_ATTRIBUTE((host, device, always_inline))
__captures(_Tag,_Captures &&...__captures2)495 constexpr auto __captures(_Tag, _Captures&&... __captures2)
496 {
497 return
498 [... __captures3 =
499 static_cast<_Captures&&>(__captures2)]<class _Cvref, class _Fun>(
500 _Cvref, _Fun&& __fun) mutable //
501 noexcept(
502 __nothrow_callable<_Fun, _Tag, __minvoke<_Cvref, _Captures>...>) //
503 -> __call_result_t<_Fun, _Tag, __minvoke<_Cvref, _Captures>...>
504 requires __callable<_Fun, _Tag, __minvoke<_Cvref, _Captures>...>
505 {
506 // The use of decltype(__captures3) here instead of _Captures is a
507 // workaround for a codegen bug in nvc++.
508 return static_cast<_Fun&&>(__fun)(
509 _Tag(), const_cast<__minvoke<_Cvref, decltype(__captures3)>&&>(
510 __captures3)...);
511 };
512 }
513
514 template <class _Tag, class _Data, class... _Child>
515 using __captures_t = decltype(__detail::__captures(_Tag(), __declval<_Data>(),
516 __declval<_Child>()...));
517
518 template <class, class, class... _Child>
519 using __tuple_size_t = char[sizeof...(_Child) + 2];
520
521 template <std::size_t _Idx, class _Descriptor>
522 concept __in_range =
523 (_Idx < sizeof(__minvoke<_Descriptor, __q<__tuple_size_t>>));
524
525 } // namespace __detail
526
527 struct __sexpr_defaults
528 {
529 static constexpr auto get_attrs = __detail::__get_attrs;
530 static constexpr auto get_env = __detail::__get_env;
531 static constexpr auto get_state = __detail::__get_state;
532 static constexpr auto connect = __detail::__connect;
533 static constexpr auto start = __detail::__start;
534 static constexpr auto complete = __detail::__complete;
535 static constexpr auto get_completion_signatures = __detail::__sigs;
536 };
537
538 template <class _Tag>
539 struct __sexpr_impl : __sexpr_defaults
540 {
541 using not_specialized = void;
542 };
543
544 using __detail::__enable_receiver_from_this;
545
546 template <class _Tag>
547 using __get_attrs_fn = __result_of<__detail::__drop_front,
548 __mtypeof<__sexpr_impl<_Tag>::get_attrs>>;
549
550 //! A dummy type used only for diagnostic purposes.
551 //! See `__sexpr` for the implementation of P2300's _`basic-sender`_.
552 template <class...>
553 struct __basic_sender
554 {
555 // See MAINTAINERS.md#class-template-parameters for `__id` and `__t`.
556 using __id = __basic_sender;
557 using __t = __basic_sender;
558 };
559
560 //! A struct template to aid in creating senders.
561 //! This struct closely resembles P2300's
562 //! [_`basic-sender`_](https://eel.is/c++draft/exec#snd.expos-24), but is not an
563 //! exact implementation. Note: The struct named `__basic_sender` is just a
564 //! dummy type and is also not _`basic-sender`_.
565 template <auto _DescriptorFn, class = __anon>
566 struct __sexpr
567 {
568 using sender_concept = sender_t;
569
570 // See MAINTAINERS.md#class-template-parameters for `__id` and `__t`.
571 using __id = __sexpr;
572 using __t = __sexpr;
573 using __desc_t = decltype(_DescriptorFn());
574 using __tag_t = typename __desc_t::__tag;
575 using __captures_t = __minvoke<__desc_t, __q<__detail::__captures_t>>;
576
577 mutable __captures_t __impl_;
578
579 template <class _Tag, class _Data, class... _Child>
580 STDEXEC_ATTRIBUTE((host, device, always_inline))
__sexprstdexec::__sexpr581 explicit __sexpr(_Tag, _Data&& __data, _Child&&... __child) :
582 __impl_(__detail::__captures(_Tag(), static_cast<_Data&&>(__data),
583 static_cast<_Child&&>(__child)...))
584 {}
585
586 template <class _Self>
587 using __impl = __sexpr_impl<__meval<__msecond, _Self, __tag_t>>;
588
589 template <class _Self = __sexpr>
590 STDEXEC_ATTRIBUTE((always_inline))
get_envstdexec::__sexpr591 auto get_env() const noexcept
592 -> __result_of<__sexpr_apply, const _Self&, __get_attrs_fn<__tag_t>>
593 {
594 return __sexpr_apply(*this,
595 __detail::__drop_front(__impl<_Self>::get_attrs));
596 }
597
598 template <__decays_to<__sexpr> _Self, class... _Env>
599 STDEXEC_ATTRIBUTE((always_inline))
get_completion_signaturesstdexec::__sexpr600 static auto get_completion_signatures(_Self&&, _Env&&...) noexcept //
601 -> __msecond<__if_c<__decays_to<_Self, __sexpr>>,
602 __result_of<__impl<_Self>::get_completion_signatures,
603 _Self, _Env...>>
604 {
605 return {};
606 }
607
608 // BUGBUG fix receiver constraint here:
609 template <__decays_to<__sexpr> _Self, /*receiver*/ class _Receiver>
610 STDEXEC_ATTRIBUTE((always_inline))
connectstdexec::__sexpr611 static auto connect(_Self&& __self, _Receiver&& __rcvr) //
612 noexcept(__noexcept_of<__impl<_Self>::connect, _Self, _Receiver>) //
613 -> __msecond<__if_c<__decays_to<_Self, __sexpr>>,
614 __result_of<__impl<_Self>::connect, _Self, _Receiver>>
615 {
616 return __impl<_Self>::connect(static_cast<_Self&&>(__self),
617 static_cast<_Receiver&&>(__rcvr));
618 }
619
620 template <class _Sender, class _ApplyFn>
621 STDEXEC_ATTRIBUTE((always_inline))
applystdexec::__sexpr622 static auto apply(_Sender&& __sndr, _ApplyFn&& __fun) //
623 noexcept(__nothrow_callable<__detail::__impl_of<_Sender>,
624 __copy_cvref_fn<_Sender>, _ApplyFn>) //
625 -> __call_result_t<__detail::__impl_of<_Sender>,
626 __copy_cvref_fn<_Sender>, _ApplyFn>
627 { //
628 return static_cast<_Sender&&>(__sndr).__impl_(
629 __copy_cvref_fn<_Sender>(), static_cast<_ApplyFn&&>(__fun)); //
630 }
631
632 template <std::size_t _Idx, __decays_to_derived_from<__sexpr> _Self>
633 STDEXEC_ATTRIBUTE((always_inline))
get(_Self && __self)634 friend auto get(_Self&& __self) noexcept -> decltype(auto)
635 requires __detail::__in_range<_Idx, __desc_t>
636 {
637 if constexpr (_Idx == 0)
638 {
639 return __tag_t();
640 }
641 else
642 {
643 return __self.__impl_(__copy_cvref_fn<_Self>(),
644 __nth_pack_element<_Idx>);
645 }
646 }
647 };
648
649 template <class _Tag, class _Data, class... _Child>
650 STDEXEC_ATTRIBUTE((host, device))
651 __sexpr(_Tag, _Data, _Child...)
652 -> __sexpr<STDEXEC_SEXPR_DESCRIPTOR(_Tag, _Data, _Child...)>;
653
654 template <class _Tag, class _Data, class... _Child>
655 using __sexpr_t = __sexpr<STDEXEC_SEXPR_DESCRIPTOR(_Tag, _Data, _Child...)>;
656
657 //////////////////////////////////////////////////////////////////////////////////////////////////
658 // __make_sexpr
659 //! A tagged function-object
660 //! Takes data and children and
661 //! returns `__sexpr_t<_Tag, _Data, _Child...>{_Tag(), data, children...}`.
662 namespace __detail
663 {
664 template <class _Tag>
665 struct __make_sexpr_t
666 {
667 template <class _Data = __, class... _Child>
operator ()stdexec::__detail::__make_sexpr_t668 constexpr auto operator()(_Data __data = {}, _Child... __child) const
669 {
670 return __sexpr_t<_Tag, _Data, _Child...>{
671 _Tag(), static_cast<_Data&&>(__data),
672 static_cast<_Child&&>(__child)...};
673 }
674 };
675 } // namespace __detail
676
677 template <class _Tag>
678 inline constexpr __detail::__make_sexpr_t<_Tag> __make_sexpr{};
679
680 // The __name_of utility defined below is used to pretty-print the type names of
681 // senders in compiler diagnostics.
682 namespace __detail
683 {
684 struct __basic_sender_name
685 {
686 template <class _Tag, class _Data, class... _Child>
687 using __result = __basic_sender<_Tag, _Data, __name_of<_Child>...>;
688
689 template <class _Sender>
690 using __f = __minvoke<typename __decay_t<_Sender>::__desc_t, __q<__result>>;
691 };
692
693 struct __id_name
694 {
695 template <class _Sender>
696 using __f = __name_of<__id<_Sender>>;
697 };
698
699 template <class _Sender>
700 extern __mcompose<__cplr, __name_of_fn<_Sender>> __name_of_v<_Sender&>;
701
702 template <class _Sender>
703 extern __mcompose<__cprr, __name_of_fn<_Sender>> __name_of_v<_Sender&&>;
704
705 template <class _Sender>
706 extern __mcompose<__cpclr, __name_of_fn<_Sender>> __name_of_v<const _Sender&>;
707
708 template <auto _Descriptor>
709 extern __basic_sender_name __name_of_v<__sexpr<_Descriptor>>;
710
711 template <__has_id _Sender>
712 requires(!same_as<__id<_Sender>, _Sender>)
713 extern __id_name __name_of_v<_Sender>;
714 } // namespace __detail
715 } // namespace stdexec
716
717 namespace std
718 {
719 template <auto _Descriptor>
720 struct tuple_size<stdexec::__sexpr<_Descriptor>> :
721 integral_constant<size_t,
722 stdexec::__v<stdexec::__minvoke<
723 stdexec::__result_of<_Descriptor>, stdexec::__msize>>>
724 {};
725
726 template <size_t _Idx, auto _Descriptor>
727 struct tuple_element<_Idx, stdexec::__sexpr<_Descriptor>>
728 {
729 using type = //
730 stdexec::__remove_rvalue_reference_t< //
731 stdexec::__call_result_t< //
732 stdexec::__detail::__impl_of<stdexec::__sexpr<_Descriptor>>,
733 stdexec::__cp, stdexec::__nth_pack_element_t<_Idx>>>;
734 };
735 } // namespace std
736