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 STDEXEC_PRAGMA_PUSH() 21 STDEXEC_PRAGMA_IGNORE_EDG(1302) 22 23 namespace exec 24 { 25 template <class _Tag, class _Value> 26 using with_t = stdexec::__env::__with<_Value, _Tag>; 27 28 namespace __envs 29 { 30 struct __with_t 31 { 32 template <class _Tag, class _Value> operator ()exec::__envs::__with_t33 auto operator()(_Tag, _Value&& __val) const 34 { 35 return stdexec::__env::__with(static_cast<_Value&&>(__val), _Tag()); 36 } 37 }; 38 39 struct __without_t 40 { 41 template <class _Env, class _Tag> operator ()exec::__envs::__without_t42 auto operator()(_Env&& __env, _Tag) const -> decltype(auto) 43 { 44 return stdexec::__env::__without(static_cast<_Env&&>(__env), _Tag()); 45 } 46 }; 47 48 // For making an environment from key/value pairs and optionally 49 // another environment. 50 struct __make_env_t 51 { 52 template <stdexec::__nothrow_move_constructible _Base, 53 stdexec::__nothrow_move_constructible _Env> operator ()exec::__envs::__make_env_t54 auto operator()(_Base&& __base, _Env&& __env) const noexcept 55 -> stdexec::__env::__join_t<_Env, _Base> 56 { 57 return stdexec::__env::__join(static_cast<_Env&&>(__env), 58 static_cast<_Base&&>(__base)); 59 } 60 61 template <stdexec::__nothrow_move_constructible _Env> operator ()exec::__envs::__make_env_t62 auto operator()(_Env&& __env) const noexcept -> _Env 63 { 64 return static_cast<_Env&&>(__env); 65 } 66 }; 67 } // namespace __envs 68 69 inline constexpr __envs::__with_t with{}; 70 inline constexpr __envs::__without_t without{}; 71 inline constexpr __envs::__make_env_t make_env{}; 72 73 template <class... _Ts> 74 using make_env_t = stdexec::__result_of<make_env, _Ts...>; 75 76 namespace __read_with_default 77 { 78 using namespace stdexec; 79 80 struct read_with_default_t; 81 82 template <class _Tag, class _DefaultId, class _ReceiverId> 83 struct __operation 84 { 85 using _Default = stdexec::__t<_DefaultId>; 86 using _Receiver = stdexec::__t<_ReceiverId>; 87 88 struct __t : __immovable 89 { 90 using __id = __operation; 91 92 STDEXEC_ATTRIBUTE((no_unique_address)) 93 _Default __default_; 94 _Receiver __rcvr_; 95 tag_invokeexec::__read_with_default::__operation96 friend void tag_invoke(start_t, __t& __self) noexcept 97 { 98 try 99 { 100 if constexpr (__callable<_Tag, env_of_t<_Receiver>>) 101 { 102 const auto& __env = get_env(__self.__rcvr_); 103 set_value(std::move(__self.__rcvr_), _Tag{}(__env)); 104 } 105 else 106 { 107 set_value(std::move(__self.__rcvr_), 108 std::move(__self.__default_)); 109 } 110 } 111 catch (...) 112 { 113 set_error(std::move(__self.__rcvr_), std::current_exception()); 114 } 115 } 116 }; 117 }; 118 119 template <class _Tag, class _Default, class _Receiver> 120 using __operation_t = __t<__operation<_Tag, __id<_Default>, __id<_Receiver>>>; 121 122 template <class _Tag, class _Default> 123 struct __sender 124 { 125 using __id = __sender; 126 using __t = __sender; 127 using sender_concept = stdexec::sender_t; 128 STDEXEC_ATTRIBUTE((no_unique_address)) 129 _Default __default_; 130 131 template <class _Env> 132 using __value_t = __minvoke< 133 __with_default<__mbind_back_q<__call_result_t, _Env>, _Default>, _Tag>; 134 template <class _Env> 135 using __default_t = __if_c<__callable<_Tag, _Env>, __ignore, _Default>; 136 template <class _Env> 137 using __completions_t = 138 completion_signatures<set_value_t(__value_t<_Env>), 139 set_error_t(std::exception_ptr)>; 140 141 template <__decays_to<__sender> _Self, class _Receiver> 142 requires receiver_of<_Receiver, __completions_t<env_of_t<_Receiver>>> tag_invoke(connect_t,_Self && __self,_Receiver __rcvr)143 friend auto tag_invoke(connect_t, _Self&& __self, _Receiver __rcvr) // 144 noexcept(std::is_nothrow_move_constructible_v<_Receiver>) 145 -> __operation_t<_Tag, __default_t<env_of_t<_Receiver>>, _Receiver> 146 { 147 return {{}, 148 static_cast<_Self&&>(__self).__default_, 149 static_cast<_Receiver&&>(__rcvr)}; 150 } 151 152 template <class _Env> tag_invoke(get_completion_signatures_t,__sender,_Env &&)153 friend auto tag_invoke(get_completion_signatures_t, __sender, _Env&&) 154 -> __completions_t<_Env> 155 { 156 return {}; 157 } 158 }; 159 160 struct __read_with_default_t 161 { 162 template <class _Tag, class _Default> operator ()exec::__read_with_default::__read_with_default_t163 constexpr auto operator()(_Tag, _Default&& __default) const 164 -> __sender<_Tag, __decay_t<_Default>> 165 { 166 return {static_cast<_Default&&>(__default)}; 167 } 168 }; 169 } // namespace __read_with_default 170 171 inline constexpr __read_with_default::__read_with_default_t read_with_default{}; 172 173 inline constexpr stdexec::__write_::__write_t write{}; 174 } // namespace exec 175 176 STDEXEC_PRAGMA_POP() 177