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 "../stdexec/execution.hpp" 19 20 #ifdef __EDG__ 21 #pragma diagnostic push 22 #pragma diag_suppress 1302 23 #endif 24 25 namespace exec 26 { 27 template <class... _TagValue> 28 using with_t = stdexec::__with<_TagValue...>; 29 30 namespace __detail 31 { 32 struct __with_t 33 { 34 template <class _Tag, class _Value> 35 with_t<_Tag, _Value> operator()(_Tag, _Value&& __val) const 36 { 37 return stdexec::__with_(_Tag(), (_Value&&)__val); 38 } 39 40 template <class _Tag> 41 with_t<_Tag> operator()(_Tag) const 42 { 43 return stdexec::__with_(_Tag()); 44 } 45 }; 46 } // namespace __detail 47 48 inline constexpr __detail::__with_t with{}; 49 50 inline constexpr stdexec::__env::__make_env_t make_env{}; 51 52 template <class... _Ts> 53 using make_env_t = stdexec::__make_env_t<_Ts...>; 54 55 namespace __read_with_default 56 { 57 using namespace stdexec; 58 59 struct read_with_default_t; 60 61 template <class _Tag, class _DefaultId, class _ReceiverId> 62 struct __operation : __immovable 63 { 64 using _Default = __t<_DefaultId>; 65 using _Receiver = __t<_ReceiverId>; 66 67 STDEXEC_NO_UNIQUE_ADDRESS _Default __default_; 68 _Receiver __rcvr_; 69 70 friend void tag_invoke(start_t, __operation& __self) noexcept 71 { 72 try 73 { 74 if constexpr (__callable<_Tag, env_of_t<_Receiver>>) 75 { 76 const auto& __env = get_env(__self.__rcvr_); 77 set_value(std::move(__self.__rcvr_), _Tag{}(__env)); 78 } 79 else 80 { 81 set_value(std::move(__self.__rcvr_), 82 std::move(__self.__default_)); 83 } 84 } 85 catch (...) 86 { 87 set_error(std::move(__self.__rcvr_), std::current_exception()); 88 } 89 } 90 }; 91 92 template <class _Tag, class _DefaultId> 93 struct __sender 94 { 95 using _Default = __t<_DefaultId>; 96 using is_sender = void; 97 STDEXEC_NO_UNIQUE_ADDRESS _Default __default_; 98 99 template <class _Env> 100 using __value_t = __minvoke< 101 __with_default<__mbind_back_q<__call_result_t, _Env>, _Default>, _Tag>; 102 template <class _Env> 103 using __default_t = __if_c<__callable<_Tag, _Env>, __ignore, _Default>; 104 template <class _Env> 105 using __completions_t = 106 completion_signatures<set_value_t(__value_t<_Env>), 107 set_error_t(std::exception_ptr)>; 108 109 template <__decays_to<__sender> _Self, class _Receiver> 110 requires receiver_of<_Receiver, __completions_t<env_of_t<_Receiver>>> 111 friend auto tag_invoke(connect_t, _Self&& __self, _Receiver __rcvr) // 112 noexcept(std::is_nothrow_move_constructible_v<_Receiver>) 113 -> __operation<_Tag, __x<__default_t<env_of_t<_Receiver>>>, 114 __x<_Receiver>> 115 { 116 return {{}, ((_Self&&)__self).__default_, (_Receiver&&)__rcvr}; 117 } 118 119 friend auto tag_invoke(get_completion_signatures_t, __sender, no_env) 120 -> dependent_completion_signatures<no_env>; 121 template <__none_of<no_env> _Env> 122 friend auto tag_invoke(get_completion_signatures_t, __sender, _Env&&) 123 -> __completions_t<_Env>; 124 }; 125 126 struct __read_with_default_t 127 { 128 template <class _Tag, class _Default> 129 constexpr auto operator()(_Tag, _Default&& __default) const 130 -> __sender<_Tag, __x<__decay_t<_Default>>> 131 { 132 return {(_Default&&)__default}; 133 } 134 }; 135 } // namespace __read_with_default 136 137 inline constexpr __read_with_default::__read_with_default_t read_with_default{}; 138 139 namespace __write 140 { 141 using namespace stdexec; 142 143 struct __write_t; 144 145 template <class _ReceiverId, class _Env> 146 struct __operation_base 147 { 148 using _Receiver = __t<_ReceiverId>; 149 _Receiver __rcvr_; 150 const _Env __env_; 151 }; 152 153 template <class _ReceiverId, class _Env> 154 struct __receiver 155 { 156 using _Receiver = stdexec::__t<_ReceiverId>; 157 158 struct __t : receiver_adaptor<__t> 159 { 160 _Receiver&& base() && noexcept 161 { 162 return (_Receiver&&)__op_->__rcvr_; 163 } 164 165 const _Receiver& base() const& noexcept 166 { 167 return __op_->__rcvr_; 168 } 169 170 auto get_env() const noexcept 171 -> __env::__env_join_t<const _Env&, env_of_t<_Receiver>> 172 { 173 return __env::__join_env(__op_->__env_, stdexec::get_env(base())); 174 } 175 176 __operation_base<_ReceiverId, _Env>* __op_; 177 }; 178 }; 179 180 template <class _SenderId, class _ReceiverId, class _Env> 181 struct __operation : __operation_base<_ReceiverId, _Env> 182 { 183 using _Sender = __t<_SenderId>; 184 using __base_t = __operation_base<_ReceiverId, _Env>; 185 using __receiver_t = __t<__receiver<_ReceiverId, _Env>>; 186 connect_result_t<_Sender, __receiver_t> __state_; 187 188 __operation(_Sender&& __sndr, auto&& __rcvr, auto&& __env) : 189 __base_t{(decltype(__rcvr))__rcvr, (decltype(__env))__env}, 190 __state_{stdexec::connect((_Sender&&)__sndr, __receiver_t{{}, this})} 191 {} 192 193 friend void tag_invoke(start_t, __operation& __self) noexcept 194 { 195 start(__self.__state_); 196 } 197 }; 198 199 template <class _SenderId, class _Env> 200 struct __sender 201 { 202 using _Sender = stdexec::__t<_SenderId>; 203 204 template <class _Receiver> 205 using __receiver_t = stdexec::__t<__receiver<__id<_Receiver>, _Env>>; 206 template <class _Self, class _Receiver> 207 using __operation_t = __operation<__id<__copy_cvref_t<_Self, _Sender>>, 208 __id<_Receiver>, _Env>; 209 210 struct __t 211 { 212 using is_sender = void; 213 using __id = __sender; 214 _Sender __sndr_; 215 _Env __env_; 216 217 template <__decays_to<__t> _Self, receiver _Receiver> 218 requires sender_to<__copy_cvref_t<_Self, _Sender>, 219 __receiver_t<_Receiver>> 220 friend auto tag_invoke(connect_t, _Self&& __self, _Receiver __rcvr) 221 -> __operation_t<_Self, _Receiver> 222 { 223 return {((_Self&&)__self).__sndr_, (_Receiver&&)__rcvr, 224 ((_Self&&)__self).__env_}; 225 } 226 227 friend auto tag_invoke(stdexec::get_env_t, const __t& __self) // 228 noexcept( 229 stdexec::__nothrow_callable<stdexec::get_env_t, const _Sender&>) 230 -> stdexec::env_of_t<const _Sender&> 231 { 232 return stdexec::get_env(__self.__sndr_); 233 } 234 235 template <__decays_to<__t> _Self, class _BaseEnv> 236 friend auto tag_invoke(get_completion_signatures_t, _Self&&, _BaseEnv&&) 237 -> stdexec::__completion_signatures_of_t< 238 __copy_cvref_t<_Self, _Sender>, 239 __env::__env_join_t<_Env, _BaseEnv>>; 240 }; 241 }; 242 243 struct __write_t 244 { 245 template <class _Sender, class... _Funs> 246 using __sender_t = 247 __t<__sender<__id<__decay_t<_Sender>>, 248 __env::__env_join_t<__env::__env_fn<_Funs>...>>>; 249 250 template <__is_not_instance_of<__env::__env_fn> _Sender, class... _Funs> 251 requires sender<_Sender> 252 auto operator()(_Sender&& __sndr, __env::__env_fn<_Funs>... __withs) const 253 -> __sender_t<_Sender, _Funs...> 254 { 255 return {(_Sender&&)__sndr, __env::__join_env(std::move(__withs)...)}; 256 } 257 258 template <class... _Funs> 259 auto operator()(__env::__env_fn<_Funs>... __withs) const 260 -> __binder_back<__write_t, __env::__env_fn<_Funs>...> 261 { 262 return {{}, {}, {std::move(__withs)...}}; 263 } 264 }; 265 } // namespace __write 266 267 inline constexpr __write::__write_t write{}; 268 } // namespace exec 269 270 #ifdef __EDG__ 271 #pragma diagnostic pop 272 #endif 273