xref: /petsc/include/petsc/private/cpp/register_finalize.hpp (revision 4f572ea9526f19623f23a8c158f3503516190bbc)
10e6b6b59SJacob Faibussowitsch #ifndef PETSC_CPP_REGISTER_FINALIZE_HPP
20e6b6b59SJacob Faibussowitsch #define PETSC_CPP_REGISTER_FINALIZE_HPP
30e6b6b59SJacob Faibussowitsch 
40e6b6b59SJacob Faibussowitsch #include <petscsys.h>
50e6b6b59SJacob Faibussowitsch 
60e6b6b59SJacob Faibussowitsch #include <petsc/private/cpp/crtp.hpp>
7acc0297cSJacob Faibussowitsch #include <petsc/private/cpp/type_traits.hpp>
80e6b6b59SJacob Faibussowitsch 
90e6b6b59SJacob Faibussowitsch template <typename T>
10089fb57cSJacob Faibussowitsch inline PetscErrorCode PetscCxxObjectRegisterFinalize(T *obj, MPI_Comm comm = PETSC_COMM_SELF) noexcept
11d71ae5a4SJacob Faibussowitsch {
120e6b6b59SJacob Faibussowitsch   PetscContainer contain   = nullptr;
130e6b6b59SJacob Faibussowitsch   const auto     finalizer = [](void *ptr) {
140e6b6b59SJacob Faibussowitsch     PetscFunctionBegin;
150e6b6b59SJacob Faibussowitsch     PetscCall(static_cast<T *>(ptr)->finalize());
163ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
170e6b6b59SJacob Faibussowitsch   };
180e6b6b59SJacob Faibussowitsch 
190e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
20*4f572ea9SToby Isaac   PetscAssertPointer(obj, 1);
210e6b6b59SJacob Faibussowitsch   PetscCall(PetscContainerCreate(comm, &contain));
220e6b6b59SJacob Faibussowitsch   PetscCall(PetscContainerSetPointer(contain, obj));
230e6b6b59SJacob Faibussowitsch   PetscCall(PetscContainerSetUserDestroy(contain, std::move(finalizer)));
240e6b6b59SJacob Faibussowitsch   PetscCall(PetscObjectRegisterDestroy(reinterpret_cast<PetscObject>(contain)));
253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
260e6b6b59SJacob Faibussowitsch }
270e6b6b59SJacob Faibussowitsch 
28d71ae5a4SJacob Faibussowitsch namespace Petsc
29d71ae5a4SJacob Faibussowitsch {
300e6b6b59SJacob Faibussowitsch 
31503aa7efSJacob Faibussowitsch // ==========================================================================================
32503aa7efSJacob Faibussowitsch // RegisterFinalizeable
33503aa7efSJacob Faibussowitsch //
34503aa7efSJacob Faibussowitsch // A mixin class that enables registering a finalizer for a class instance to run during
35503aa7efSJacob Faibussowitsch // PetscFinalize(). Enables 3 public methods:
36503aa7efSJacob Faibussowitsch //
37503aa7efSJacob Faibussowitsch // 1. register_finalize() - Register the calling instance to run the member function
38503aa7efSJacob Faibussowitsch //    finalize_() during PetscFinalize(). It only registers the class once.
39503aa7efSJacob Faibussowitsch // 2. finalize() - Run the member function finalize_() immediately.
40503aa7efSJacob Faibussowitsch // 3. registered() - Query whether you are registered.
41503aa7efSJacob Faibussowitsch // ==========================================================================================
420e6b6b59SJacob Faibussowitsch template <typename Derived>
43b042f95bSJacob Faibussowitsch class RegisterFinalizeable : public util::crtp<RegisterFinalizeable, Derived> {
440e6b6b59SJacob Faibussowitsch public:
450e6b6b59SJacob Faibussowitsch   using derived_type = Derived;
460e6b6b59SJacob Faibussowitsch 
470e6b6b59SJacob Faibussowitsch   PETSC_NODISCARD bool registered() const noexcept;
480e6b6b59SJacob Faibussowitsch   template <typename... Args>
49089fb57cSJacob Faibussowitsch   PetscErrorCode finalize(Args &&...) noexcept;
500e6b6b59SJacob Faibussowitsch   template <typename... Args>
51acc0297cSJacob Faibussowitsch   PetscErrorCode finalize(Args &&...) const noexcept;
52acc0297cSJacob Faibussowitsch   template <typename... Args>
53089fb57cSJacob Faibussowitsch   PetscErrorCode register_finalize(Args &&...) noexcept;
54acc0297cSJacob Faibussowitsch   template <typename... Args>
55acc0297cSJacob Faibussowitsch   PetscErrorCode register_finalize(Args &&...) const noexcept;
560e6b6b59SJacob Faibussowitsch 
570e6b6b59SJacob Faibussowitsch private:
58acc0297cSJacob Faibussowitsch   constexpr RegisterFinalizeable() noexcept = default;
590e6b6b59SJacob Faibussowitsch   friend derived_type;
600e6b6b59SJacob Faibussowitsch 
61acc0297cSJacob Faibussowitsch   template <typename Self, typename... Args>
62acc0297cSJacob Faibussowitsch   static PetscErrorCode do_finalize_(Self &&, Args &&...) noexcept;
63acc0297cSJacob Faibussowitsch   template <typename Self, typename... Args>
64acc0297cSJacob Faibussowitsch   static PetscErrorCode do_register_finalize_(Self &&, Args &&...) noexcept;
65acc0297cSJacob Faibussowitsch 
660e6b6b59SJacob Faibussowitsch   // default implementations if the derived class does not want to implement them
670e6b6b59SJacob Faibussowitsch   template <typename... Args>
68acc0297cSJacob Faibussowitsch   static constexpr PetscErrorCode finalize_(Args &&...) noexcept;
690e6b6b59SJacob Faibussowitsch   template <typename... Args>
70acc0297cSJacob Faibussowitsch   static constexpr PetscErrorCode register_finalize_(Args &&...) noexcept;
710e6b6b59SJacob Faibussowitsch 
72acc0297cSJacob Faibussowitsch   mutable bool registered_ = false;
730e6b6b59SJacob Faibussowitsch };
740e6b6b59SJacob Faibussowitsch 
750e6b6b59SJacob Faibussowitsch template <typename D>
76acc0297cSJacob Faibussowitsch template <typename Self, typename... Args>
77acc0297cSJacob Faibussowitsch inline PetscErrorCode RegisterFinalizeable<D>::do_finalize_(Self &&self, Args &&...args) noexcept
78acc0297cSJacob Faibussowitsch {
79acc0297cSJacob Faibussowitsch   PetscFunctionBegin;
80acc0297cSJacob Faibussowitsch   // order of setting registered_ to false matters here, if the finalizer wants to re-register
81acc0297cSJacob Faibussowitsch   // it should be able to
82acc0297cSJacob Faibussowitsch   if (self.underlying().registered()) {
83acc0297cSJacob Faibussowitsch     self.registered_ = false;
84acc0297cSJacob Faibussowitsch     PetscCall(self.underlying().finalize_(std::forward<Args>(args)...));
85acc0297cSJacob Faibussowitsch   }
86acc0297cSJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
87acc0297cSJacob Faibussowitsch }
88acc0297cSJacob Faibussowitsch 
89acc0297cSJacob Faibussowitsch template <typename D>
90acc0297cSJacob Faibussowitsch template <typename Self, typename... Args>
91acc0297cSJacob Faibussowitsch inline PetscErrorCode RegisterFinalizeable<D>::do_register_finalize_(Self &&self, Args &&...args) noexcept
92acc0297cSJacob Faibussowitsch {
93acc0297cSJacob Faibussowitsch   PetscFunctionBegin;
94acc0297cSJacob Faibussowitsch   if (PetscLikely(self.underlying().registered())) PetscFunctionReturn(PETSC_SUCCESS);
95acc0297cSJacob Faibussowitsch   self.registered_ = true;
96acc0297cSJacob Faibussowitsch   PetscCall(self.underlying().register_finalize_(std::forward<Args>(args)...));
97acc0297cSJacob Faibussowitsch   // Check if registered before we commit to actually register-finalizing. register_finalize_()
98acc0297cSJacob Faibussowitsch   // is allowed to run its finalizer immediately
99acc0297cSJacob Faibussowitsch   if (self.underlying().registered()) {
100acc0297cSJacob Faibussowitsch     using decayed_type = util::decay_t<Self>;
101acc0297cSJacob Faibussowitsch 
102acc0297cSJacob Faibussowitsch     PetscCall(PetscCxxObjectRegisterFinalize(const_cast<decayed_type *>(std::addressof(self))));
103acc0297cSJacob Faibussowitsch   }
104acc0297cSJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
105acc0297cSJacob Faibussowitsch }
106acc0297cSJacob Faibussowitsch 
107acc0297cSJacob Faibussowitsch template <typename D>
1080e6b6b59SJacob Faibussowitsch template <typename... Args>
109acc0297cSJacob Faibussowitsch inline constexpr PetscErrorCode RegisterFinalizeable<D>::finalize_(Args &&...) noexcept
110d71ae5a4SJacob Faibussowitsch {
1113ba16761SJacob Faibussowitsch   return PETSC_SUCCESS;
1120e6b6b59SJacob Faibussowitsch }
1130e6b6b59SJacob Faibussowitsch 
1140e6b6b59SJacob Faibussowitsch template <typename D>
1150e6b6b59SJacob Faibussowitsch template <typename... Args>
116acc0297cSJacob Faibussowitsch inline constexpr PetscErrorCode RegisterFinalizeable<D>::register_finalize_(Args &&...) noexcept
117d71ae5a4SJacob Faibussowitsch {
1183ba16761SJacob Faibussowitsch   return PETSC_SUCCESS;
1190e6b6b59SJacob Faibussowitsch }
1200e6b6b59SJacob Faibussowitsch 
121503aa7efSJacob Faibussowitsch /*
122503aa7efSJacob Faibussowitsch   RegisterFinalizeable::registered - Determine if the class instance is registered
123503aa7efSJacob Faibussowitsch 
124503aa7efSJacob Faibussowitsch   Notes:
125503aa7efSJacob Faibussowitsch   Returns true if class is registered, false otherwise.
126503aa7efSJacob Faibussowitsch */
1270e6b6b59SJacob Faibussowitsch template <typename D>
128d71ae5a4SJacob Faibussowitsch inline bool RegisterFinalizeable<D>::registered() const noexcept
129d71ae5a4SJacob Faibussowitsch {
1300e6b6b59SJacob Faibussowitsch   return registered_;
1310e6b6b59SJacob Faibussowitsch }
1320e6b6b59SJacob Faibussowitsch 
133503aa7efSJacob Faibussowitsch /*
134503aa7efSJacob Faibussowitsch   RegisterFinalizeable::finalize - Run the finalizer for a class
135503aa7efSJacob Faibussowitsch 
136503aa7efSJacob Faibussowitsch   Input Parameters:
137503aa7efSJacob Faibussowitsch 
138503aa7efSJacob Faibussowitsch . ...args - A set of arguments to pass to the finalizer
139503aa7efSJacob Faibussowitsch 
140503aa7efSJacob Faibussowitsch   Notes:
141503aa7efSJacob Faibussowitsch   It is not necessary to implement finalize_() in the derived class (though pretty much
142503aa7efSJacob Faibussowitsch   pointless), a default (no-op) implementation is provided.
143503aa7efSJacob Faibussowitsch 
144503aa7efSJacob Faibussowitsch   Runs the member function finalize_() with args forwarded.
145503aa7efSJacob Faibussowitsch 
146503aa7efSJacob Faibussowitsch   "Unregisters" the class from PetscFinalize(). However, it is safe for finalize_() to
147503aa7efSJacob Faibussowitsch   re-register itself (via register_finalize()). registered() is guaranteed to return false
148503aa7efSJacob Faibussowitsch   inside finalize_().
149503aa7efSJacob Faibussowitsch */
1500e6b6b59SJacob Faibussowitsch template <typename D>
1510e6b6b59SJacob Faibussowitsch template <typename... Args>
152d71ae5a4SJacob Faibussowitsch inline PetscErrorCode RegisterFinalizeable<D>::finalize(Args &&...args) noexcept
153d71ae5a4SJacob Faibussowitsch {
1540e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
155acc0297cSJacob Faibussowitsch   PetscCall(do_finalize_(*this, std::forward<Args>(args)...));
156acc0297cSJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
157503aa7efSJacob Faibussowitsch }
158acc0297cSJacob Faibussowitsch 
159acc0297cSJacob Faibussowitsch template <typename D>
160acc0297cSJacob Faibussowitsch template <typename... Args>
161acc0297cSJacob Faibussowitsch inline PetscErrorCode RegisterFinalizeable<D>::finalize(Args &&...args) const noexcept
162acc0297cSJacob Faibussowitsch {
163acc0297cSJacob Faibussowitsch   PetscFunctionBegin;
164acc0297cSJacob Faibussowitsch   PetscCall(do_finalize_(*this, std::forward<Args>(args)...));
1653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1660e6b6b59SJacob Faibussowitsch }
1670e6b6b59SJacob Faibussowitsch 
168503aa7efSJacob Faibussowitsch /*
169503aa7efSJacob Faibussowitsch   RegisterFinalizeable::register_finalize - Register a finalizer to run during PetscFinalize()
170503aa7efSJacob Faibussowitsch 
171503aa7efSJacob Faibussowitsch   Input Parameters:
172503aa7efSJacob Faibussowitsch . ...args - Additional arguments to pass to the register_finalize_() hook
173503aa7efSJacob Faibussowitsch 
174503aa7efSJacob Faibussowitsch   Notes:
175503aa7efSJacob Faibussowitsch   It is not necessary to implement register_finalize_() in the derived class. A default (no-op)
176503aa7efSJacob Faibussowitsch   implementation is provided.
177503aa7efSJacob Faibussowitsch 
178503aa7efSJacob Faibussowitsch   Before registering the class, the register_finalize_() hook function is run. This is useful
179503aa7efSJacob Faibussowitsch   for running any one-time setup code before registering. Subsequent invocations of this
180503aa7efSJacob Faibussowitsch   function (as long as registered() returns true) will not run register_finalize_() again.
181503aa7efSJacob Faibussowitsch 
182503aa7efSJacob Faibussowitsch   The class is considered registered before calling the hook, that is registered() will always
183503aa7efSJacob Faibussowitsch   return true inside register_finalize_(). register_finalize_() is allowed to immediately
184503aa7efSJacob Faibussowitsch   un-register the class (via finalize()). In this case the finalizer does not run at
185503aa7efSJacob Faibussowitsch   PetscFinalize(), and registered() returns false after this routine returns.
186503aa7efSJacob Faibussowitsch */
1870e6b6b59SJacob Faibussowitsch template <typename D>
1880e6b6b59SJacob Faibussowitsch template <typename... Args>
189503aa7efSJacob Faibussowitsch inline PetscErrorCode RegisterFinalizeable<D>::register_finalize(Args &&...args) noexcept
190d71ae5a4SJacob Faibussowitsch {
1910e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
192acc0297cSJacob Faibussowitsch   PetscCall(do_register_finalize_(*this, std::forward<Args>(args)...));
193acc0297cSJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
194acc0297cSJacob Faibussowitsch }
195acc0297cSJacob Faibussowitsch 
196acc0297cSJacob Faibussowitsch template <typename D>
197acc0297cSJacob Faibussowitsch template <typename... Args>
198acc0297cSJacob Faibussowitsch inline PetscErrorCode RegisterFinalizeable<D>::register_finalize(Args &&...args) const noexcept
199acc0297cSJacob Faibussowitsch {
200acc0297cSJacob Faibussowitsch   PetscFunctionBegin;
201acc0297cSJacob Faibussowitsch   PetscCall(do_register_finalize_(*this, std::forward<Args>(args)...));
2023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2030e6b6b59SJacob Faibussowitsch }
2040e6b6b59SJacob Faibussowitsch 
2050e6b6b59SJacob Faibussowitsch } // namespace Petsc
2060e6b6b59SJacob Faibussowitsch 
2070e6b6b59SJacob Faibussowitsch #endif // PETSC_CPP_REGISTER_FINALIZE_HPP
208