blob: 5f02635d102496885c03cbff078536c611deb217 [file] [log] [blame]
Patrick Williams5932cd62023-11-16 11:13:00 -06001/*
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"
Patrick Williams8723a542024-02-12 11:18:32 -060019#include "__concepts.hpp"
20#include "__config.hpp"
Patrick Williams4c2d73d2023-12-01 16:58:58 -060021#include "__env.hpp"
Patrick Williams5932cd62023-11-16 11:13:00 -060022#include "__execution_fwd.hpp"
23#include "__meta.hpp"
Patrick Williams4c2d73d2023-12-01 16:58:58 -060024#include "__tuple.hpp"
Patrick Williams5932cd62023-11-16 11:13:00 -060025#include "__type_traits.hpp"
26
Patrick Williams8723a542024-02-12 11:18:32 -060027#include <cstddef>
28#include <type_traits>
Patrick Williams5932cd62023-11-16 11:13:00 -060029#include <utility> // for tuple_size/tuple_element
30
31namespace stdexec
32{
33/////////////////////////////////////////////////////////////////////////////
34// Generic __sender type
35namespace __detail
36{
37template <class _Sender>
38using __impl_of = decltype((__declval<_Sender>().__impl_));
39
40struct __get_tag
41{
42 template <class _Tag, class... _Rest>
Patrick Williams4c2d73d2023-12-01 16:58:58 -060043 STDEXEC_ATTRIBUTE((always_inline))
Patrick Williams5932cd62023-11-16 11:13:00 -060044 _Tag operator()(_Tag, _Rest&&...) const noexcept
45 {
46 return {};
47 }
48};
49
50struct __get_data
51{
52 template <class _Data, class... _Rest>
Patrick Williams4c2d73d2023-12-01 16:58:58 -060053 STDEXEC_ATTRIBUTE((always_inline))
Patrick Williams5932cd62023-11-16 11:13:00 -060054 _Data&& operator()(__ignore, _Data&& __data, _Rest&&...) const noexcept
55 {
56 return (_Data&&)__data;
57 }
58};
59
60template <class _Continuation>
61struct __get_children
62{
Patrick Williams4c2d73d2023-12-01 16:58:58 -060063 template <class... _Child>
64 STDEXEC_ATTRIBUTE((always_inline))
65 auto operator()(__ignore, __ignore, _Child&&...) const noexcept
66 -> __mtype<__minvoke<_Continuation, _Child...>> (*)()
Patrick Williams5932cd62023-11-16 11:13:00 -060067 {
68 return nullptr;
69 }
70};
71
Patrick Williams4c2d73d2023-12-01 16:58:58 -060072template <class _Tag, class _Data, class... _Child>
73struct __desc
Patrick Williams5932cd62023-11-16 11:13:00 -060074{
Patrick Williams4c2d73d2023-12-01 16:58:58 -060075 using __tag = _Tag;
76 using __data = _Data;
77 using __children = __types<_Child...>;
78};
Patrick Williams5932cd62023-11-16 11:13:00 -060079
Patrick Williams4c2d73d2023-12-01 16:58:58 -060080template <class _Fn>
81struct __sexpr_uncurry_fn
82{
83 template <class _Tag, class _Data, class... _Child>
84 requires __minvocable<_Fn, _Tag, _Data, _Child...>
85 constexpr auto operator()(_Tag, _Data&&, _Child&&...) const noexcept
86 -> __minvoke<_Fn, _Tag, _Data, _Child...>;
87};
88
89template <class _Sender, class _Fn>
90using __sexpr_uncurry =
91 __call_result_t<__impl_of<_Sender>, __copy_cvref_fn<_Sender>,
92 __sexpr_uncurry_fn<_Fn>>;
93
94template <class _Sender>
95using __desc_of = __sexpr_uncurry<_Sender, __q<__desc>>;
96
97using __get_desc = __sexpr_uncurry_fn<__q<__desc>>;
98
99template <class _Sender>
100extern __q<__midentity> __name_of_v;
101
102template <class _Sender>
103using __name_of_fn = decltype(__name_of_v<_Sender>);
104
105template <class _Sender>
106using __name_of = __minvoke<__name_of_fn<_Sender>, _Sender>;
107} // namespace __detail
108
109template <class _Sender>
110using tag_of_t = typename __detail::__desc_of<_Sender>::__tag;
111
112template <class _Sender>
113using __data_of = typename __detail::__desc_of<_Sender>::__data;
114
115template <class _Sender, class _Continuation = __q<__types>>
116using __children_of = //
117 __mapply<_Continuation, typename __detail::__desc_of<_Sender>::__children>;
118
119template <class _Ny, class _Sender>
120using __nth_child_of = __children_of<_Sender, __mbind_front_q<__m_at, _Ny>>;
121
122template <std::size_t _Ny, class _Sender>
123using __nth_child_of_c =
124 __children_of<_Sender, __mbind_front_q<__m_at, __msize_t<_Ny>>>;
125
126template <class _Sender>
127using __child_of = __children_of<_Sender, __q<__mfront>>;
128
129template <class _Sender>
130inline constexpr std::size_t __nbr_children_of =
131 __v<__children_of<_Sender, __msize>>;
132
133template <class _Fn, class _Tp>
134 requires __mvalid<tag_of_t, _Tp> &&
135 __mvalid<__detail::__sexpr_uncurry, _Tp, _Fn>
136struct __uncurry_<_Fn, _Tp>
137{
138 using __t = __detail::__sexpr_uncurry<_Tp, _Fn>;
139};
140
141template <class _Tag>
142struct __sexpr_impl;
143
144template <class _Sender>
145using __name_of = __detail::__name_of<_Sender>;
146
147namespace __detail
148{
149template <class _Sexpr, class _Receiver>
150struct __op_state;
151
152template <class _Sexpr, class _Receiver>
153struct __connect_fn;
154
155template <class _Tag, class _Sexpr, class _Receiver>
156using __state_type_t =
157 __decay_t<__result_of<__sexpr_impl<_Tag>::get_state, _Sexpr, _Receiver&>>;
158
159template <class _Tag, class _Index, class _Sexpr, class _Receiver>
160using __env_type_t =
161 __result_of<__sexpr_impl<_Tag>::get_env, _Index,
162 __state_type_t<_Tag, _Sexpr, _Receiver>&, _Receiver&>;
163
164template <class _Sexpr, class _Receiver>
165concept __connectable =
166 __callable<__impl_of<_Sexpr>, __copy_cvref_fn<_Sexpr>,
167 __connect_fn<_Sexpr, _Receiver>> &&
168 __mvalid<__state_type_t, tag_of_t<_Sexpr>, _Sexpr, _Receiver>;
169
Patrick Williamsac329c52024-01-03 17:52:04 -0600170// // Note: This is UB. UBSAN allows it for now.
171// template <class _Parent, class _Child>
172// _Parent* __parent_from_child(_Child* __child, _Child _Parent::*__mbr_ptr)
173// noexcept {
174// alignas(_Parent) char __buf[sizeof(_Parent)];
175// _Parent* __parent = (_Parent*) &__buf;
176// const std::ptrdiff_t __offset = (char*) &(__parent->*__mbr_ptr) - __buf;
177// return (_Parent*) ((char*) __child - __offset);
178// }
Patrick Williams4c2d73d2023-12-01 16:58:58 -0600179
180inline constexpr auto __get_attrs = //
181 [](__ignore, const auto&... __child) noexcept -> decltype(auto) {
182 if constexpr (sizeof...(__child) == 1)
183 {
184 return stdexec::get_env(
185 __child...); // BUGBUG: should be only the forwarding queries
186 }
187 else
188 {
189 return empty_env();
190 }
191 STDEXEC_UNREACHABLE();
192};
193
194inline constexpr auto __get_env = //
195 []<class _Receiver>(__ignore, __ignore, const _Receiver& __rcvr) noexcept
196 -> env_of_t<const _Receiver&> { return stdexec::get_env(__rcvr); };
197
198inline constexpr auto __get_state = //
199 []<class _Sender>(_Sender&& __sndr, __ignore) noexcept -> decltype(auto) {
200 return STDEXEC_CALL_EXPLICIT_THIS_MEMFN((_Sender&&)__sndr,
201 apply)(__get_data());
202};
203
204inline constexpr auto __connect = //
205 []<class _Sender, class _Receiver>(
206 _Sender&& __sndr, _Receiver __rcvr) -> __op_state<_Sender, _Receiver>
207 requires __connectable<_Sender, _Receiver>
208{
209 return __op_state<_Sender, _Receiver>{(_Sender&&)__sndr,
210 (_Receiver&&)__rcvr};
211};
212
213inline constexpr auto __start = //
214 []<class _StartTag = start_t, class... _ChildOps>(
215 __ignore, __ignore, _ChildOps&... __ops) noexcept
216{
217 (_StartTag()(__ops), ...);
218};
219
220inline constexpr auto __complete = //
221 []<class _Index, class _Receiver, class _SetTag, class... _Args>(
222 _Index, __ignore, _Receiver& __rcvr, _SetTag,
223 _Args&&... __args) noexcept {
224 static_assert(__v<_Index> == 0,
225 "I don't know how to complete this operation.");
226 _SetTag()(std::move(__rcvr), (_Args&&)__args...);
227};
228
229inline constexpr auto __get_completion_signagures = //
230 [](__ignore, __ignore) noexcept { return void(); };
231
232template <class _ReceiverId, class _Sexpr, class _Idx>
233struct __receiver
234{
235 struct __t
236 {
237 using receiver_concept = receiver_t;
238 using _Receiver = stdexec::__t<_ReceiverId>;
239 using __sexpr = _Sexpr;
240 using __index = _Idx;
241 using __id = __receiver;
242 using __parent_op_t = __op_state<_Sexpr, _Receiver>;
243 using __tag_t = tag_of_t<_Sexpr>;
244
245 // A pointer to the parent operation state, which contains the one
246 // created with this receiver.
247 __parent_op_t* __op_;
248
Patrick Williamsac329c52024-01-03 17:52:04 -0600249 // template <class _ChildSexpr, class _ChildReceiver>
250 // static __t __from_op_state(__op_state<_ChildSexpr, _ChildReceiver>*
251 // __child) noexcept {
252 // using __parent_op_t = __op_state<_Sexpr, _Receiver>;
253 // std::ptrdiff_t __offset = __parent_op_t::template
254 // __get_child_op_offset<__v<_Idx>>();
255 // __parent_op_t* __parent = (__parent_op_t*) ((char*) __child -
256 // __offset); return __t{__parent};
257 // }
Patrick Williams4c2d73d2023-12-01 16:58:58 -0600258
259 template <__completion_tag _Tag, class... _Args>
260 STDEXEC_ATTRIBUTE((always_inline))
261 friend void tag_invoke(_Tag, __t&& __self, _Args&&... __args) noexcept
262 {
263 __self.__op_->__complete(_Idx(), _Tag(), (_Args&&)__args...);
264 }
265
266 template <same_as<get_env_t> _Tag, class _SexprTag = __tag_t>
267 STDEXEC_ATTRIBUTE((always_inline))
268 friend auto tag_invoke(_Tag, const __t& __self) noexcept
269 -> __env_type_t<_SexprTag, _Idx, _Sexpr, _Receiver>
270 {
271 return __self.__op_->__get_env(_Idx());
272 }
273 };
274};
275
276template <class _Receiver>
277using __sexpr_connected_with =
278 __mapply<__mbind_front_q<__m_at, typename _Receiver::__index>,
279 typename __call_result_t<__impl_of<typename _Receiver::__sexpr>,
280 __cp, __get_desc>::__children>;
281
282template <class _Sexpr, class _Receiver>
283struct __op_base : __immovable
284{
285 using __tag_t = typename __decay_t<_Sexpr>::__tag_t;
286 using __state_t = __state_type_t<__tag_t, _Sexpr, _Receiver>;
287
288 STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS _Receiver __rcvr_;
289 STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS __state_t __state_;
290
291 __op_base(_Sexpr&& __sndr, _Receiver&& __rcvr) :
292 __rcvr_((_Receiver&&)__rcvr),
293 __state_(__sexpr_impl<__tag_t>::get_state((_Sexpr&&)__sndr, __rcvr_))
294 {}
295
Patrick Williamsac329c52024-01-03 17:52:04 -0600296 _Receiver& __rcvr() & noexcept
Patrick Williams4c2d73d2023-12-01 16:58:58 -0600297 {
298 return __rcvr_;
299 }
300};
301
302// template <class _Sexpr, class _Receiver>
303// requires __is_instance_of<__id<_Receiver>, __receiver>
304// && __decays_to<_Sexpr, __sexpr_connected_with<_Receiver>>
305// struct __op_base<_Sexpr, _Receiver> : __immovable {
306// using __tag_t = typename __decay_t<_Sexpr>::__tag_t;
307// using __state_t = __state_type_t<__tag_t, _Sexpr, _Receiver>;
308
309// STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS __state_t __state_;
310
311// __op_base(_Sexpr&& __sndr, _Receiver&& __rcvr)
312// : __state_(__sexpr_impl<__tag_t>::get_state((_Sexpr&&) __sndr, __rcvr)) {
313// STDEXEC_ASSERT(this->__rcvr().__op_ == __rcvr.__op_);
314// }
315
316// _Receiver __rcvr() const noexcept {
317// return _Receiver::__from_op_state( //
318// static_cast<__op_state<_Sexpr, _Receiver>*>( //
319// const_cast<__op_base*>(this)));
320// }
321// };
322
323STDEXEC_PRAGMA_PUSH()
324STDEXEC_PRAGMA_IGNORE_GNU("-Winvalid-offsetof")
325STDEXEC_PRAGMA_IGNORE_EDG(offset_in_non_POD_nonstandard)
326
327template <class _Sexpr, class _Receiver>
328struct __enable_receiver_from_this
329{
330 using __op_base_t = __op_base<_Sexpr, _Receiver>;
331
332 decltype(auto) __receiver() noexcept
333 {
334 using __derived_t = decltype(__op_base_t::__state_);
335 __derived_t* __derived = static_cast<__derived_t*>(this);
336 constexpr std::size_t __offset = offsetof(__op_base_t, __state_);
337 __op_base_t* __base = (__op_base_t*)((char*)__derived - __offset);
338 return __base->__rcvr();
339 }
Patrick Williams5932cd62023-11-16 11:13:00 -0600340};
341
342STDEXEC_PRAGMA_POP()
343
Patrick Williams4c2d73d2023-12-01 16:58:58 -0600344STDEXEC_PRAGMA_PUSH()
345STDEXEC_PRAGMA_IGNORE_GNU("-Wmissing-braces")
346
347template <class _Sexpr, class _Receiver>
348struct __connect_fn
Patrick Williams5932cd62023-11-16 11:13:00 -0600349{
Patrick Williams4c2d73d2023-12-01 16:58:58 -0600350 template <std::size_t _Idx>
351 using __receiver_t =
352 __t<__receiver<__id<_Receiver>, _Sexpr, __mconstant<_Idx>>>;
353
354 __op_state<_Sexpr, _Receiver>* __op_;
355
356 struct __impl
Patrick Williams5932cd62023-11-16 11:13:00 -0600357 {
Patrick Williams4c2d73d2023-12-01 16:58:58 -0600358 __op_state<_Sexpr, _Receiver>* __op_;
359
360 template <std::size_t... _Is, class _Tag, class _Data, class... _Child>
361 auto operator()(__indices<_Is...>, _Tag, _Data&&,
362 _Child&&... __child) const
363 -> __tup::__tuple<__indices<_Is...>,
364 connect_result_t<_Child, __receiver_t<_Is>>...>
365 {
366 return __tuple{
367 connect((_Child&&)__child, __receiver_t<_Is>{__op_})...};
368 }
369 };
370
371 template <class _Tag, class _Data, class... _Child>
372 auto operator()(_Tag, _Data&& __data, _Child&&... __child) const
373 -> __call_result_t<__impl, __indices_for<_Child...>, _Tag, _Data,
374 _Child...>
375 {
376 return __impl{__op_}(__indices_for<_Child...>(), _Tag(),
377 (_Data&&)__data, (_Child&&)__child...);
Patrick Williams5932cd62023-11-16 11:13:00 -0600378 }
379};
Patrick Williams4c2d73d2023-12-01 16:58:58 -0600380STDEXEC_PRAGMA_POP()
381
382template <class _Sexpr, class _Receiver>
383struct __op_state : __op_base<_Sexpr, _Receiver>
384{
385 using __desc_t = typename __decay_t<_Sexpr>::__desc_t;
386 using __tag_t = typename __desc_t::__tag;
387 using __data_t = typename __desc_t::__data;
388 using __children_t = typename __desc_t::__children;
389 using __state_t = typename __op_state::__state_t;
Patrick Williams4c2d73d2023-12-01 16:58:58 -0600390 using __inner_ops_t =
Patrick Williamsac329c52024-01-03 17:52:04 -0600391 __result_of<__sexpr_apply, _Sexpr, __connect_fn<_Sexpr, _Receiver>>;
392
Patrick Williams4c2d73d2023-12-01 16:58:58 -0600393 __inner_ops_t __inner_ops_;
394
Patrick Williamsac329c52024-01-03 17:52:04 -0600395 // template <std::size_t _Idx>
396 // static std::ptrdiff_t __get_child_op_offset() noexcept {
397 // __op_state* __self = (__op_state*) &__self;
398 // return (std::ptrdiff_t)((char*)
399 // &__tup::__get<_Idx>(__self->__inner_ops_) - (char*) __self);
400 // }
Patrick Williams4c2d73d2023-12-01 16:58:58 -0600401
402 __op_state(_Sexpr&& __sexpr, _Receiver __rcvr) :
403 __op_state::__op_base{(_Sexpr&&)__sexpr, (_Receiver&&)__rcvr},
Patrick Williamsac329c52024-01-03 17:52:04 -0600404 __inner_ops_(__sexpr_apply((_Sexpr&&)__sexpr,
405 __connect_fn<_Sexpr, _Receiver>{this}))
Patrick Williams4c2d73d2023-12-01 16:58:58 -0600406 {}
407
408 template <same_as<start_t> _Tag2>
409 STDEXEC_ATTRIBUTE((always_inline))
410 friend void tag_invoke(_Tag2, __op_state& __self) noexcept
411 {
412 using __tag_t = typename __op_state::__tag_t;
413 auto&& __rcvr = __self.__rcvr();
414 __tup::__apply(
415 [&](auto&... __ops) noexcept {
416 __sexpr_impl<__tag_t>::start(__self.__state_, __rcvr, __ops...);
417 },
418 __self.__inner_ops_);
419 }
420
421 template <class _Index, class _Tag2, class... _Args>
422 STDEXEC_ATTRIBUTE((always_inline))
423 void __complete(_Index, _Tag2, _Args&&... __args) noexcept
424 {
425 using __tag_t = typename __op_state::__tag_t;
426 auto&& __rcvr = this->__rcvr();
427 __sexpr_impl<__tag_t>::complete(_Index(), this->__state_, __rcvr,
428 _Tag2(), (_Args&&)__args...);
429 }
430
431 template <class _Index>
432 STDEXEC_ATTRIBUTE((always_inline)) //
433 auto __get_env(_Index) noexcept
434 -> __env_type_t<__tag_t, _Index, _Sexpr, _Receiver>
435 {
436 const auto& __rcvr = this->__rcvr();
437 return __sexpr_impl<__tag_t>::get_env(_Index(), this->__state_, __rcvr);
438 }
439};
440
441inline constexpr auto __drop_front = //
442 []<class _Fn>(_Fn __fn) noexcept {
443 return
444 [__fn = std::move(__fn)]<class... _Rest>(
445 auto&&, _Rest&&... __rest) noexcept(__nothrow_callable<const _Fn&,
446 _Rest...>)
447 -> __call_result_t<const _Fn&, _Rest...> {
448 return __fn((_Rest&&)__rest...);
449 };
450};
Patrick Williams5932cd62023-11-16 11:13:00 -0600451} // namespace __detail
452
Patrick Williams4c2d73d2023-12-01 16:58:58 -0600453struct __sexpr_defaults
454{
455 static constexpr auto get_attrs = __detail::__get_attrs;
456 static constexpr auto get_env = __detail::__get_env;
457 static constexpr auto get_state = __detail::__get_state;
458 static constexpr auto connect = __detail::__connect;
459 static constexpr auto start = __detail::__start;
460 static constexpr auto complete = __detail::__complete;
461 static constexpr auto get_completion_signagures =
462 __detail::__get_completion_signagures;
463};
464
465template <class Tag>
466struct __sexpr_impl : __sexpr_defaults
467{};
468
469using __detail::__enable_receiver_from_this;
470
471template <class _Tag>
472using __get_attrs_fn = __result_of<__detail::__drop_front,
473 __mtypeof<__sexpr_impl<_Tag>::get_attrs>>;
474
Patrick Williams5932cd62023-11-16 11:13:00 -0600475//////////////////////////////////////////////////////////////////////////////////////////////////
476// __sexpr
477template <class...>
478struct __sexpr
479{
480 using __id = __sexpr;
481 using __t = __sexpr;
482};
483
484template <class _ImplFn>
485struct __sexpr<_ImplFn>
486{
Patrick Williams4c2d73d2023-12-01 16:58:58 -0600487 using sender_concept = sender_t;
Patrick Williams5932cd62023-11-16 11:13:00 -0600488 using __t = __sexpr;
489 using __id = __sexpr;
Patrick Williams4c2d73d2023-12-01 16:58:58 -0600490 using __desc_t = __call_result_t<_ImplFn, __cp, __detail::__get_desc>;
491 using __tag_t = typename __desc_t::__tag;
492 using __data_t = typename __desc_t::__data;
493 using __children_t = typename __desc_t::__children;
Patrick Williams5932cd62023-11-16 11:13:00 -0600494 using __arity_t = __mapply<__msize, __children_t>;
495
Patrick Williams4c2d73d2023-12-01 16:58:58 -0600496 template <class _Tag>
497 using __impl = __sexpr_impl<__meval<__msecond, _Tag, __tag_t>>;
498
Patrick Williams5932cd62023-11-16 11:13:00 -0600499 STDEXEC_ATTRIBUTE((always_inline)) //
500 static __tag_t __tag() noexcept
501 {
502 return {};
503 }
504
505 mutable _ImplFn __impl_;
506
507 STDEXEC_ATTRIBUTE((host, device, always_inline))
508 explicit __sexpr(_ImplFn __impl) : __impl_((_ImplFn&&)__impl) {}
509
510 template <same_as<get_env_t> _Tag, same_as<__sexpr> _Self>
Patrick Williams4c2d73d2023-12-01 16:58:58 -0600511 STDEXEC_ATTRIBUTE((always_inline)) //
512 friend auto tag_invoke(_Tag, const _Self& __self) noexcept //
513 -> __msecond<
514 __if_c<same_as<_Tag, get_env_t> && same_as<_Self, __sexpr>>, //
515 __result_of<__sexpr_apply, const _Self&, __get_attrs_fn<__tag_t>>>
Patrick Williams5932cd62023-11-16 11:13:00 -0600516 {
Patrick Williams4c2d73d2023-12-01 16:58:58 -0600517 return __sexpr_apply(__self,
518 __detail::__drop_front(__impl<_Tag>::get_attrs));
Patrick Williams5932cd62023-11-16 11:13:00 -0600519 }
520
521 template <same_as<get_completion_signatures_t> _Tag,
522 __decays_to<__sexpr> _Self, class _Env>
Patrick Williams4c2d73d2023-12-01 16:58:58 -0600523 STDEXEC_ATTRIBUTE((always_inline)) //
524 friend auto tag_invoke(_Tag, _Self&& __self, _Env&& __env) noexcept //
525 -> __msecond<
526 __if_c<same_as<_Tag, get_completion_signatures_t> &&
527 __decays_to<_Self, __sexpr>>,
528 __result_of<__impl<_Tag>::get_completion_signatures, _Self, _Env>>
Patrick Williams5932cd62023-11-16 11:13:00 -0600529 {
530 return {};
531 }
532
533 // BUGBUG fix receiver constraint here:
534 template <same_as<connect_t> _Tag, __decays_to<__sexpr> _Self,
535 /*receiver*/ class _Receiver>
Patrick Williams4c2d73d2023-12-01 16:58:58 -0600536 STDEXEC_ATTRIBUTE((always_inline)) //
537 friend auto tag_invoke(_Tag, _Self&& __self, _Receiver&& __rcvr) //
538 noexcept(noexcept(__impl<_Tag>::connect((_Self&&)__self,
539 (_Receiver&&)__rcvr))) //
540 -> __msecond<
541 __if_c<same_as<_Tag, connect_t> && __decays_to<_Self, __sexpr>>,
542 __result_of<__impl<_Tag>::connect, _Self, _Receiver>>
Patrick Williams5932cd62023-11-16 11:13:00 -0600543 {
Patrick Williams4c2d73d2023-12-01 16:58:58 -0600544 return __impl<_Tag>::connect((_Self&&)__self, (_Receiver&&)__rcvr);
Patrick Williams5932cd62023-11-16 11:13:00 -0600545 }
546
547 template <class _Sender, class _ApplyFn>
548 STDEXEC_ATTRIBUTE((always_inline)) //
549 STDEXEC_DEFINE_EXPLICIT_THIS_MEMFN(auto apply)(this _Sender&& __sndr,
550 _ApplyFn&& __fun) //
551 noexcept(__nothrow_callable<__detail::__impl_of<_Sender>,
552 __copy_cvref_fn<_Sender>, _ApplyFn>) //
553 -> __call_result_t<__detail::__impl_of<_Sender>,
554 __copy_cvref_fn<_Sender>, _ApplyFn>
555 { //
556 return ((_Sender&&)__sndr)
557 .__impl_(__copy_cvref_fn<_Sender>(), (_ApplyFn&&)__fun); //
558 }
559
560 template <std::size_t _Idx, __decays_to_derived_from<__sexpr> _Self>
561 STDEXEC_ATTRIBUTE((always_inline))
562 friend decltype(auto) get(_Self&& __self) noexcept
563 requires(_Idx < (__v<__arity_t> + 2))
564 {
565 if constexpr (_Idx == 0)
566 {
567 return __tag_t();
568 }
569 else
570 {
571 return __self.__impl_(__copy_cvref_fn<_Self>(),
572 __nth_pack_element<_Idx>);
573 }
574 STDEXEC_UNREACHABLE();
575 }
576};
577
578template <class _ImplFn>
579STDEXEC_ATTRIBUTE((host, device))
580__sexpr(_ImplFn) -> __sexpr<_ImplFn>;
581
582//////////////////////////////////////////////////////////////////////////////////////////////////
583// __make_sexpr
584namespace __detail
585{
586template <class _Tag>
587struct __make_sexpr_t
588{
Patrick Williams4c2d73d2023-12-01 16:58:58 -0600589 template <class _Data = __, class... _Child>
590 constexpr auto operator()(_Data __data = {}, _Child... __child) const;
Patrick Williams5932cd62023-11-16 11:13:00 -0600591};
592
593#if STDEXEC_NVHPC() || (STDEXEC_GCC() && __GNUC__ < 13)
594// The NVIDIA HPC compiler and gcc prior to v13 struggle with capture
595// initializers for a parameter pack. As a workaround, we use a wrapper that
596// performs moves when non-const lvalues are copied. That constructor is
597// only used when capturing the variables, never when the resulting lambda
598// is copied or moved.
599
600// Move-by-copy
601template <class _Ty>
602struct __mbc
603{
604 template <class _Cvref>
605 using __f = __minvoke<_Cvref, _Ty>;
606
607 _Ty __value;
608
609 STDEXEC_ATTRIBUTE((always_inline))
610 explicit __mbc(_Ty& __v) noexcept(
611 std::is_nothrow_move_constructible_v<_Ty>) :
612 __value((_Ty&&)__v)
613 {}
614
615 // This is a template so as to not be considered a copy/move constructor.
616 // Therefore, it doesn't suppress the generation of the default copy/move
617 // constructors.
618 STDEXEC_ATTRIBUTE((always_inline))
619 __mbc(same_as<__mbc> auto& __that) noexcept(
620 std::is_nothrow_move_constructible_v<_Ty>) :
621 __value(static_cast<_Ty&&>(__that.__value))
622 {}
623};
624
625// Rather strange definition of the lambda return type below is to reap the
626// benefits of SFINAE without nvc++ encoding the whole return type into the
627// symbol name.
628template <class _Ty>
629extern _Ty (*__f)();
630
631// Anonymous namespace here is to avoid symbol name collisions with the
632// lambda functions returned by __make_tuple.
633namespace
634{
635constexpr auto __make_tuple = //
636 []<class _Tag, class... _Captures>(_Tag, _Captures&&... __captures) {
637 return
638 [=]<class _Cvref, class _Fun>(_Cvref __cvref, _Fun&& __fun) mutable //
639 noexcept(
640 __nothrow_callable<_Fun, _Tag, __minvoke<_Captures, _Cvref>...>) //
641 -> decltype(__f<__call_result_t<_Fun, _Tag,
642 __minvoke<_Captures, _Cvref>...>>())
643 requires __callable<_Fun, _Tag, __minvoke<_Captures, _Cvref>...>
644 {
645 return ((_Fun&&)__fun)(
646 _Tag(),
647 const_cast<__minvoke<_Captures, _Cvref>&&>(__captures.__value)...);
648 };
649};
650} // anonymous namespace
651
652template <class _Tag>
Patrick Williams4c2d73d2023-12-01 16:58:58 -0600653template <class _Data, class... _Child>
Patrick Williams5932cd62023-11-16 11:13:00 -0600654constexpr auto __make_sexpr_t<_Tag>::operator()(_Data __data,
Patrick Williams4c2d73d2023-12-01 16:58:58 -0600655 _Child... __child) const
Patrick Williams5932cd62023-11-16 11:13:00 -0600656{
657 return __sexpr{__make_tuple(_Tag(), __detail::__mbc(__data),
Patrick Williams4c2d73d2023-12-01 16:58:58 -0600658 __detail::__mbc(__child)...)};
Patrick Williams5932cd62023-11-16 11:13:00 -0600659}
660#else
661// Anonymous namespace here is to avoid symbol name collisions with the
662// lambda functions returned by __make_tuple.
663namespace
664{
665constexpr auto __make_tuple = //
666 []<class _Tag, class... _Captures>(_Tag, _Captures&&... __captures) {
667 return
668 [... __captures = (_Captures&&)__captures]<class _Cvref, class _Fun>(
669 _Cvref, _Fun&& __fun) mutable //
670 noexcept(
671 __nothrow_callable<_Fun, _Tag, __minvoke<_Cvref, _Captures>...>) //
672 -> __call_result_t<_Fun, _Tag, __minvoke<_Cvref, _Captures>...>
673 requires __callable<_Fun, _Tag, __minvoke<_Cvref, _Captures>...>
674 {
675 return ((_Fun&&)__fun)(
676 _Tag(), const_cast<__minvoke<_Cvref, _Captures>&&>(__captures)...);
677 };
678};
679} // anonymous namespace
680
681template <class _Tag>
Patrick Williams4c2d73d2023-12-01 16:58:58 -0600682template <class _Data, class... _Child>
Patrick Williams5932cd62023-11-16 11:13:00 -0600683constexpr auto __make_sexpr_t<_Tag>::operator()(_Data __data,
Patrick Williams4c2d73d2023-12-01 16:58:58 -0600684 _Child... __child) const
Patrick Williams5932cd62023-11-16 11:13:00 -0600685{
Patrick Williams4c2d73d2023-12-01 16:58:58 -0600686 return __sexpr{__make_tuple(_Tag(), (_Data&&)__data, (_Child&&)__child...)};
Patrick Williams5932cd62023-11-16 11:13:00 -0600687};
688#endif
689
690template <class _Tag>
691inline constexpr __make_sexpr_t<_Tag> __make_sexpr{};
692} // namespace __detail
693
694using __detail::__make_sexpr;
695
Patrick Williams4c2d73d2023-12-01 16:58:58 -0600696template <class _Tag, class _Data, class... _Child>
697using __sexpr_t = __result_of<__make_sexpr<_Tag>, _Data, _Child...>;
Patrick Williams5932cd62023-11-16 11:13:00 -0600698
699namespace __detail
700{
701struct __sexpr_apply_t
702{
703 template <class _Sender, class _ApplyFn>
704 STDEXEC_ATTRIBUTE((always_inline)) //
705 auto operator()(_Sender&& __sndr, _ApplyFn&& __fun) const //
706 noexcept(noexcept(STDEXEC_CALL_EXPLICIT_THIS_MEMFN(
707 ((_Sender&&)__sndr), apply)((_ApplyFn&&)__fun))) //
708 -> decltype(STDEXEC_CALL_EXPLICIT_THIS_MEMFN(((_Sender&&)__sndr),
709 apply)((_ApplyFn&&)__fun))
710 {
711 return STDEXEC_CALL_EXPLICIT_THIS_MEMFN(((_Sender&&)__sndr),
712 apply)((_ApplyFn&&)__fun); //
713 }
714};
715} // namespace __detail
716
717using __detail::__sexpr_apply_t;
718inline constexpr __sexpr_apply_t __sexpr_apply{};
719
720template <class _Sender, class _ApplyFn>
721using __sexpr_apply_result_t =
722 __call_result_t<__sexpr_apply_t, _Sender, _ApplyFn>;
723
Patrick Williams5932cd62023-11-16 11:13:00 -0600724template <class _Sender>
725concept sender_expr = //
Patrick Williams4c2d73d2023-12-01 16:58:58 -0600726 __mvalid<tag_of_t, _Sender>;
Patrick Williams5932cd62023-11-16 11:13:00 -0600727
728template <class _Sender, class _Tag>
729concept sender_expr_for = //
Patrick Williams4c2d73d2023-12-01 16:58:58 -0600730 sender_expr<_Sender> && same_as<tag_of_t<_Sender>, _Tag>;
Patrick Williams5932cd62023-11-16 11:13:00 -0600731
732// The __name_of utility defined below is used to pretty-print the type names of
733// senders in compiler diagnostics.
734namespace __detail
735{
Patrick Williams5932cd62023-11-16 11:13:00 -0600736struct __basic_sender_name
737{
738 template <class _Sender>
739 using __f = //
740 __call_result_t<__sexpr_apply_result_t<_Sender, __basic_sender_name>>;
741
Patrick Williams4c2d73d2023-12-01 16:58:58 -0600742 template <class _Tag, class _Data, class... _Child>
743 auto operator()(_Tag, _Data&&, _Child&&...) const //
744 -> __sexpr<_Tag, _Data, __name_of<_Child>...> (*)();
Patrick Williams5932cd62023-11-16 11:13:00 -0600745};
746
747struct __id_name
748{
749 template <class _Sender>
750 using __f = __name_of<__id<_Sender>>;
751};
752
753template <class _Sender>
754extern __mcompose<__cplr, __name_of_fn<_Sender>> __name_of_v<_Sender&>;
755
756template <class _Sender>
757extern __mcompose<__cprr, __name_of_fn<_Sender>> __name_of_v<_Sender&&>;
758
759template <class _Sender>
760extern __mcompose<__cpclr, __name_of_fn<_Sender>> __name_of_v<const _Sender&>;
761
762template <class _Impl>
763extern __basic_sender_name __name_of_v<__sexpr<_Impl>>;
764
765template <__has_id _Sender>
766 requires(!same_as<__id<_Sender>, _Sender>)
767extern __id_name __name_of_v<_Sender>;
Patrick Williams5932cd62023-11-16 11:13:00 -0600768} // namespace __detail
Patrick Williams5932cd62023-11-16 11:13:00 -0600769} // namespace stdexec
770
771namespace std
772{
773template <class _Impl>
774struct tuple_size<stdexec::__sexpr<_Impl>> :
775 integral_constant<
776 size_t, stdexec::__v<typename stdexec::__sexpr<_Impl>::__arity_t> + 2>
777{};
778
779template <size_t _Idx, class _Impl>
780struct tuple_element<_Idx, stdexec::__sexpr<_Impl>>
781{
Patrick Williams8723a542024-02-12 11:18:32 -0600782 using type = stdexec::__remove_rvalue_reference_t<stdexec::__call_result_t<
783 _Impl, stdexec::__cp, stdexec::__nth_pack_element_t<_Idx>>>;
Patrick Williams5932cd62023-11-16 11:13:00 -0600784};
785} // namespace std