1 /* 2 * Copyright (c) 2025 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 "__config.hpp" 20 #include "__execution_fwd.hpp" 21 #include "__operation_states.hpp" 22 #include "__receivers.hpp" 23 24 #include <memory> 25 26 namespace stdexec { 27 template <class _Rcvr, class _Env = env_of_t<_Rcvr>> 28 struct __rcvr_ref { 29 using receiver_concept = receiver_t; 30 STDEXEC_ATTRIBUTEstdexec::__rcvr_ref31 STDEXEC_ATTRIBUTE(host, device) 32 explicit constexpr __rcvr_ref(_Rcvr& __rcvr) noexcept 33 : __rcvr_{std::addressof(__rcvr)} { 34 } 35 36 template <class... _As> STDEXEC_ATTRIBUTEstdexec::__rcvr_ref37 STDEXEC_ATTRIBUTE(host, device) 38 void set_value(_As&&... __as) noexcept { 39 stdexec::set_value(static_cast<_Rcvr&&>(*__rcvr_), static_cast<_As&&>(__as)...); 40 } 41 42 template <class _Error> STDEXEC_ATTRIBUTEstdexec::__rcvr_ref43 STDEXEC_ATTRIBUTE(host, device) 44 void set_error(_Error&& __err) noexcept { 45 stdexec::set_error(static_cast<_Rcvr&&>(*__rcvr_), static_cast<_Error&&>(__err)); 46 } 47 STDEXEC_ATTRIBUTEstdexec::__rcvr_ref48 STDEXEC_ATTRIBUTE(host, device) void set_stopped() noexcept { 49 stdexec::set_stopped(static_cast<_Rcvr&&>(*__rcvr_)); 50 } 51 52 [[nodiscard]] STDEXEC_ATTRIBUTEstdexec::__rcvr_ref53 STDEXEC_ATTRIBUTE(host, device) auto get_env() const noexcept -> _Env { 54 static_assert( 55 std::is_same_v<_Env, env_of_t<_Rcvr>>, 56 "get_env() must return the same type as env_of_t<_Rcvr>"); 57 return stdexec::get_env(*__rcvr_); 58 } 59 60 private: 61 _Rcvr* __rcvr_; 62 }; 63 64 namespace __detail { 65 template <class _Rcvr, size_t = sizeof(_Rcvr)> STDEXEC_ATTRIBUTE(host,device)66 STDEXEC_ATTRIBUTE(host, device) 67 constexpr auto __is_type_complete(int) noexcept { 68 return true; 69 } 70 71 template <class _Rcvr> STDEXEC_ATTRIBUTE(host,device)72 STDEXEC_ATTRIBUTE(host, device) 73 constexpr auto __is_type_complete(long) noexcept { 74 return false; 75 } 76 } // namespace __detail 77 78 // The __ref_rcvr function and its helpers are used to avoid wrapping a receiver in a 79 // __rcvr_ref when that is possible. The logic goes as follows: 80 81 // 1. If the receiver is an instance of __rcvr_ref, return it. 82 // 2. If the type is incomplete or an operation state, return a __rcvr_ref wrapping the 83 // receiver. 84 // 3. If the receiver is nothrow copy constructible, return it. 85 // 4. Otherwise, return a __rcvr_ref wrapping the receiver. 86 template <class _Env = void, class _Rcvr> STDEXEC_ATTRIBUTE(nodiscard,host,device)87 STDEXEC_ATTRIBUTE(nodiscard, host, device) 88 constexpr auto __ref_rcvr(_Rcvr& __rcvr) noexcept { 89 if constexpr (std::is_same_v<_Env, void>) { 90 return stdexec::__ref_rcvr<env_of_t<_Rcvr>>(__rcvr); 91 } else if constexpr (__is_instance_of<_Rcvr, __rcvr_ref>) { 92 return __rcvr; 93 } else if constexpr (!__detail::__is_type_complete<_Rcvr>(0)) { 94 return __rcvr_ref<_Rcvr, _Env>{__rcvr}; 95 } else if constexpr (operation_state<_Rcvr>) { 96 return __rcvr_ref<_Rcvr, _Env>{__rcvr}; 97 } else if constexpr (__nothrow_constructible_from<_Rcvr, const _Rcvr&>) { 98 return const_cast<const _Rcvr&>(__rcvr); 99 } else { 100 return __rcvr_ref{__rcvr}; 101 } 102 STDEXEC_UNREACHABLE(); 103 } 104 105 template <class _Rcvr, class _Env = env_of_t<_Rcvr>> 106 using __rcvr_ref_t = decltype(stdexec::__ref_rcvr<_Env>(stdexec::__declval<_Rcvr&>())); 107 } // namespace stdexec 108