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))
62 __call_result_t<_T1, __call_result_t<_T0, _Sender>>
operator ()stdexec::__closure::__compose63 operator()(_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))
73 __call_result_t<_T1, __call_result_t<_T0, _Sender>>
operator ()stdexec::__closure::__compose74 operator()(_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))
86 __call_result_t<_Closure, _Sender>
operator |(_Sender && __sndr,_Closure && __clsur)87 operator|(_Sender&& __sndr, _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 template <sender _Sender>
108 requires __callable<_Fun, _Sender, _As...>
109 STDEXEC_ATTRIBUTE((host, device, always_inline))
operator ()stdexec::__closure::__binder_back110 __call_result_t<_Fun, _Sender, _As...> operator()(
111 _Sender&& __sndr) && noexcept(__nothrow_callable<_Fun, _Sender, _As...>)
112 {
113 return this->apply(
114 [&__sndr, this](_As&... __as) noexcept(
115 __nothrow_callable<_Fun, _Sender, _As...>)
116 -> __call_result_t<_Fun, _Sender, _As...> {
117 return static_cast<_Fun&&>(
118 __fun_)(static_cast<_Sender&&>(__sndr),
119 static_cast<_As&&>(__as)...);
120 },
121 *this);
122 }
123
124 template <sender _Sender>
125 requires __callable<const _Fun&, _Sender, const _As&...>
126 STDEXEC_ATTRIBUTE((host, device, always_inline))
operator ()stdexec::__closure::__binder_back127 auto operator()(_Sender&& __sndr) const& //
128 noexcept(__nothrow_callable<const _Fun&, _Sender, const _As&...>)
129 -> __call_result_t<const _Fun&, _Sender, const _As&...>
130 {
131 return this->apply(
132 [&__sndr, this](const _As&... __as) noexcept(
133 __nothrow_callable<_Fun, _Sender, const _As&...>)
134 -> __call_result_t<const _Fun&, _Sender, const _As&...> {
135 return __fun_(static_cast<_Sender&&>(__sndr), __as...);
136 },
137 *this);
138 }
139 };
140 } // namespace __closure
141
142 using __closure::__binder_back;
143 } // namespace stdexec
144