xref: /petsc/include/petsc/private/cpp/type_traits.hpp (revision 834855d6effb0d027771461c8e947ee1ce5a1e17)
1 #pragma once
2 
3 #include <petsc/private/petscimpl.h> // _p_PetscObject
4 #include <petsc/private/cpp/macros.hpp>
5 
6 #include <type_traits>
7 
8 namespace Petsc
9 {
10 
11 namespace util
12 {
13 
14 #if PETSC_CPP_VERSION >= 14
15 using std::add_const_t;
16 using std::add_pointer_t;
17 using std::conditional_t;
18 using std::decay_t;
19 using std::enable_if_t;
20 using std::remove_const_t;
21 using std::remove_cv_t;
22 using std::remove_extent_t;
23 using std::remove_pointer_t;
24 using std::remove_reference_t;
25 using std::underlying_type_t;
26 using std::common_type_t;
27 #else  // C++14
28 template <bool B, class T = void>
29 using enable_if_t = typename std::enable_if<B, T>::type;
30 template <bool B, class T, class F>
31 using conditional_t = typename std::conditional<B, T, F>::type;
32 template <class T>
33 using remove_const_t = typename std::remove_const<T>::type;
34 template <class T>
35 using add_const_t = typename std::add_const<T>::type;
36 template <class T>
37 using remove_cv_t = typename std::remove_cv<T>::type;
38 template <class T>
39 using underlying_type_t = typename std::underlying_type<T>::type;
40 template <class T>
41 using remove_pointer_t = typename std::remove_pointer<T>::type;
42 template <class T>
43 using add_pointer_t = typename std::add_pointer<T>::type;
44 template <class T>
45 using decay_t = typename std::decay<T>::type;
46 template <class T>
47 using remove_reference_t = typename std::remove_reference<T>::type;
48 template <class T>
49 using remove_extent_t = typename std::remove_extent<T>::type;
50 template <class... T>
51 using common_type_t = typename std::common_type<T...>::type;
52 #endif // C++14
53 
54 #if PETSC_CPP_VERSION >= 17
55 using std::void_t;
56 using std::invoke_result_t;
57 using std::disjunction;
58 using std::conjunction;
59 #else
60 template <class...>
61 using void_t = void;
62 
63 template <class Func, class... Args>
64 using invoke_result_t = typename std::result_of<Func &&(Args &&...)>::type;
65 
66 template <class...>
67 struct disjunction : std::false_type { };
68 template <class B1>
69 struct disjunction<B1> : B1 { };
70 template <class B1, class... Bn>
71 struct disjunction<B1, Bn...> : conditional_t<bool(B1::value), B1, disjunction<Bn...>> { };
72 
73 template <class...>
74 struct conjunction : std::true_type { };
75 template <class B1>
76 struct conjunction<B1> : B1 { };
77 template <class B1, class... Bn>
78 struct conjunction<B1, Bn...> : conditional_t<bool(B1::value), conjunction<Bn...>, B1> { };
79 #endif
80 
81 #if PETSC_CPP_VERSION >= 20
82 using std::remove_cvref;
83 using std::remove_cvref_t;
84 using std::type_identity;
85 using std::type_identity_t;
86 #else
87 template <class T>
88 struct remove_cvref {
89   using type = remove_cv_t<remove_reference_t<T>>;
90 };
91 
92 template <class T>
93 using remove_cvref_t = typename remove_cvref<T>::type;
94 
95 template <class T>
96 struct type_identity {
97   using type = T;
98 };
99 
100 template <class T>
101 using type_identity_t = typename type_identity<T>::type;
102 #endif // C++20
103 
104 #if PETSC_CPP_VERSION >= 23
105 using std::to_underlying;
106 #else
107 template <typename T>
to_underlying(T value)108 static inline constexpr underlying_type_t<T> to_underlying(T value) noexcept
109 {
110   static_assert(std::is_enum<T>::value, "");
111   return static_cast<underlying_type_t<T>>(value);
112 }
113 
114 #endif
115 
116 template <typename... T>
117 struct always_false : std::false_type { };
118 
119 namespace detail
120 {
121 
122 template <typename T, typename U = _p_PetscObject>
123 struct is_derived_petsc_object_impl : conditional_t<!std::is_same<T, U>::value && std::is_base_of<_p_PetscObject, T>::value, std::true_type, std::false_type> { };
124 
125 template <typename T>
126 struct is_derived_petsc_object_impl<T, decltype(T::hdr)> : conditional_t<std::is_class<T>::value && std::is_standard_layout<T>::value, std::true_type, std::false_type> { };
127 
128 namespace test
129 {
130 
131 struct Empty { };
132 
133 struct IntHdr {
134   int hdr;
135 };
136 
137 struct CPetscObject {
138   _p_PetscObject hdr;
139   int            x;
140 };
141 
142 struct CxxPetscObject {
143   void          *x;
144   _p_PetscObject hdr;
145 };
146 
147 struct CxxDerivedPetscObject : _p_PetscObject { };
148 
149 // PetscObject is not derived from itself
150 static_assert(!::Petsc::util::detail::is_derived_petsc_object_impl<_p_PetscObject>::value, "");
151 // an int is not a PetscObject
152 static_assert(!::Petsc::util::detail::is_derived_petsc_object_impl<int>::value, "");
153 static_assert(!::Petsc::util::detail::is_derived_petsc_object_impl<Empty>::value, "");
154 static_assert(!::Petsc::util::detail::is_derived_petsc_object_impl<IntHdr>::value, "");
155 
156 // each of these should be valid in PetscObjectCast()
157 static_assert(::Petsc::util::detail::is_derived_petsc_object_impl<CPetscObject>::value, "");
158 static_assert(::Petsc::util::detail::is_derived_petsc_object_impl<CxxPetscObject>::value, "");
159 static_assert(::Petsc::util::detail::is_derived_petsc_object_impl<CxxDerivedPetscObject>::value, "");
160 
161 } // namespace test
162 
163 } // namespace detail
164 
165 template <typename T>
166 using is_derived_petsc_object = detail::is_derived_petsc_object_impl<remove_pointer_t<decay_t<T>>>;
167 
168 template <class, template <class> class>
169 struct is_instance : public std::false_type { };
170 
171 template <class T, template <class> class U>
172 struct is_instance<U<T>, U> : public std::true_type { };
173 
174 namespace detail
175 {
176 template <template <class> class B, class E>
177 struct is_crtp_base_of_impl : std::is_base_of<B<E>, E> { };
178 
179 template <template <class> class B, class E, template <class> class F>
180 struct is_crtp_base_of_impl<B, F<E>> : disjunction<std::is_base_of<B<E>, F<E>>, std::is_base_of<B<F<E>>, F<E>>> { };
181 } // namespace detail
182 
183 template <template <class> class B, class E>
184 using is_crtp_base_of = detail::is_crtp_base_of_impl<B, decay_t<E>>;
185 
186 } // namespace util
187 
188 } // namespace Petsc
189 
190 template <typename T>
PetscRemoveConstCast(T & object)191 PETSC_NODISCARD inline constexpr Petsc::util::remove_const_t<T> &PetscRemoveConstCast(T &object) noexcept
192 {
193   return const_cast<Petsc::util::remove_const_t<T> &>(object);
194 }
195 
196 template <typename T>
PetscRemoveConstCast(const T & object)197 PETSC_NODISCARD inline constexpr T &PetscRemoveConstCast(const T &object) noexcept
198 {
199   return const_cast<T &>(object);
200 }
201 
202 template <typename T>
PetscRemoveConstCast(const T * & object)203 PETSC_NODISCARD inline constexpr T *&PetscRemoveConstCast(const T *&object) noexcept
204 {
205   return const_cast<T *&>(object);
206 }
207 
208 template <typename T>
PetscAddConstCast(T & object)209 PETSC_NODISCARD inline constexpr Petsc::util::add_const_t<T> &PetscAddConstCast(T &object) noexcept
210 {
211   return const_cast<Petsc::util::add_const_t<T> &>(std::forward<T>(object));
212 }
213 
214 template <typename T>
PetscAddConstCast(T * & object)215 PETSC_NODISCARD inline constexpr Petsc::util::add_const_t<T> *&PetscAddConstCast(T *&object) noexcept
216 {
217   static_assert(!std::is_const<T>::value, "");
218   return const_cast<Petsc::util::add_const_t<T> *&>(std::forward<T>(object));
219 }
220 
221 // PetscObjectCast() - Cast an object to PetscObject
222 //
223 // input param:
224 // object - the object to cast
225 //
226 // output param:
227 // [return value] - The resulting PetscObject
228 //
229 // notes:
230 // This function checks that the object passed in is in fact a PetscObject, and hence requires
231 // the full definition of the object. This means you must include the appropriate header
232 // containing the _p_<object> struct definition
233 //
234 //   not available from Fortran
235 template <typename T>
PetscObjectCast(T && object)236 PETSC_NODISCARD inline constexpr PetscObject PetscObjectCast(T &&object) noexcept
237 {
238   static_assert(Petsc::util::is_derived_petsc_object<Petsc::util::decay_t<T>>::value, "If this is a PetscObject then the private definition of the struct must be visible for this to work");
239   return (PetscObject)object;
240 }
241 
PetscObjectCast(PetscObject object)242 PETSC_NODISCARD inline constexpr PetscObject PetscObjectCast(PetscObject object) noexcept
243 {
244   return object;
245 }
246 
247 template <typename T>
PetscObjectComm(T && obj)248 PETSC_NODISCARD inline constexpr auto PetscObjectComm(T &&obj) noexcept -> Petsc::util::enable_if_t<!std::is_same<Petsc::util::decay_t<T>, PetscObject>::value, MPI_Comm>
249 {
250   return PetscObjectComm(PetscObjectCast(std::forward<T>(obj)));
251 }
252