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