1 #ifndef PETSC_CPP_REGISTER_FINALIZE_HPP 2 #define PETSC_CPP_REGISTER_FINALIZE_HPP 3 4 #include <petscsys.h> 5 6 #if defined(__cplusplus) 7 #include <petsc/private/cpp/crtp.hpp> 8 9 namespace 10 { 11 12 template <typename T> 13 PETSC_NODISCARD inline PetscErrorCode PetscCxxObjectRegisterFinalize(T *obj, MPI_Comm comm = PETSC_COMM_SELF) noexcept 14 { 15 PetscContainer contain = nullptr; 16 const auto finalizer = [](void *ptr) { 17 PetscFunctionBegin; 18 PetscCall(static_cast<T *>(ptr)->finalize()); 19 PetscFunctionReturn(0); 20 }; 21 22 PetscFunctionBegin; 23 PetscValidPointer(obj, 1); 24 PetscCall(PetscContainerCreate(comm, &contain)); 25 PetscCall(PetscContainerSetPointer(contain, obj)); 26 PetscCall(PetscContainerSetUserDestroy(contain, std::move(finalizer))); 27 PetscCall(PetscObjectRegisterDestroy(reinterpret_cast<PetscObject>(contain))); 28 PetscFunctionReturn(0); 29 } 30 31 } // anonymous namespace 32 33 namespace Petsc 34 { 35 36 template <typename Derived> 37 class RegisterFinalizeable : public util::crtp<Derived, RegisterFinalizeable> { 38 public: 39 using derived_type = Derived; 40 using crtp_type = util::crtp<Derived, RegisterFinalizeable>; 41 42 PETSC_NODISCARD bool registered() const noexcept; 43 template <typename... Args> 44 PETSC_NODISCARD PetscErrorCode finalize(Args &&...) noexcept; 45 template <typename... Args> 46 PETSC_NODISCARD PetscErrorCode register_finalize(MPI_Comm comm = PETSC_COMM_SELF, Args &&...) noexcept; 47 48 private: 49 constexpr RegisterFinalizeable() = default; 50 friend derived_type; 51 52 // default implementations if the derived class does not want to implement them 53 template <typename... Args> 54 PETSC_NODISCARD static PetscErrorCode finalize_(Args &&...) noexcept; 55 template <typename... Args> 56 PETSC_NODISCARD static PetscErrorCode register_finalize_(Args &&...) noexcept; 57 58 bool registered_ = false; 59 }; 60 61 template <typename D> 62 template <typename... Args> 63 inline PetscErrorCode RegisterFinalizeable<D>::finalize_(Args &&...) noexcept 64 { 65 return 0; 66 } 67 68 template <typename D> 69 template <typename... Args> 70 inline PetscErrorCode RegisterFinalizeable<D>::register_finalize_(Args &&...) noexcept 71 { 72 return 0; 73 } 74 75 template <typename D> 76 inline bool RegisterFinalizeable<D>::registered() const noexcept 77 { 78 return registered_; 79 } 80 81 template <typename D> 82 template <typename... Args> 83 inline PetscErrorCode RegisterFinalizeable<D>::finalize(Args &&...args) noexcept 84 { 85 PetscFunctionBegin; 86 // order of registered_ matters here, if the finalizer wants to re-register it should be able to 87 registered_ = false; 88 PetscCall(this->underlying().finalize_(std::forward<Args>(args)...)); 89 PetscFunctionReturn(0); 90 } 91 92 template <typename D> 93 template <typename... Args> 94 inline PetscErrorCode RegisterFinalizeable<D>::register_finalize(MPI_Comm comm, Args &&...args) noexcept 95 { 96 PetscFunctionBegin; 97 if (PetscLikely(this->underlying().registered())) PetscFunctionReturn(0); 98 registered_ = true; 99 PetscCall(this->underlying().register_finalize_(std::forward<Args>(args)...)); 100 PetscCall(PetscCxxObjectRegisterFinalize(this, comm)); 101 PetscFunctionReturn(0); 102 } 103 104 } // namespace Petsc 105 106 #endif // __cplusplus 107 108 #endif // PETSC_CPP_REGISTER_FINALIZE_HPP 109