1 /* 2 * Copyright (c) 2022-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 "../functional.hpp" 19 #include "__concepts.hpp" 20 #include "__diagnostics.hpp" 21 #include "__env.hpp" 22 #include "__execution_fwd.hpp" 23 #include "__tag_invoke.hpp" 24 25 #include <exception> 26 27 namespace stdexec 28 { 29 ///////////////////////////////////////////////////////////////////////////// 30 // [execution.receivers] 31 namespace __rcvrs 32 { 33 struct set_value_t 34 { 35 template <class _Fn, class... _Args> 36 using __f = __minvoke<_Fn, _Args...>; 37 38 template <__same_as<set_value_t> _Self, class _Receiver, class... _As> 39 STDEXEC_ATTRIBUTE((host, device, always_inline)) 40 friend auto tag_invoke(_Self, _Receiver&& __rcvr, _As&&... __as) noexcept 41 -> decltype(static_cast<_Receiver&&>(__rcvr).set_value( 42 static_cast<_As&&>(__as)...)) 43 { 44 static_assert(noexcept(static_cast<_Receiver&&>(__rcvr).set_value( 45 static_cast<_As&&>(__as)...)), 46 "set_value member functions must be noexcept"); 47 static_assert( 48 __same_as<decltype(static_cast<_Receiver&&>(__rcvr).set_value( 49 static_cast<_As&&>(__as)...)), 50 void>, 51 "set_value member functions must return void"); 52 static_cast<_Receiver&&>(__rcvr).set_value(static_cast<_As&&>(__as)...); 53 } 54 55 template <class _Receiver, class... _As> 56 requires tag_invocable<set_value_t, _Receiver, _As...> 57 STDEXEC_ATTRIBUTE((host, device, always_inline)) void 58 operator()(_Receiver&& __rcvr, _As&&... __as) const noexcept 59 { 60 static_assert(nothrow_tag_invocable<set_value_t, _Receiver, _As...>); 61 (void)tag_invoke(stdexec::set_value_t{}, 62 static_cast<_Receiver&&>(__rcvr), 63 static_cast<_As&&>(__as)...); 64 } 65 }; 66 67 struct set_error_t 68 { 69 template <class _Fn, class... _Args> 70 requires(sizeof...(_Args) == 1) 71 using __f = __minvoke<_Fn, _Args...>; 72 73 template <__same_as<set_error_t> _Self, class _Receiver, class _Error> 74 STDEXEC_ATTRIBUTE((host, device, always_inline)) 75 friend auto tag_invoke(_Self, _Receiver&& __rcvr, _Error&& __err) noexcept 76 -> decltype(static_cast<_Receiver&&>(__rcvr).set_error( 77 static_cast<_Error&&>(__err))) 78 { 79 static_assert(noexcept(static_cast<_Receiver&&>(__rcvr).set_error( 80 static_cast<_Error&&>(__err))), 81 "set_error member functions must be noexcept"); 82 static_assert( 83 __same_as<decltype(static_cast<_Receiver&&>(__rcvr).set_error( 84 static_cast<_Error&&>(__err))), 85 void>, 86 "set_error member functions must return void"); 87 static_cast<_Receiver&&>(__rcvr).set_error( 88 static_cast<_Error&&>(__err)); 89 } 90 91 template <class _Receiver, class _Error> 92 requires tag_invocable<set_error_t, _Receiver, _Error> 93 STDEXEC_ATTRIBUTE((host, device, always_inline)) void 94 operator()(_Receiver&& __rcvr, _Error&& __err) const noexcept 95 { 96 static_assert(nothrow_tag_invocable<set_error_t, _Receiver, _Error>); 97 (void)tag_invoke(stdexec::set_error_t{}, 98 static_cast<_Receiver&&>(__rcvr), 99 static_cast<_Error&&>(__err)); 100 } 101 }; 102 103 struct set_stopped_t 104 { 105 template <class _Fn, class... _Args> 106 requires(sizeof...(_Args) == 0) 107 using __f = __minvoke<_Fn, _Args...>; 108 109 template <__same_as<set_stopped_t> _Self, class _Receiver> 110 STDEXEC_ATTRIBUTE((host, device, always_inline)) 111 friend auto tag_invoke(_Self, _Receiver&& __rcvr) noexcept 112 -> decltype(static_cast<_Receiver&&>(__rcvr).set_stopped()) 113 { 114 static_assert(noexcept(static_cast<_Receiver&&>(__rcvr).set_stopped()), 115 "set_stopped member functions must be noexcept"); 116 static_assert( 117 __same_as<decltype(static_cast<_Receiver&&>(__rcvr).set_stopped()), 118 void>, 119 "set_stopped member functions must return void"); 120 static_cast<_Receiver&&>(__rcvr).set_stopped(); 121 } 122 123 template <class _Receiver> 124 requires tag_invocable<set_stopped_t, _Receiver> 125 STDEXEC_ATTRIBUTE((host, device, always_inline)) void 126 operator()(_Receiver&& __rcvr) const noexcept 127 { 128 static_assert(nothrow_tag_invocable<set_stopped_t, _Receiver>); 129 (void)tag_invoke(stdexec::set_stopped_t{}, 130 static_cast<_Receiver&&>(__rcvr)); 131 } 132 }; 133 } // namespace __rcvrs 134 135 using __rcvrs::set_error_t; 136 using __rcvrs::set_stopped_t; 137 using __rcvrs::set_value_t; 138 inline constexpr set_value_t set_value{}; 139 inline constexpr set_error_t set_error{}; 140 inline constexpr set_stopped_t set_stopped{}; 141 142 struct receiver_t 143 { 144 using receiver_concept = receiver_t; // NOT TO SPEC 145 }; 146 147 namespace __detail 148 { 149 template <class _Receiver> 150 concept __enable_receiver = // 151 (STDEXEC_NVHPC(requires { typename _Receiver::receiver_concept; }&&) // 152 derived_from<typename _Receiver::receiver_concept, receiver_t>) || 153 requires { typename _Receiver::is_receiver; } // back-compat, NOT TO SPEC 154 || STDEXEC_IS_BASE_OF(receiver_t, 155 _Receiver); // NOT TO SPEC, for receiver_adaptor 156 } // namespace __detail 157 158 template <class _Receiver> 159 inline constexpr bool enable_receiver = 160 __detail::__enable_receiver<_Receiver>; // NOT TO SPEC 161 162 template <class _Receiver> 163 concept receiver = // 164 enable_receiver<__decay_t<_Receiver>> // 165 && environment_provider<__cref_t<_Receiver>> // 166 && move_constructible<__decay_t<_Receiver>> // 167 && constructible_from<__decay_t<_Receiver>, _Receiver>; 168 169 namespace __detail 170 { 171 template <class _Receiver, class _Tag, class... _Args> 172 auto __try_completion(_Tag (*)(_Args...)) 173 -> __mexception<_MISSING_COMPLETION_SIGNAL_<_Tag(_Args...)>, 174 _WITH_RECEIVER_<_Receiver>>; 175 176 template <class _Receiver, class _Tag, class... _Args> 177 requires nothrow_tag_invocable<_Tag, _Receiver, _Args...> 178 auto __try_completion(_Tag (*)(_Args...)) -> __msuccess; 179 180 template <class _Receiver, class... _Sigs> 181 auto __try_completions(completion_signatures<_Sigs...>*) // 182 -> decltype(( 183 __msuccess(), ..., 184 __detail::__try_completion<_Receiver>(static_cast<_Sigs*>(nullptr)))); 185 } // namespace __detail 186 187 template <class _Receiver, class _Completions> 188 concept receiver_of = // 189 receiver<_Receiver> && // 190 requires(_Completions* __completions) { 191 { 192 __detail::__try_completions<__decay_t<_Receiver>>(__completions) 193 } -> __ok; 194 }; 195 196 template <class _Receiver, class _Sender> 197 concept __receiver_from = 198 receiver_of<_Receiver, 199 __completion_signatures_of_t<_Sender, env_of_t<_Receiver>>>; 200 201 /// A utility for calling set_value with the result of a function invocation: 202 template <bool _CanThrow = false, class _Receiver, class _Fun, class... _As> 203 void __set_value_invoke(_Receiver&& __rcvr, _Fun&& __fun, 204 _As&&... __as) noexcept(!_CanThrow) 205 { 206 if constexpr (_CanThrow || __nothrow_invocable<_Fun, _As...>) 207 { 208 if constexpr (same_as<void, __invoke_result_t<_Fun, _As...>>) 209 { 210 __invoke(static_cast<_Fun&&>(__fun), static_cast<_As&&>(__as)...); 211 stdexec::set_value(static_cast<_Receiver&&>(__rcvr)); 212 } 213 else 214 { 215 set_value(static_cast<_Receiver&&>(__rcvr), 216 __invoke(static_cast<_Fun&&>(__fun), 217 static_cast<_As&&>(__as)...)); 218 } 219 } 220 else 221 { 222 try 223 { 224 stdexec::__set_value_invoke<true>(static_cast<_Receiver&&>(__rcvr), 225 static_cast<_Fun&&>(__fun), 226 static_cast<_As&&>(__as)...); 227 } 228 catch (...) 229 { 230 stdexec::set_error(static_cast<_Receiver&&>(__rcvr), 231 std::current_exception()); 232 } 233 } 234 } 235 } // namespace stdexec 236