1 /*
2  * Copyright (c) 2021-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 "../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::prop<_Tag, _Value>;
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::prop{_Tag(), static_cast<_Value&&>(__val)};
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 
startexec::__read_with_default::__operation::__t96         void start() & noexcept
97         {
98             try
99             {
100                 if constexpr (__callable<_Tag, env_of_t<_Receiver>>)
101                 {
102                     const auto& __env = get_env(__rcvr_);
103                     stdexec::set_value(std::move(__rcvr_), _Tag{}(__env));
104                 }
105                 else
106                 {
107                     stdexec::set_value(std::move(__rcvr_),
108                                        std::move(__default_));
109                 }
110             }
111             catch (...)
112             {
113                 stdexec::set_error(std::move(__rcvr_),
114                                    std::current_exception());
115             }
116         }
117     };
118 };
119 
120 template <class _Tag, class _Default, class _Receiver>
121 using __operation_t = __t<__operation<_Tag, __id<_Default>, __id<_Receiver>>>;
122 
123 template <class _Tag, class _Default>
124 struct __sender
125 {
126     using __id = __sender;
127     using __t = __sender;
128     using sender_concept = stdexec::sender_t;
129     STDEXEC_ATTRIBUTE((no_unique_address))
130     _Default __default_;
131 
132     template <class _Env>
133     using __value_t = __minvoke<
134         __with_default<__mbind_back_q<__call_result_t, _Env>, _Default>, _Tag>;
135     template <class _Env>
136     using __default_t = __if_c<__callable<_Tag, _Env>, __ignore, _Default>;
137 
138     template <class _Env>
139     using __completions_t =
140         completion_signatures<set_value_t(__value_t<_Env>),
141                               set_error_t(std::exception_ptr)>;
142 
143     template <__decays_to<__sender> _Self, class _Receiver>
144         requires receiver_of<_Receiver, __completions_t<env_of_t<_Receiver>>>
connectexec::__read_with_default::__sender145     static auto connect(_Self&& __self, _Receiver __rcvr) //
146         noexcept(std::is_nothrow_move_constructible_v<_Receiver>)
147             -> __operation_t<_Tag, __default_t<env_of_t<_Receiver>>, _Receiver>
148     {
149         return {{},
150                 static_cast<_Self&&>(__self).__default_,
151                 static_cast<_Receiver&&>(__rcvr)};
152     }
153 
154     template <class _Env>
get_completion_signaturesexec::__read_with_default::__sender155     auto get_completion_signatures(_Env&&) -> __completions_t<_Env>
156     {
157         return {};
158     }
159 };
160 
161 struct __read_with_default_t
162 {
163     template <class _Tag, class _Default>
operator ()exec::__read_with_default::__read_with_default_t164     constexpr auto operator()(_Tag, _Default&& __default) const
165         -> __sender<_Tag, __decay_t<_Default>>
166     {
167         return {static_cast<_Default&&>(__default)};
168     }
169 };
170 } // namespace __read_with_default
171 
172 inline constexpr __read_with_default::__read_with_default_t read_with_default{};
173 
174 inline constexpr stdexec::__write_::__write_env_t write{};
175 inline constexpr stdexec::__write_::__write_env_t write_env{};
176 } // namespace exec
177 
178 STDEXEC_PRAGMA_POP()
179