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