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