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