xref: /petsc/include/petsc/private/cpp/register_finalize.hpp (revision 6a205d90b50912c88a5a12ff27ab96e75fb87d0e)
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