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