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 "__cpo.hpp" 20 #include "__execution_fwd.hpp" 21 #include "__receivers.hpp" 22 #include "__tag_invoke.hpp" 23 #include "__type_traits.hpp" 24 #include "__utility.hpp" 25 26 namespace stdexec 27 { 28 namespace __adaptors 29 { 30 namespace __no 31 { 32 struct __nope 33 {}; 34 35 struct __receiver : __nope 36 { 37 using receiver_concept = receiver_t; 38 39 void set_error(std::exception_ptr) noexcept; 40 void set_stopped() noexcept; 41 auto get_env() const noexcept -> empty_env; 42 }; 43 } // namespace __no 44 45 using __not_a_receiver = __no::__receiver; 46 47 template <class _Base> 48 struct __adaptor_base 49 { 50 template <class _T1> 51 requires constructible_from<_Base, _T1> __adaptor_basestdexec::__adaptors::__adaptor_base52 explicit __adaptor_base(_T1&& __base) : __base_(static_cast<_T1&&>(__base)) 53 {} 54 55 private: 56 STDEXEC_ATTRIBUTE((no_unique_address)) 57 _Base __base_; 58 59 protected: 60 STDEXEC_ATTRIBUTE((host, device, always_inline)) basestdexec::__adaptors::__adaptor_base61 _Base& base() & noexcept 62 { 63 return __base_; 64 } 65 66 STDEXEC_ATTRIBUTE((host, device, always_inline)) basestdexec::__adaptors::__adaptor_base67 const _Base& base() const& noexcept 68 { 69 return __base_; 70 } 71 72 STDEXEC_ATTRIBUTE((host, device, always_inline)) basestdexec::__adaptors::__adaptor_base73 _Base&& base() && noexcept 74 { 75 return static_cast<_Base&&>(__base_); 76 } 77 }; 78 79 template <derived_from<__no::__nope> _Base> 80 struct __adaptor_base<_Base> 81 {}; 82 83 // BUGBUG Not to spec: on gcc and nvc++, member functions in derived classes 84 // don't shadow type aliases of the same name in base classes. :-O 85 // On mingw gcc, 'bool(type::existing_member_function)' evaluates to true, 86 // but 'int(type::existing_member_function)' is an error (as desired). 87 #define STDEXEC_DISPATCH_MEMBER(_TAG) \ 88 template <class _Self, class... _Ts> \ 89 STDEXEC_ATTRIBUTE((host, device, always_inline)) \ 90 static auto __call_##_TAG(_Self&& __self, _Ts&&... __ts) noexcept \ 91 -> decltype((static_cast<_Self&&>(__self)) \ 92 ._TAG(static_cast<_Ts&&>(__ts)...)) \ 93 { \ 94 static_assert(noexcept((static_cast<_Self&&>(__self)) \ 95 ._TAG(static_cast<_Ts&&>(__ts)...))); \ 96 return static_cast<_Self&&>(__self)._TAG(static_cast<_Ts&&>(__ts)...); \ 97 } /**/ 98 #define STDEXEC_CALL_MEMBER(_TAG, ...) __call_##_TAG(__VA_ARGS__) 99 100 #if STDEXEC_CLANG() 101 // Only clang gets this right. 102 #define STDEXEC_MISSING_MEMBER(_Dp, _TAG) requires { typename _Dp::_TAG; } 103 #define STDEXEC_DEFINE_MEMBER(_TAG) \ 104 STDEXEC_DISPATCH_MEMBER(_TAG) using _TAG = void 105 #else 106 #define STDEXEC_MISSING_MEMBER(_Dp, _TAG) (__missing_##_TAG<_Dp>()) 107 #define STDEXEC_DEFINE_MEMBER(_TAG) \ 108 template <class _Dp> \ 109 static constexpr bool __missing_##_TAG() noexcept \ 110 { \ 111 return requires { requires bool(int(_Dp::_TAG)); }; \ 112 } \ 113 STDEXEC_DISPATCH_MEMBER(_TAG) \ 114 static constexpr int _TAG = 1 /**/ 115 #endif 116 117 template <__class _Derived, class _Base = __not_a_receiver> 118 struct receiver_adaptor : __adaptor_base<_Base>, receiver_t 119 { 120 static constexpr bool __has_base = !derived_from<_Base, __no::__nope>; 121 122 template <class _Self> 123 using __base_from_derived_t = decltype(__declval<_Self>().base()); 124 125 using __get_base_fn = 126 __if_c<__has_base, __mbind_back_q<__copy_cvref_t, _Base>, 127 __q<__base_from_derived_t>>; 128 129 template <class _Self> 130 using __base_t = __minvoke<__get_base_fn, _Self&&>; 131 132 template <class _Self> 133 STDEXEC_ATTRIBUTE((host, device)) __get_basestdexec::__adaptors::receiver_adaptor134 static auto __get_base(_Self&& __self) noexcept -> __base_t<_Self> 135 { 136 if constexpr (__has_base) 137 { 138 return __c_upcast<receiver_adaptor>(static_cast<_Self&&>(__self)) 139 .base(); 140 } 141 else 142 { 143 return static_cast<_Self&&>(__self).base(); 144 } 145 } 146 147 public: 148 using receiver_concept = receiver_t; 149 150 receiver_adaptor() = default; 151 using __adaptor_base<_Base>::__adaptor_base; 152 153 template <class... _As, class _Self = _Derived> 154 requires __callable<set_value_t, __base_t<_Self>, _As...> 155 STDEXEC_ATTRIBUTE((host, device)) set_valuestdexec::__adaptors::receiver_adaptor156 void set_value(_As&&... __as) && noexcept 157 { 158 return stdexec::set_value(__get_base(static_cast<_Self&&>(*this)), 159 static_cast<_As&&>(__as)...); 160 } 161 162 template <class _Error, class _Self = _Derived> 163 requires __callable<set_error_t, __base_t<_Self>, _Error> 164 STDEXEC_ATTRIBUTE((host, device)) set_errorstdexec::__adaptors::receiver_adaptor165 void set_error(_Error&& __err) && noexcept 166 { 167 return stdexec::set_error(__get_base(static_cast<_Self&&>(*this)), 168 static_cast<_Error&&>(__err)); 169 } 170 171 template <class _Self = _Derived> 172 requires __callable<set_stopped_t, __base_t<_Self>> 173 STDEXEC_ATTRIBUTE((host, device)) set_stoppedstdexec::__adaptors::receiver_adaptor174 void set_stopped() && noexcept 175 { 176 return stdexec::set_stopped(__get_base(static_cast<_Self&&>(*this))); 177 } 178 179 template <class _Self = _Derived> 180 STDEXEC_ATTRIBUTE((host, device)) get_envstdexec::__adaptors::receiver_adaptor181 auto get_env() const noexcept -> env_of_t<__base_t<const _Self&>> 182 { 183 return stdexec::get_env(__get_base(static_cast<const _Self&>(*this))); 184 } 185 }; 186 } // namespace __adaptors 187 188 template <__class _Derived, receiver _Base = __adaptors::__not_a_receiver> 189 using receiver_adaptor = __adaptors::receiver_adaptor<_Derived, _Base>; 190 } // namespace stdexec 191