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