xref: /openbmc/sdbusplus/include/sdbusplus/async/stdexec/__detail/__utility.hpp (revision 10d0b4b7d1498cfd5c3d37edea271a54d1984e41)
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