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 "__concepts.hpp"
19 #include "__execution_fwd.hpp"
20 #include "__senders_core.hpp"
21 #include "__tuple.hpp"
22 #include "__type_traits.hpp"
23
24 namespace stdexec
25 {
26 // NOT TO SPEC:
27 namespace __closure
28 {
29 template <__class _Dp>
30 struct sender_adaptor_closure;
31 } // namespace __closure
32
33 using __closure::sender_adaptor_closure;
34
35 template <class _Tp>
36 concept __sender_adaptor_closure =
37 derived_from<__decay_t<_Tp>, sender_adaptor_closure<__decay_t<_Tp>>> &&
38 move_constructible<__decay_t<_Tp>> //
39 && constructible_from<__decay_t<_Tp>, _Tp>;
40
41 template <class _Tp, class _Sender>
42 concept __sender_adaptor_closure_for = //
43 __sender_adaptor_closure<_Tp> //
44 && sender<__decay_t<_Sender>> //
45 && __callable<_Tp, __decay_t<_Sender>> //
46 && sender<__call_result_t<_Tp, __decay_t<_Sender>>>;
47
48 namespace __closure
49 {
50 template <class _T0, class _T1>
51 struct __compose : sender_adaptor_closure<__compose<_T0, _T1>>
52 {
53 STDEXEC_ATTRIBUTE((no_unique_address))
54 _T0 __t0_;
55 STDEXEC_ATTRIBUTE((no_unique_address))
56 _T1 __t1_;
57
58 template <sender _Sender>
59 requires __callable<_T0, _Sender> &&
60 __callable<_T1, __call_result_t<_T0, _Sender>>
61 STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__closure::__compose62 __call_result_t<_T1, __call_result_t<_T0, _Sender>> operator()(
63 _Sender&& __sndr) &&
64 {
65 return static_cast<_T1&&>(__t1_)(
66 static_cast<_T0&&>(__t0_)(static_cast<_Sender&&>(__sndr)));
67 }
68
69 template <sender _Sender>
70 requires __callable<const _T0&, _Sender> &&
71 __callable<const _T1&, __call_result_t<const _T0&, _Sender>>
72 STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__closure::__compose73 __call_result_t<_T1, __call_result_t<_T0, _Sender>> operator()(
74 _Sender&& __sndr) const&
75 {
76 return __t1_(__t0_(static_cast<_Sender&&>(__sndr)));
77 }
78 };
79
80 template <__class _Dp>
81 struct sender_adaptor_closure
82 {};
83
84 template <sender _Sender, __sender_adaptor_closure_for<_Sender> _Closure>
85 STDEXEC_ATTRIBUTE((always_inline))
operator |(_Sender && __sndr,_Closure && __clsur)86 __call_result_t<_Closure, _Sender> operator|(_Sender&& __sndr,
87 _Closure&& __clsur)
88 {
89 return static_cast<_Closure&&>(__clsur)(static_cast<_Sender&&>(__sndr));
90 }
91
92 template <__sender_adaptor_closure _T0, __sender_adaptor_closure _T1>
93 STDEXEC_ATTRIBUTE((always_inline))
operator |(_T0 && __t0,_T1 && __t1)94 __compose<__decay_t<_T0>, __decay_t<_T1>> operator|(_T0&& __t0, _T1&& __t1)
95 {
96 return {{}, static_cast<_T0&&>(__t0), static_cast<_T1&&>(__t1)};
97 }
98
99 template <class _Fun, class... _As>
100 struct __binder_back :
101 __tuple_for<_As...>,
102 sender_adaptor_closure<__binder_back<_Fun, _As...>>
103 {
104 STDEXEC_ATTRIBUTE((no_unique_address))
105 _Fun __fun_{};
106
107 #if STDEXEC_INTELLISENSE()
108 // MSVCBUG
109 // https://developercommunity.visualstudio.com/t/rejects-valid-EDG-invocation-of-lambda/10786020
110
111 template <class _Sender>
112 struct __lambda_rvalue
113 {
114 __binder_back& __self_;
115 _Sender& __sndr_;
116
117 STDEXEC_ATTRIBUTE((host, device, always_inline))
operator ()stdexec::__closure::__binder_back::__lambda_rvalue118 auto operator()(_As&... __as) const //
119 noexcept(__nothrow_callable<_Fun, _Sender, _As...>)
120 -> __call_result_t<_Fun, _Sender, _As...>
121 {
122 return static_cast<_Fun&&>(__self_.__fun_)(
123 static_cast<_Sender&&>(__sndr_), static_cast<_As&&>(__as)...);
124 }
125 };
126
127 template <class _Sender>
128 struct __lambda_lvalue
129 {
130 const __binder_back& __self_;
131 _Sender& __sndr_;
132
133 STDEXEC_ATTRIBUTE((host, device, always_inline))
operator ()stdexec::__closure::__binder_back::__lambda_lvalue134 auto operator()(const _As&... __as) const //
135 noexcept(__nothrow_callable<const _Fun&, _Sender, const _As&...>)
136 -> __call_result_t<const _Fun&, _Sender, const _As&...>
137 {
138 return __self_.__fun_(static_cast<_Sender&&>(__sndr_), __as...);
139 }
140 };
141 #endif
142
143 template <sender _Sender>
144 requires __callable<_Fun, _Sender, _As...>
145 STDEXEC_ATTRIBUTE((host, device, always_inline))
operator ()stdexec::__closure::__binder_back146 auto operator()(_Sender&& __sndr) && //
147 noexcept(__nothrow_callable<_Fun, _Sender, _As...>)
148 -> __call_result_t<_Fun, _Sender, _As...>
149 {
150 #if STDEXEC_INTELLISENSE()
151 return this->apply(__lambda_rvalue<_Sender>{*this, __sndr}, *this);
152 #else
153 return this->apply(
154 [&__sndr, this](_As&... __as) //
155 noexcept(__nothrow_callable<_Fun, _Sender, _As...>)
156 -> __call_result_t<_Fun, _Sender, _As...> {
157 return static_cast<_Fun&&>(
158 __fun_)(static_cast<_Sender&&>(__sndr),
159 static_cast<_As&&>(__as)...);
160 },
161 *this);
162 #endif
163 }
164
165 template <sender _Sender>
166 requires __callable<const _Fun&, _Sender, const _As&...>
167 STDEXEC_ATTRIBUTE((host, device, always_inline))
operator ()stdexec::__closure::__binder_back168 auto operator()(_Sender&& __sndr) const& //
169 noexcept(__nothrow_callable<const _Fun&, _Sender, const _As&...>)
170 -> __call_result_t<const _Fun&, _Sender, const _As&...>
171 {
172 #if STDEXEC_INTELLISENSE()
173 return this->apply(__lambda_lvalue<_Sender>{*this, __sndr}, *this);
174 #else
175 return this->apply(
176 [&__sndr, this](const _As&... __as) //
177 noexcept(__nothrow_callable<const _Fun&, _Sender, const _As&...>)
178 -> __call_result_t<const _Fun&, _Sender, const _As&...> {
179 return __fun_(static_cast<_Sender&&>(__sndr), __as...);
180 },
181 *this);
182 #endif
183 }
184 };
185 } // namespace __closure
186
187 using __closure::__binder_back;
188 } // namespace stdexec
189