Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 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" |
Patrick Williams | 8723a54 | 2024-02-12 11:18:32 -0600 | [diff] [blame^] | 19 | #include "__concepts.hpp" |
| 20 | #include "__config.hpp" |
Patrick Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 21 | #include "__env.hpp" |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 22 | #include "__execution_fwd.hpp" |
| 23 | #include "__meta.hpp" |
Patrick Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 24 | #include "__tuple.hpp" |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 25 | #include "__type_traits.hpp" |
| 26 | |
Patrick Williams | 8723a54 | 2024-02-12 11:18:32 -0600 | [diff] [blame^] | 27 | #include <cstddef> |
| 28 | #include <type_traits> |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 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> |
Patrick Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 43 | STDEXEC_ATTRIBUTE((always_inline)) |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 44 | _Tag operator()(_Tag, _Rest&&...) const noexcept |
| 45 | { |
| 46 | return {}; |
| 47 | } |
| 48 | }; |
| 49 | |
| 50 | struct __get_data |
| 51 | { |
| 52 | template <class _Data, class... _Rest> |
Patrick Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 53 | STDEXEC_ATTRIBUTE((always_inline)) |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 54 | _Data&& operator()(__ignore, _Data&& __data, _Rest&&...) const noexcept |
| 55 | { |
| 56 | return (_Data&&)__data; |
| 57 | } |
| 58 | }; |
| 59 | |
| 60 | template <class _Continuation> |
| 61 | struct __get_children |
| 62 | { |
Patrick Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 63 | template <class... _Child> |
| 64 | STDEXEC_ATTRIBUTE((always_inline)) |
| 65 | auto operator()(__ignore, __ignore, _Child&&...) const noexcept |
| 66 | -> __mtype<__minvoke<_Continuation, _Child...>> (*)() |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 67 | { |
| 68 | return nullptr; |
| 69 | } |
| 70 | }; |
| 71 | |
Patrick Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 72 | template <class _Tag, class _Data, class... _Child> |
| 73 | struct __desc |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 74 | { |
Patrick Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 75 | using __tag = _Tag; |
| 76 | using __data = _Data; |
| 77 | using __children = __types<_Child...>; |
| 78 | }; |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 79 | |
Patrick Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 80 | template <class _Fn> |
| 81 | struct __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 | |
| 89 | template <class _Sender, class _Fn> |
| 90 | using __sexpr_uncurry = |
| 91 | __call_result_t<__impl_of<_Sender>, __copy_cvref_fn<_Sender>, |
| 92 | __sexpr_uncurry_fn<_Fn>>; |
| 93 | |
| 94 | template <class _Sender> |
| 95 | using __desc_of = __sexpr_uncurry<_Sender, __q<__desc>>; |
| 96 | |
| 97 | using __get_desc = __sexpr_uncurry_fn<__q<__desc>>; |
| 98 | |
| 99 | template <class _Sender> |
| 100 | extern __q<__midentity> __name_of_v; |
| 101 | |
| 102 | template <class _Sender> |
| 103 | using __name_of_fn = decltype(__name_of_v<_Sender>); |
| 104 | |
| 105 | template <class _Sender> |
| 106 | using __name_of = __minvoke<__name_of_fn<_Sender>, _Sender>; |
| 107 | } // namespace __detail |
| 108 | |
| 109 | template <class _Sender> |
| 110 | using tag_of_t = typename __detail::__desc_of<_Sender>::__tag; |
| 111 | |
| 112 | template <class _Sender> |
| 113 | using __data_of = typename __detail::__desc_of<_Sender>::__data; |
| 114 | |
| 115 | template <class _Sender, class _Continuation = __q<__types>> |
| 116 | using __children_of = // |
| 117 | __mapply<_Continuation, typename __detail::__desc_of<_Sender>::__children>; |
| 118 | |
| 119 | template <class _Ny, class _Sender> |
| 120 | using __nth_child_of = __children_of<_Sender, __mbind_front_q<__m_at, _Ny>>; |
| 121 | |
| 122 | template <std::size_t _Ny, class _Sender> |
| 123 | using __nth_child_of_c = |
| 124 | __children_of<_Sender, __mbind_front_q<__m_at, __msize_t<_Ny>>>; |
| 125 | |
| 126 | template <class _Sender> |
| 127 | using __child_of = __children_of<_Sender, __q<__mfront>>; |
| 128 | |
| 129 | template <class _Sender> |
| 130 | inline constexpr std::size_t __nbr_children_of = |
| 131 | __v<__children_of<_Sender, __msize>>; |
| 132 | |
| 133 | template <class _Fn, class _Tp> |
| 134 | requires __mvalid<tag_of_t, _Tp> && |
| 135 | __mvalid<__detail::__sexpr_uncurry, _Tp, _Fn> |
| 136 | struct __uncurry_<_Fn, _Tp> |
| 137 | { |
| 138 | using __t = __detail::__sexpr_uncurry<_Tp, _Fn>; |
| 139 | }; |
| 140 | |
| 141 | template <class _Tag> |
| 142 | struct __sexpr_impl; |
| 143 | |
| 144 | template <class _Sender> |
| 145 | using __name_of = __detail::__name_of<_Sender>; |
| 146 | |
| 147 | namespace __detail |
| 148 | { |
| 149 | template <class _Sexpr, class _Receiver> |
| 150 | struct __op_state; |
| 151 | |
| 152 | template <class _Sexpr, class _Receiver> |
| 153 | struct __connect_fn; |
| 154 | |
| 155 | template <class _Tag, class _Sexpr, class _Receiver> |
| 156 | using __state_type_t = |
| 157 | __decay_t<__result_of<__sexpr_impl<_Tag>::get_state, _Sexpr, _Receiver&>>; |
| 158 | |
| 159 | template <class _Tag, class _Index, class _Sexpr, class _Receiver> |
| 160 | using __env_type_t = |
| 161 | __result_of<__sexpr_impl<_Tag>::get_env, _Index, |
| 162 | __state_type_t<_Tag, _Sexpr, _Receiver>&, _Receiver&>; |
| 163 | |
| 164 | template <class _Sexpr, class _Receiver> |
| 165 | concept __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 Williams | ac329c5 | 2024-01-03 17:52:04 -0600 | [diff] [blame] | 170 | // // 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 Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 179 | |
| 180 | inline 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 | |
| 194 | inline 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 | |
| 198 | inline 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 | |
| 204 | inline 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 | |
| 213 | inline constexpr auto __start = // |
| 214 | []<class _StartTag = start_t, class... _ChildOps>( |
| 215 | __ignore, __ignore, _ChildOps&... __ops) noexcept |
| 216 | { |
| 217 | (_StartTag()(__ops), ...); |
| 218 | }; |
| 219 | |
| 220 | inline 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 | |
| 229 | inline constexpr auto __get_completion_signagures = // |
| 230 | [](__ignore, __ignore) noexcept { return void(); }; |
| 231 | |
| 232 | template <class _ReceiverId, class _Sexpr, class _Idx> |
| 233 | struct __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 Williams | ac329c5 | 2024-01-03 17:52:04 -0600 | [diff] [blame] | 249 | // 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 Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 258 | |
| 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 | |
| 276 | template <class _Receiver> |
| 277 | using __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 | |
| 282 | template <class _Sexpr, class _Receiver> |
| 283 | struct __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 Williams | ac329c5 | 2024-01-03 17:52:04 -0600 | [diff] [blame] | 296 | _Receiver& __rcvr() & noexcept |
Patrick Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 297 | { |
| 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 | |
| 323 | STDEXEC_PRAGMA_PUSH() |
| 324 | STDEXEC_PRAGMA_IGNORE_GNU("-Winvalid-offsetof") |
| 325 | STDEXEC_PRAGMA_IGNORE_EDG(offset_in_non_POD_nonstandard) |
| 326 | |
| 327 | template <class _Sexpr, class _Receiver> |
| 328 | struct __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 Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 340 | }; |
| 341 | |
| 342 | STDEXEC_PRAGMA_POP() |
| 343 | |
Patrick Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 344 | STDEXEC_PRAGMA_PUSH() |
| 345 | STDEXEC_PRAGMA_IGNORE_GNU("-Wmissing-braces") |
| 346 | |
| 347 | template <class _Sexpr, class _Receiver> |
| 348 | struct __connect_fn |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 349 | { |
Patrick Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 350 | 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 Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 357 | { |
Patrick Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 358 | __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 Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 378 | } |
| 379 | }; |
Patrick Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 380 | STDEXEC_PRAGMA_POP() |
| 381 | |
| 382 | template <class _Sexpr, class _Receiver> |
| 383 | struct __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 Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 390 | using __inner_ops_t = |
Patrick Williams | ac329c5 | 2024-01-03 17:52:04 -0600 | [diff] [blame] | 391 | __result_of<__sexpr_apply, _Sexpr, __connect_fn<_Sexpr, _Receiver>>; |
| 392 | |
Patrick Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 393 | __inner_ops_t __inner_ops_; |
| 394 | |
Patrick Williams | ac329c5 | 2024-01-03 17:52:04 -0600 | [diff] [blame] | 395 | // 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 Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 401 | |
| 402 | __op_state(_Sexpr&& __sexpr, _Receiver __rcvr) : |
| 403 | __op_state::__op_base{(_Sexpr&&)__sexpr, (_Receiver&&)__rcvr}, |
Patrick Williams | ac329c5 | 2024-01-03 17:52:04 -0600 | [diff] [blame] | 404 | __inner_ops_(__sexpr_apply((_Sexpr&&)__sexpr, |
| 405 | __connect_fn<_Sexpr, _Receiver>{this})) |
Patrick Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 406 | {} |
| 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 | |
| 441 | inline 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 Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 451 | } // namespace __detail |
| 452 | |
Patrick Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 453 | struct __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 | |
| 465 | template <class Tag> |
| 466 | struct __sexpr_impl : __sexpr_defaults |
| 467 | {}; |
| 468 | |
| 469 | using __detail::__enable_receiver_from_this; |
| 470 | |
| 471 | template <class _Tag> |
| 472 | using __get_attrs_fn = __result_of<__detail::__drop_front, |
| 473 | __mtypeof<__sexpr_impl<_Tag>::get_attrs>>; |
| 474 | |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 475 | ////////////////////////////////////////////////////////////////////////////////////////////////// |
| 476 | // __sexpr |
| 477 | template <class...> |
| 478 | struct __sexpr |
| 479 | { |
| 480 | using __id = __sexpr; |
| 481 | using __t = __sexpr; |
| 482 | }; |
| 483 | |
| 484 | template <class _ImplFn> |
| 485 | struct __sexpr<_ImplFn> |
| 486 | { |
Patrick Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 487 | using sender_concept = sender_t; |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 488 | using __t = __sexpr; |
| 489 | using __id = __sexpr; |
Patrick Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 490 | 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 Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 494 | using __arity_t = __mapply<__msize, __children_t>; |
| 495 | |
Patrick Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 496 | template <class _Tag> |
| 497 | using __impl = __sexpr_impl<__meval<__msecond, _Tag, __tag_t>>; |
| 498 | |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 499 | 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 Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 511 | 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 Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 516 | { |
Patrick Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 517 | return __sexpr_apply(__self, |
| 518 | __detail::__drop_front(__impl<_Tag>::get_attrs)); |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 519 | } |
| 520 | |
| 521 | template <same_as<get_completion_signatures_t> _Tag, |
| 522 | __decays_to<__sexpr> _Self, class _Env> |
Patrick Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 523 | 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 Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 529 | { |
| 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 Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 536 | 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 Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 543 | { |
Patrick Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 544 | return __impl<_Tag>::connect((_Self&&)__self, (_Receiver&&)__rcvr); |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 545 | } |
| 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 | |
| 578 | template <class _ImplFn> |
| 579 | STDEXEC_ATTRIBUTE((host, device)) |
| 580 | __sexpr(_ImplFn) -> __sexpr<_ImplFn>; |
| 581 | |
| 582 | ////////////////////////////////////////////////////////////////////////////////////////////////// |
| 583 | // __make_sexpr |
| 584 | namespace __detail |
| 585 | { |
| 586 | template <class _Tag> |
| 587 | struct __make_sexpr_t |
| 588 | { |
Patrick Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 589 | template <class _Data = __, class... _Child> |
| 590 | constexpr auto operator()(_Data __data = {}, _Child... __child) const; |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 591 | }; |
| 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 |
| 601 | template <class _Ty> |
| 602 | struct __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. |
| 628 | template <class _Ty> |
| 629 | extern _Ty (*__f)(); |
| 630 | |
| 631 | // Anonymous namespace here is to avoid symbol name collisions with the |
| 632 | // lambda functions returned by __make_tuple. |
| 633 | namespace |
| 634 | { |
| 635 | constexpr 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 | |
| 652 | template <class _Tag> |
Patrick Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 653 | template <class _Data, class... _Child> |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 654 | constexpr auto __make_sexpr_t<_Tag>::operator()(_Data __data, |
Patrick Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 655 | _Child... __child) const |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 656 | { |
| 657 | return __sexpr{__make_tuple(_Tag(), __detail::__mbc(__data), |
Patrick Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 658 | __detail::__mbc(__child)...)}; |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 659 | } |
| 660 | #else |
| 661 | // Anonymous namespace here is to avoid symbol name collisions with the |
| 662 | // lambda functions returned by __make_tuple. |
| 663 | namespace |
| 664 | { |
| 665 | constexpr 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 | |
| 681 | template <class _Tag> |
Patrick Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 682 | template <class _Data, class... _Child> |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 683 | constexpr auto __make_sexpr_t<_Tag>::operator()(_Data __data, |
Patrick Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 684 | _Child... __child) const |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 685 | { |
Patrick Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 686 | return __sexpr{__make_tuple(_Tag(), (_Data&&)__data, (_Child&&)__child...)}; |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 687 | }; |
| 688 | #endif |
| 689 | |
| 690 | template <class _Tag> |
| 691 | inline constexpr __make_sexpr_t<_Tag> __make_sexpr{}; |
| 692 | } // namespace __detail |
| 693 | |
| 694 | using __detail::__make_sexpr; |
| 695 | |
Patrick Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 696 | template <class _Tag, class _Data, class... _Child> |
| 697 | using __sexpr_t = __result_of<__make_sexpr<_Tag>, _Data, _Child...>; |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 698 | |
| 699 | namespace __detail |
| 700 | { |
| 701 | struct __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 | |
| 717 | using __detail::__sexpr_apply_t; |
| 718 | inline constexpr __sexpr_apply_t __sexpr_apply{}; |
| 719 | |
| 720 | template <class _Sender, class _ApplyFn> |
| 721 | using __sexpr_apply_result_t = |
| 722 | __call_result_t<__sexpr_apply_t, _Sender, _ApplyFn>; |
| 723 | |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 724 | template <class _Sender> |
| 725 | concept sender_expr = // |
Patrick Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 726 | __mvalid<tag_of_t, _Sender>; |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 727 | |
| 728 | template <class _Sender, class _Tag> |
| 729 | concept sender_expr_for = // |
Patrick Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 730 | sender_expr<_Sender> && same_as<tag_of_t<_Sender>, _Tag>; |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 731 | |
| 732 | // The __name_of utility defined below is used to pretty-print the type names of |
| 733 | // senders in compiler diagnostics. |
| 734 | namespace __detail |
| 735 | { |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 736 | struct __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 Williams | 4c2d73d | 2023-12-01 16:58:58 -0600 | [diff] [blame] | 742 | template <class _Tag, class _Data, class... _Child> |
| 743 | auto operator()(_Tag, _Data&&, _Child&&...) const // |
| 744 | -> __sexpr<_Tag, _Data, __name_of<_Child>...> (*)(); |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 745 | }; |
| 746 | |
| 747 | struct __id_name |
| 748 | { |
| 749 | template <class _Sender> |
| 750 | using __f = __name_of<__id<_Sender>>; |
| 751 | }; |
| 752 | |
| 753 | template <class _Sender> |
| 754 | extern __mcompose<__cplr, __name_of_fn<_Sender>> __name_of_v<_Sender&>; |
| 755 | |
| 756 | template <class _Sender> |
| 757 | extern __mcompose<__cprr, __name_of_fn<_Sender>> __name_of_v<_Sender&&>; |
| 758 | |
| 759 | template <class _Sender> |
| 760 | extern __mcompose<__cpclr, __name_of_fn<_Sender>> __name_of_v<const _Sender&>; |
| 761 | |
| 762 | template <class _Impl> |
| 763 | extern __basic_sender_name __name_of_v<__sexpr<_Impl>>; |
| 764 | |
| 765 | template <__has_id _Sender> |
| 766 | requires(!same_as<__id<_Sender>, _Sender>) |
| 767 | extern __id_name __name_of_v<_Sender>; |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 768 | } // namespace __detail |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 769 | } // namespace stdexec |
| 770 | |
| 771 | namespace std |
| 772 | { |
| 773 | template <class _Impl> |
| 774 | struct tuple_size<stdexec::__sexpr<_Impl>> : |
| 775 | integral_constant< |
| 776 | size_t, stdexec::__v<typename stdexec::__sexpr<_Impl>::__arity_t> + 2> |
| 777 | {}; |
| 778 | |
| 779 | template <size_t _Idx, class _Impl> |
| 780 | struct tuple_element<_Idx, stdexec::__sexpr<_Impl>> |
| 781 | { |
Patrick Williams | 8723a54 | 2024-02-12 11:18:32 -0600 | [diff] [blame^] | 782 | using type = stdexec::__remove_rvalue_reference_t<stdexec::__call_result_t< |
| 783 | _Impl, stdexec::__cp, stdexec::__nth_pack_element_t<_Idx>>>; |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 784 | }; |
| 785 | } // namespace std |