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