Actual source code: type_traits.hpp

  1: #pragma once

  3: #include <petsc/private/petscimpl.h>
  4: #include <petsc/private/cpp/macros.hpp>

  6: #include <type_traits>

  8: namespace Petsc
  9: {

 11: namespace util
 12: {

 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

 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;

 63: template <class F, class... Args>
 64: using invoke_result_t = typename std::result_of<F && (Args && ...)>::type;

 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...>> { };

 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

 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: };

 92: template <class T>
 93: using remove_cvref_t = typename remove_cvref<T>::type;

 95: template <class T>
 96: struct type_identity {
 97:   using type = T;
 98: };

100: template <class T>
101: using type_identity_t = typename type_identity<T>::type;
102: #endif // C++20

104: #if PETSC_CPP_VERSION >= 23
105: using std::to_underlying;
106: #else
107: template <typename T>
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: }

114: #endif

116: template <typename... T>
117: struct always_false : std::false_type { };

119: namespace detail
120: {

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> { };

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> { };

128: namespace test
129: {

131: struct Empty { };

133: struct IntHdr {
134:   int hdr;
135: };

137: struct CPetscObject {
138:   _p_PetscObject hdr;
139:   int            x;
140: };

142: struct CxxPetscObject {
143:   void          *x;
144:   _p_PetscObject hdr;
145: };

147: struct CxxDerivedPetscObject : _p_PetscObject { };

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, "");

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, "");

161: } // namespace test

163: } // namespace detail

165: template <typename T>
166: using is_derived_petsc_object = detail::is_derived_petsc_object_impl<remove_pointer_t<decay_t<T>>>;

168: template <class, template <class> class>
169: struct is_instance : public std::false_type { };

171: template <class T, template <class> class U>
172: struct is_instance<U<T>, U> : public std::true_type { };

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> { };

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

183: template <template <class> class B, class E>
184: using is_crtp_base_of = detail::is_crtp_base_of_impl<B, decay_t<E>>;

186: } // namespace util

188: } // namespace Petsc

190: template <typename T>
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: }

196: template <typename T>
197: PETSC_NODISCARD inline constexpr T &PetscRemoveConstCast(const T &object) noexcept
198: {
199:   return const_cast<T &>(object);
200: }

202: template <typename T>
203: PETSC_NODISCARD inline constexpr T *&PetscRemoveConstCast(const T *&object) noexcept
204: {
205:   return const_cast<T *&>(object);
206: }

208: template <typename T>
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: }

214: template <typename T>
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: }

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_ struct definition
233: //
234: //   not available from Fortran
235: template <typename T>
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: }

242: PETSC_NODISCARD inline constexpr PetscObject PetscObjectCast(PetscObject object) noexcept
243: {
244:   return object;
245: }

247: template <typename T>
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: }