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 "__execution_fwd.hpp" 19 20 // include these after __execution_fwd.hpp 21 #include "__awaitable.hpp" 22 #include "__completion_signatures.hpp" 23 #include "__concepts.hpp" 24 #include "__connect_awaitable.hpp" 25 #include "__debug.hpp" 26 #include "__env.hpp" 27 #include "__operation_states.hpp" 28 #include "__receivers.hpp" 29 #include "__senders_core.hpp" 30 #include "__transform_completion_signatures.hpp" 31 #include "__transform_sender.hpp" 32 #include "__type_traits.hpp" 33 34 namespace stdexec 35 { 36 ///////////////////////////////////////////////////////////////////////////// 37 // [execution.get_completion_signatures] 38 namespace __detail 39 { 40 struct __dependent_completions 41 {}; 42 43 template <class _Completions> 44 concept __well_formed_sender = 45 __valid_completion_signatures<_Completions> || 46 __same_as<_Completions, _ERROR_<__dependent_completions>>; 47 } // namespace __detail 48 49 using dependent_completions = _ERROR_<__detail::__dependent_completions>; 50 51 namespace __sigs 52 { 53 template <class _Sender, class _Env> 54 using __tfx_sender = 55 transform_sender_result_t<__late_domain_of_t<_Sender, _Env>, _Sender, _Env>; 56 57 template <class _Sender, class... _Env> 58 using __member_result_t = 59 decltype(__declval<_Sender>().get_completion_signatures( 60 __declval<_Env>()...)); 61 62 template <class _Sender, class... _Env> 63 using __static_member_result_t = // 64 decltype(STDEXEC_REMOVE_REFERENCE(_Sender) // 65 ::get_completion_signatures(__declval<_Sender>(), 66 __declval<_Env>()...)); 67 68 template <class _Sender, class... _Env> 69 concept __with_member = __mvalid<__member_result_t, _Sender, _Env...>; 70 71 template <class _Sender, class... _Env> 72 concept __with_static_member = 73 __mvalid<__static_member_result_t, _Sender, _Env...>; 74 75 template <class _Sender, class... _Env> 76 concept __with_tag_invoke = // 77 tag_invocable<get_completion_signatures_t, _Sender, _Env...>; 78 79 template <class _Sender, class... _Env> 80 concept __with_legacy_tag_invoke = // 81 (sizeof...(_Env) == 0) && 82 tag_invocable<get_completion_signatures_t, _Sender, empty_env>; 83 84 template <class _Sender> 85 using __member_alias_t = // 86 typename __decay_t<_Sender>::completion_signatures; 87 88 template <class _Sender> 89 concept __with_member_alias = __mvalid<__member_alias_t, _Sender>; 90 91 struct get_completion_signatures_t 92 { 93 template <class _Sender, class... _Env> 94 static auto __impl() 95 { 96 // Compute the type of the transformed sender: 97 using __tfx_fn = 98 __if_c<sizeof...(_Env) == 0, __mconst<_Sender>, __q<__tfx_sender>>; 99 using _TfxSender = __minvoke<__tfx_fn, _Sender, _Env...>; 100 101 if constexpr (__merror<_TfxSender>) 102 { 103 // Computing the type of the transformed sender returned an error 104 // type. Propagate it. 105 return static_cast<_TfxSender (*)()>(nullptr); 106 } 107 else if constexpr (__with_member_alias<_TfxSender>) 108 { 109 using _Result = __member_alias_t<_TfxSender>; 110 return static_cast<_Result (*)()>(nullptr); 111 } 112 else if constexpr (__with_static_member<_TfxSender, _Env...>) 113 { 114 using _Result = __static_member_result_t<_TfxSender, _Env...>; 115 return static_cast<_Result (*)()>(nullptr); 116 } 117 else if constexpr (__with_member<_TfxSender, _Env...>) 118 { 119 using _Result = __member_result_t<_TfxSender, _Env...>; 120 return static_cast<_Result (*)()>(nullptr); 121 } 122 else if constexpr (__with_tag_invoke<_TfxSender, _Env...>) 123 { 124 using _Result = tag_invoke_result_t<get_completion_signatures_t, 125 _TfxSender, _Env...>; 126 return static_cast<_Result (*)()>(nullptr); 127 } 128 else if constexpr (__with_legacy_tag_invoke<_TfxSender, _Env...>) 129 { 130 // This branch is strictly for backwards compatibility 131 using _Result = tag_invoke_result_t<get_completion_signatures_t, 132 _Sender, empty_env>; 133 return static_cast<_Result (*)()>(nullptr); 134 // [WAR] The explicit cast to bool below is to work around a bug in 135 // nvc++ (nvbug#4707793) 136 } 137 else if constexpr (bool(__awaitable<_TfxSender, 138 __env::__promise<_Env>...>)) 139 { 140 using _AwaitResult = 141 __await_result_t<_TfxSender, __env::__promise<_Env>...>; 142 using _Result = completion_signatures< 143 // set_value_t() or set_value_t(T) 144 __minvoke<__mremove<void, __qf<set_value_t>>, _AwaitResult>, 145 set_error_t(std::exception_ptr), set_stopped_t()>; 146 return static_cast<_Result (*)()>(nullptr); 147 } 148 else if constexpr (sizeof...(_Env) == 0) 149 { 150 // It's possible this is a dependent sender. 151 return static_cast<dependent_completions (*)()>(nullptr); 152 } 153 else if constexpr ((__is_debug_env<_Env> || ...)) 154 { 155 using __tag_invoke::tag_invoke; 156 // This ought to cause a hard error that indicates where the problem 157 // is. 158 using _Completions [[maybe_unused]] = 159 tag_invoke_result_t<get_completion_signatures_t, _Sender, 160 _Env...>; 161 return static_cast<__debug::__completion_signatures (*)()>(nullptr); 162 } 163 else 164 { 165 using _Result = __mexception<_UNRECOGNIZED_SENDER_TYPE_<>, 166 _WITH_SENDER_<_Sender>, 167 _WITH_ENVIRONMENT_<_Env>...>; 168 return static_cast<_Result (*)()>(nullptr); 169 } 170 } 171 172 // NOT TO SPEC: if we're unable to compute the completion signatures, 173 // return an error type instead of SFINAE. 174 template <class _Sender, class... _Env> 175 requires(sizeof...(_Env) <= 1) 176 constexpr auto operator()(_Sender&&, _Env&&...) const noexcept // 177 -> decltype(__impl<_Sender, _Env...>()()) 178 { 179 return {}; 180 } 181 }; 182 } // namespace __sigs 183 184 using __sigs::get_completion_signatures_t; 185 inline constexpr get_completion_signatures_t get_completion_signatures{}; 186 187 ///////////////////////////////////////////////////////////////////////////// 188 // [execution.senders.connect] 189 namespace __connect 190 { 191 template <class _Sender, class _Receiver> 192 using __tfx_sender = // 193 transform_sender_result_t<__late_domain_of_t<_Sender, env_of_t<_Receiver>>, 194 _Sender, env_of_t<_Receiver>>; 195 196 template <class _Sender, class _Receiver> 197 using __member_result_t = 198 decltype(__declval<_Sender>().connect(__declval<_Receiver>())); 199 200 template <class _Sender, class _Receiver> 201 using __static_member_result_t = 202 decltype(STDEXEC_REMOVE_REFERENCE(_Sender) // 203 ::connect(__declval<_Sender>(), __declval<_Receiver>())); 204 205 template <class _Sender, class _Receiver> 206 concept __with_member = __mvalid<__member_result_t, _Sender, _Receiver>; 207 208 template <class _Sender, class _Receiver> 209 concept __with_static_member = 210 __mvalid<__static_member_result_t, _Sender, _Receiver>; 211 212 template <class _Sender, class _Receiver> 213 concept __with_tag_invoke = tag_invocable<connect_t, _Sender, _Receiver>; 214 215 template <class _Sender, class _Receiver> 216 concept __with_co_await = __callable<__connect_awaitable_t, _Sender, _Receiver>; 217 218 struct connect_t 219 { 220 template <class _Sender, class _Env> 221 static constexpr auto __check_signatures() -> bool 222 { 223 if constexpr (sender_in<_Sender, _Env>) 224 { 225 // Instantiate __debug_sender via completion_signatures_of_t to 226 // check that the actual completions match the expected completions. 227 // 228 // Instantiate completion_signatures_of_t only if sender_in is true 229 // to workaround Clang not implementing CWG#2369 yet (connect() does 230 // not have a constraint for _Sender satisfying sender_in). 231 using __checked_signatures 232 [[maybe_unused]] = completion_signatures_of_t<_Sender, _Env>; 233 } 234 return true; 235 } 236 237 template <class _Sender, class _Receiver> 238 static constexpr auto __select_impl() noexcept 239 { 240 using _Domain = __late_domain_of_t<_Sender, env_of_t<_Receiver>>; 241 using _TfxSender = __tfx_sender<_Sender, _Receiver>; 242 constexpr bool _NothrowTfxSender = 243 __nothrow_callable<transform_sender_t, _Domain, _Sender, 244 env_of_t<_Receiver>>; 245 246 #if STDEXEC_ENABLE_EXTRA_TYPE_CHECKING() 247 static_assert(__check_signatures<_TfxSender, env_of_t<_Receiver>>()); 248 #endif 249 250 if constexpr (__with_static_member<_TfxSender, _Receiver>) 251 { 252 using _Result = __static_member_result_t<_TfxSender, _Receiver>; 253 constexpr bool _Nothrow = // 254 _NothrowTfxSender&& noexcept(__declval<_TfxSender>().connect( 255 __declval<_TfxSender>(), __declval<_Receiver>())); 256 return static_cast<_Result (*)() noexcept(_Nothrow)>(nullptr); 257 } 258 else if constexpr (__with_member<_TfxSender, _Receiver>) 259 { 260 using _Result = __member_result_t<_TfxSender, _Receiver>; 261 constexpr bool _Nothrow = // 262 _NothrowTfxSender&& noexcept( 263 __declval<_TfxSender>().connect(__declval<_Receiver>())); 264 return static_cast<_Result (*)() noexcept(_Nothrow)>(nullptr); 265 } 266 else if constexpr (__with_tag_invoke<_TfxSender, _Receiver>) 267 { 268 using _Result = 269 tag_invoke_result_t<connect_t, _TfxSender, _Receiver>; 270 constexpr bool _Nothrow = // 271 _NothrowTfxSender && 272 nothrow_tag_invocable<connect_t, _TfxSender, _Receiver>; 273 return static_cast<_Result (*)() noexcept(_Nothrow)>(nullptr); 274 } 275 else if constexpr (__with_co_await<_TfxSender, _Receiver>) 276 { 277 using _Result = 278 __call_result_t<__connect_awaitable_t, _TfxSender, _Receiver>; 279 return static_cast<_Result (*)()>(nullptr); 280 } 281 else 282 { 283 using _Result = __debug::__debug_operation; 284 return static_cast<_Result (*)() noexcept(_NothrowTfxSender)>( 285 nullptr); 286 } 287 } 288 289 template <class _Sender, class _Receiver> 290 using __select_impl_t = decltype(__select_impl<_Sender, _Receiver>()); 291 292 template <sender _Sender, receiver _Receiver> 293 requires __with_static_member<__tfx_sender<_Sender, _Receiver>, 294 _Receiver> || 295 __with_member<__tfx_sender<_Sender, _Receiver>, _Receiver> || 296 __with_tag_invoke<__tfx_sender<_Sender, _Receiver>, 297 _Receiver> || 298 __with_co_await<__tfx_sender<_Sender, _Receiver>, _Receiver> || 299 __is_debug_env<env_of_t<_Receiver>> 300 auto operator()(_Sender&& __sndr, _Receiver&& __rcvr) const 301 noexcept(__nothrow_callable<__select_impl_t<_Sender, _Receiver>>) 302 -> __call_result_t<__select_impl_t<_Sender, _Receiver>> 303 { 304 using _TfxSender = __tfx_sender<_Sender, _Receiver>; 305 auto&& __env = get_env(__rcvr); 306 auto __domain = __get_late_domain(__sndr, __env); 307 308 if constexpr (__with_static_member<_TfxSender, _Receiver>) 309 { 310 static_assert( 311 operation_state< 312 __static_member_result_t<_TfxSender, _Receiver>>, 313 "Sender::connect(sender, receiver) must return a type that " 314 "satisfies the operation_state concept"); 315 auto&& __tfx_sndr = transform_sender( 316 __domain, static_cast<_Sender&&>(__sndr), __env); 317 return __tfx_sndr.connect(static_cast<_TfxSender&&>(__tfx_sndr), 318 static_cast<_Receiver&&>(__rcvr)); 319 } 320 else if constexpr (__with_member<_TfxSender, _Receiver>) 321 { 322 static_assert( 323 operation_state<__member_result_t<_TfxSender, _Receiver>>, 324 "sender.connect(receiver) must return a type that " 325 "satisfies the operation_state concept"); 326 return transform_sender(__domain, static_cast<_Sender&&>(__sndr), 327 __env) 328 .connect(static_cast<_Receiver&&>(__rcvr)); 329 } 330 else if constexpr (__with_tag_invoke<_TfxSender, _Receiver>) 331 { 332 static_assert( 333 operation_state< 334 tag_invoke_result_t<connect_t, _TfxSender, _Receiver>>, 335 "stdexec::connect(sender, receiver) must return a type that " 336 "satisfies the operation_state concept"); 337 return tag_invoke(connect_t(), 338 transform_sender(__domain, 339 static_cast<_Sender&&>(__sndr), 340 __env), 341 static_cast<_Receiver&&>(__rcvr)); 342 } 343 else if constexpr (__with_co_await<_TfxSender, _Receiver>) 344 { 345 return __connect_awaitable( // 346 transform_sender(__domain, static_cast<_Sender&&>(__sndr), 347 __env), 348 static_cast<_Receiver&&>(__rcvr)); 349 } 350 else 351 { 352 // This should generate an instantiation backtrace that contains 353 // useful debugging information. 354 using __tag_invoke::tag_invoke; 355 tag_invoke(*this, 356 transform_sender(__domain, 357 static_cast<_Sender&&>(__sndr), __env), 358 static_cast<_Receiver&&>(__rcvr)); 359 } 360 } 361 362 static constexpr auto query(forwarding_query_t) noexcept -> bool 363 { 364 return false; 365 } 366 }; 367 } // namespace __connect 368 369 using __connect::connect_t; 370 inline constexpr __connect::connect_t connect{}; 371 372 ///////////////////////////////////////////////////////////////////////////// 373 // [exec.snd] 374 template <class _Sender, class _Receiver> 375 concept sender_to = // 376 receiver<_Receiver> // 377 && sender_in<_Sender, env_of_t<_Receiver>> // 378 && __receiver_from<_Receiver, _Sender> // 379 && requires(_Sender&& __sndr, _Receiver&& __rcvr) { 380 connect(static_cast<_Sender&&>(__sndr), 381 static_cast<_Receiver&&>(__rcvr)); 382 }; 383 384 template <class _Tag, class... _Args> 385 auto __tag_of_sig_(_Tag (*)(_Args...)) -> _Tag; 386 template <class _Sig> 387 using __tag_of_sig_t = 388 decltype(stdexec::__tag_of_sig_(static_cast<_Sig*>(nullptr))); 389 390 template <class _Sender, class _SetSig, class _Env = empty_env> 391 concept sender_of = // 392 sender_in<_Sender, _Env> // 393 && 394 same_as< 395 __types<_SetSig>, 396 __gather_completions_of< 397 __tag_of_sig_t<_SetSig>, _Sender, _Env, 398 __mcompose_q<__types, __qf<__tag_of_sig_t<_SetSig>>::template __f>, 399 __mconcat<__qq<__types>>>>; 400 401 template <class _Error> 402 requires false 403 using __nofail_t = _Error; 404 405 template <class _Sender, class _Env = empty_env> 406 concept __nofail_sender = 407 sender_in<_Sender, _Env> && 408 requires { 409 typename __gather_completion_signatures< 410 __completion_signatures_of_t<_Sender, _Env>, set_error_t, 411 __nofail_t, __sigs::__default_completion, __types>; 412 }; 413 414 ///////////////////////////////////////////////////////////////////////////// 415 // early sender type-checking 416 template <class _Sender> 417 concept __well_formed_sender = __detail::__well_formed_sender<__minvoke< 418 __with_default_q<__completion_signatures_of_t, dependent_completions>, 419 _Sender>>; 420 } // namespace stdexec 421