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