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