xref: /petsc/include/petsc/private/cpp/register_finalize.hpp (revision a0c7f9aa3b59be96b422b2e54790cd20c111f46e)
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 // ==========================================================================================
37 // RegisterFinalizeable
38 //
39 // A mixin class that enables registering a finalizer for a class instance to run during
40 // PetscFinalize(). Enables 3 public methods:
41 //
42 // 1. register_finalize() - Register the calling instance to run the member function
43 //    finalize_() during PetscFinalize(). It only registers the class once.
44 // 2. finalize() - Run the member function finalize_() immediately.
45 // 3. registered() - Query whether you are registered.
46 // ==========================================================================================
47 template <typename Derived>
48 class RegisterFinalizeable : public util::crtp<Derived, RegisterFinalizeable> {
49 public:
50   using derived_type = Derived;
51   using crtp_type    = util::crtp<Derived, RegisterFinalizeable>;
52 
53   PETSC_NODISCARD bool registered() const noexcept;
54   template <typename... Args>
55   PETSC_NODISCARD PetscErrorCode finalize(Args &&...) noexcept;
56   template <typename... Args>
57   PETSC_NODISCARD PetscErrorCode register_finalize(Args &&...) noexcept;
58 
59 private:
60   RegisterFinalizeable() = default;
61   friend derived_type;
62 
63   // default implementations if the derived class does not want to implement them
64   template <typename... Args>
65   PETSC_NODISCARD static PetscErrorCode finalize_(Args &&...) noexcept;
66   template <typename... Args>
67   PETSC_NODISCARD static PetscErrorCode register_finalize_(Args &&...) noexcept;
68 
69   bool registered_ = false;
70 };
71 
72 template <typename D>
73 template <typename... Args>
74 inline PetscErrorCode RegisterFinalizeable<D>::finalize_(Args &&...) noexcept
75 {
76   return 0;
77 }
78 
79 template <typename D>
80 template <typename... Args>
81 inline PetscErrorCode RegisterFinalizeable<D>::register_finalize_(Args &&...) noexcept
82 {
83   return 0;
84 }
85 
86 /*
87   RegisterFinalizeable::registered - Determine if the class instance is registered
88 
89   Notes:
90   Returns true if class is registered, false otherwise.
91 */
92 template <typename D>
93 inline bool RegisterFinalizeable<D>::registered() const noexcept
94 {
95   return registered_;
96 }
97 
98 /*
99   RegisterFinalizeable::finalize - Run the finalizer for a class
100 
101   Input Parameters:
102 
103 . ...args - A set of arguments to pass to the finalizer
104 
105   Notes:
106   It is not necessary to implement finalize_() in the derived class (though pretty much
107   pointless), a default (no-op) implementation is provided.
108 
109   Runs the member function finalize_() with args forwarded.
110 
111   "Unregisters" the class from PetscFinalize(). However, it is safe for finalize_() to
112   re-register itself (via register_finalize()). registered() is guaranteed to return false
113   inside finalize_().
114 */
115 template <typename D>
116 template <typename... Args>
117 inline PetscErrorCode RegisterFinalizeable<D>::finalize(Args &&...args) noexcept
118 {
119   PetscFunctionBegin;
120   // order of setting registered_ to false matters here, if the finalizer wants to re-register
121   // it should be able to
122   if (this->underlying().registered()) {
123     registered_ = false;
124     PetscCall(this->underlying().finalize_(std::forward<Args>(args)...));
125   }
126   PetscFunctionReturn(0);
127 }
128 
129 /*
130   RegisterFinalizeable::register_finalize - Register a finalizer to run during PetscFinalize()
131 
132   Input Parameters:
133 . ...args - Additional arguments to pass to the register_finalize_() hook
134 
135   Notes:
136   It is not necessary to implement register_finalize_() in the derived class. A default (no-op)
137   implementation is provided.
138 
139   Before registering the class, the register_finalize_() hook function is run. This is useful
140   for running any one-time setup code before registering. Subsequent invocations of this
141   function (as long as registered() returns true) will not run register_finalize_() again.
142 
143   The class is considered registered before calling the hook, that is registered() will always
144   return true inside register_finalize_(). register_finalize_() is allowed to immediately
145   un-register the class (via finalize()). In this case the finalizer does not run at
146   PetscFinalize(), and registered() returns false after this routine returns.
147 */
148 template <typename D>
149 template <typename... Args>
150 inline PetscErrorCode RegisterFinalizeable<D>::register_finalize(Args &&...args) noexcept
151 {
152   PetscFunctionBegin;
153   if (PetscLikely(this->underlying().registered())) PetscFunctionReturn(0);
154   registered_ = true;
155   PetscCall(this->underlying().register_finalize_(std::forward<Args>(args)...));
156   // Check if registered before we commit to actually register-finalizing. register_finalize_()
157   // is allowed to run its finalizer immediately
158   if (this->underlying().registered()) PetscCall(PetscCxxObjectRegisterFinalize(this));
159   PetscFunctionReturn(0);
160 }
161 
162 } // namespace Petsc
163 
164 #endif // __cplusplus
165 
166 #endif // PETSC_CPP_REGISTER_FINALIZE_HPP
167