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