1 /* 2 * Copyright (c) 2023 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 "__config.hpp" 19 #include "__concepts.hpp" 20 #include "__type_traits.hpp" 21 22 #include <initializer_list> 23 #include <type_traits> 24 25 namespace stdexec { 26 constexpr std::size_t __npos = ~0UL; 27 28 template <class...> 29 struct __undefined; 30 31 struct __ { }; 32 33 struct __ignore { 34 __ignore() = default; 35 STDEXEC_ATTRIBUTEstdexec::__ignore36 STDEXEC_ATTRIBUTE(always_inline) constexpr __ignore(auto&&...) noexcept { 37 } 38 }; 39 40 #if STDEXEC_MSVC() 41 // MSVCBUG https://developercommunity.visualstudio.com/t/Incorrect-function-template-argument-sub/10437827 42 43 template <std::size_t> 44 struct __ignore_t { 45 __ignore_t() = default; 46 __ignore_tstdexec::__ignore_t47 constexpr __ignore_t(auto&&...) noexcept { 48 } 49 }; 50 #else 51 template <std::size_t> 52 using __ignore_t = __ignore; 53 #endif 54 55 struct __none_such { }; 56 57 namespace { 58 struct __anon { }; 59 } // namespace 60 61 struct __immovable { 62 __immovable() = default; 63 private: 64 STDEXEC_IMMOVABLE(__immovable); 65 }; 66 67 struct __move_only { 68 __move_only() = default; 69 70 __move_only(__move_only&&) noexcept = default; 71 auto operator=(__move_only&&) noexcept -> __move_only& = default; 72 73 __move_only(const __move_only&) = delete; 74 auto operator=(const __move_only&) -> __move_only& = delete; 75 }; 76 77 template <class... _Fns> 78 struct __overload : _Fns... { 79 using _Fns::operator()...; 80 }; 81 82 template <class... _Fns> 83 __overload(_Fns...) -> __overload<_Fns...>; 84 __umax(std::initializer_list<std::size_t> __il)85 inline constexpr auto __umax(std::initializer_list<std::size_t> __il) noexcept -> std::size_t { 86 std::size_t __m = 0; 87 for (std::size_t __i: __il) { 88 if (__i > __m) { 89 __m = __i; 90 } 91 } 92 return __m; 93 } 94 95 inline constexpr auto __pos_of(const bool * const __first,const bool * const __last)96 __pos_of(const bool* const __first, const bool* const __last) noexcept -> std::size_t { 97 for (const bool* __where = __first; __where != __last; ++__where) { 98 if (*__where) { 99 return static_cast<std::size_t>(__where - __first); 100 } 101 } 102 return __npos; 103 } 104 105 template <class _Ty, class... _Ts> __index_of()106 inline constexpr auto __index_of() noexcept -> std::size_t { 107 constexpr bool __same[] = {STDEXEC_IS_SAME(_Ty, _Ts)..., false}; 108 return __pos_of(__same, __same + sizeof...(_Ts)); 109 } 110 111 namespace __detail { 112 template <class _Cpcvref> 113 struct __forward_like_fn { 114 template <class _Uy> STDEXEC_ATTRIBUTEstdexec::__detail::__forward_like_fn115 STDEXEC_ATTRIBUTE(always_inline) 116 constexpr auto operator()(_Uy&& __uy) const noexcept -> auto&& { 117 return static_cast<_Cpcvref::template __f<std::remove_reference_t<_Uy>>>(__uy); 118 } 119 }; 120 } // namespace __detail 121 122 template <class _Ty> 123 inline constexpr __detail::__forward_like_fn<__copy_cvref_fn<_Ty&&>> __forward_like{}; 124 125 STDEXEC_PRAGMA_PUSH() 126 STDEXEC_PRAGMA_IGNORE_GNU("-Wold-style-cast") 127 128 // A derived-to-base cast that works even when the base is not accessible from derived. 129 template <class _Tp, class _Up> STDEXEC_ATTRIBUTE(host,device)130 STDEXEC_ATTRIBUTE(host, device) 131 auto __c_upcast(_Up&& u) noexcept -> __copy_cvref_t<_Up&&, _Tp> 132 requires __decays_to<_Tp, _Tp> 133 { 134 static_assert(STDEXEC_IS_BASE_OF(_Tp, __decay_t<_Up>)); 135 return (__copy_cvref_t<_Up&&, _Tp>) static_cast<_Up&&>(u); 136 } 137 138 // A base-to-derived cast that works even when the base is not accessible from derived. 139 template <class _Tp, class _Up> STDEXEC_ATTRIBUTE(host,device)140 STDEXEC_ATTRIBUTE(host, device) 141 auto __c_downcast(_Up&& u) noexcept -> __copy_cvref_t<_Up&&, _Tp> 142 requires __decays_to<_Tp, _Tp> 143 { 144 static_assert(STDEXEC_IS_BASE_OF(__decay_t<_Up>, _Tp)); 145 return (__copy_cvref_t<_Up&&, _Tp>) static_cast<_Up&&>(u); 146 } 147 148 STDEXEC_PRAGMA_POP() 149 150 template <class _Ty> 151 auto __decay_copy(_Ty) noexcept -> _Ty; 152 153 template <class _Ty> 154 struct __indestructible { 155 template <class... _Us> __indestructiblestdexec::__indestructible156 constexpr __indestructible(_Us&&... __us) noexcept(__nothrow_constructible_from<_Ty, _Us...>) 157 : __value(static_cast<_Us&&>(__us)...) { 158 } 159 ~__indestructiblestdexec::__indestructible160 constexpr ~__indestructible() { 161 } 162 getstdexec::__indestructible163 auto get() noexcept -> _Ty& { 164 return __value; 165 } 166 getstdexec::__indestructible167 auto get() const noexcept -> const _Ty& { 168 return __value; 169 } 170 171 union { 172 _Ty __value; 173 }; 174 }; 175 } // namespace stdexec 176 177 #if defined(__cpp_auto_cast) && (__cpp_auto_cast >= 2021'10L) 178 # define STDEXEC_DECAY_COPY(...) auto(__VA_ARGS__) 179 #else 180 # define STDEXEC_DECAY_COPY(...) (true ? (__VA_ARGS__) : stdexec::__decay_copy(__VA_ARGS__)) 181 #endif 182