1a4963045SJacob Faibussowitsch #pragma once
20e6b6b59SJacob Faibussowitsch
30e6b6b59SJacob Faibussowitsch #include <petscsys.h>
40e6b6b59SJacob Faibussowitsch
50e6b6b59SJacob Faibussowitsch #include <petsc/private/cpp/crtp.hpp>
6acc0297cSJacob Faibussowitsch #include <petsc/private/cpp/type_traits.hpp>
70e6b6b59SJacob Faibussowitsch
80e6b6b59SJacob Faibussowitsch template <typename T>
PetscCxxObjectRegisterFinalize(T * obj,MPI_Comm comm=PETSC_COMM_SELF)9089fb57cSJacob Faibussowitsch inline PetscErrorCode PetscCxxObjectRegisterFinalize(T *obj, MPI_Comm comm = PETSC_COMM_SELF) noexcept
10d71ae5a4SJacob Faibussowitsch {
110e6b6b59SJacob Faibussowitsch PetscContainer contain = nullptr;
12*2a8381b2SBarry Smith const auto finalizer = [](PetscCtxRt ctx) {
130e6b6b59SJacob Faibussowitsch PetscFunctionBegin;
14*2a8381b2SBarry Smith PetscCall(static_cast<T *>(*(void **)ctx)->finalize());
153ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
160e6b6b59SJacob Faibussowitsch };
170e6b6b59SJacob Faibussowitsch
180e6b6b59SJacob Faibussowitsch PetscFunctionBegin;
194f572ea9SToby Isaac PetscAssertPointer(obj, 1);
200e6b6b59SJacob Faibussowitsch PetscCall(PetscContainerCreate(comm, &contain));
210e6b6b59SJacob Faibussowitsch PetscCall(PetscContainerSetPointer(contain, obj));
2249abdd8aSBarry Smith PetscCall(PetscContainerSetCtxDestroy(contain, std::move(finalizer)));
230e6b6b59SJacob Faibussowitsch PetscCall(PetscObjectRegisterDestroy(reinterpret_cast<PetscObject>(contain)));
243ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
250e6b6b59SJacob Faibussowitsch }
260e6b6b59SJacob Faibussowitsch
27d71ae5a4SJacob Faibussowitsch namespace Petsc
28d71ae5a4SJacob Faibussowitsch {
290e6b6b59SJacob Faibussowitsch
30503aa7efSJacob Faibussowitsch // ==========================================================================================
31503aa7efSJacob Faibussowitsch // RegisterFinalizeable
32503aa7efSJacob Faibussowitsch //
33503aa7efSJacob Faibussowitsch // A mixin class that enables registering a finalizer for a class instance to run during
34503aa7efSJacob Faibussowitsch // PetscFinalize(). Enables 3 public methods:
35503aa7efSJacob Faibussowitsch //
36503aa7efSJacob Faibussowitsch // 1. register_finalize() - Register the calling instance to run the member function
37503aa7efSJacob Faibussowitsch // finalize_() during PetscFinalize(). It only registers the class once.
38503aa7efSJacob Faibussowitsch // 2. finalize() - Run the member function finalize_() immediately.
39503aa7efSJacob Faibussowitsch // 3. registered() - Query whether you are registered.
40503aa7efSJacob Faibussowitsch // ==========================================================================================
410e6b6b59SJacob Faibussowitsch template <typename Derived>
42b042f95bSJacob Faibussowitsch class RegisterFinalizeable : public util::crtp<RegisterFinalizeable, Derived> {
430e6b6b59SJacob Faibussowitsch public:
440e6b6b59SJacob Faibussowitsch using derived_type = Derived;
450e6b6b59SJacob Faibussowitsch
460e6b6b59SJacob Faibussowitsch PETSC_NODISCARD bool registered() const noexcept;
470e6b6b59SJacob Faibussowitsch template <typename... Args>
48089fb57cSJacob Faibussowitsch PetscErrorCode finalize(Args &&...) noexcept;
490e6b6b59SJacob Faibussowitsch template <typename... Args>
50acc0297cSJacob Faibussowitsch PetscErrorCode finalize(Args &&...) const noexcept;
51acc0297cSJacob Faibussowitsch template <typename... Args>
52089fb57cSJacob Faibussowitsch PetscErrorCode register_finalize(Args &&...) noexcept;
53acc0297cSJacob Faibussowitsch template <typename... Args>
54acc0297cSJacob Faibussowitsch PetscErrorCode register_finalize(Args &&...) const noexcept;
550e6b6b59SJacob Faibussowitsch
560e6b6b59SJacob Faibussowitsch private:
57acc0297cSJacob Faibussowitsch constexpr RegisterFinalizeable() noexcept = default;
580e6b6b59SJacob Faibussowitsch friend derived_type;
590e6b6b59SJacob Faibussowitsch
60acc0297cSJacob Faibussowitsch template <typename Self, typename... Args>
61acc0297cSJacob Faibussowitsch static PetscErrorCode do_finalize_(Self &&, Args &&...) noexcept;
62acc0297cSJacob Faibussowitsch template <typename Self, typename... Args>
63acc0297cSJacob Faibussowitsch static PetscErrorCode do_register_finalize_(Self &&, Args &&...) noexcept;
64acc0297cSJacob Faibussowitsch
650e6b6b59SJacob Faibussowitsch // default implementations if the derived class does not want to implement them
660e6b6b59SJacob Faibussowitsch template <typename... Args>
67acc0297cSJacob Faibussowitsch static constexpr PetscErrorCode finalize_(Args &&...) noexcept;
680e6b6b59SJacob Faibussowitsch template <typename... Args>
69acc0297cSJacob Faibussowitsch static constexpr PetscErrorCode register_finalize_(Args &&...) noexcept;
700e6b6b59SJacob Faibussowitsch
71acc0297cSJacob Faibussowitsch mutable bool registered_ = false;
720e6b6b59SJacob Faibussowitsch };
730e6b6b59SJacob Faibussowitsch
740e6b6b59SJacob Faibussowitsch template <typename D>
75acc0297cSJacob Faibussowitsch template <typename Self, typename... Args>
do_finalize_(Self && self,Args &&...args)76acc0297cSJacob Faibussowitsch inline PetscErrorCode RegisterFinalizeable<D>::do_finalize_(Self &&self, Args &&...args) noexcept
77acc0297cSJacob Faibussowitsch {
78acc0297cSJacob Faibussowitsch PetscFunctionBegin;
79acc0297cSJacob Faibussowitsch // order of setting registered_ to false matters here, if the finalizer wants to re-register
80acc0297cSJacob Faibussowitsch // it should be able to
81acc0297cSJacob Faibussowitsch if (self.underlying().registered()) {
82acc0297cSJacob Faibussowitsch self.registered_ = false;
83acc0297cSJacob Faibussowitsch PetscCall(self.underlying().finalize_(std::forward<Args>(args)...));
84acc0297cSJacob Faibussowitsch }
85acc0297cSJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
86acc0297cSJacob Faibussowitsch }
87acc0297cSJacob Faibussowitsch
88acc0297cSJacob Faibussowitsch template <typename D>
89acc0297cSJacob Faibussowitsch template <typename Self, typename... Args>
do_register_finalize_(Self && self,Args &&...args)90acc0297cSJacob Faibussowitsch inline PetscErrorCode RegisterFinalizeable<D>::do_register_finalize_(Self &&self, Args &&...args) noexcept
91acc0297cSJacob Faibussowitsch {
92acc0297cSJacob Faibussowitsch PetscFunctionBegin;
93acc0297cSJacob Faibussowitsch if (PetscLikely(self.underlying().registered())) PetscFunctionReturn(PETSC_SUCCESS);
94acc0297cSJacob Faibussowitsch self.registered_ = true;
95acc0297cSJacob Faibussowitsch PetscCall(self.underlying().register_finalize_(std::forward<Args>(args)...));
96acc0297cSJacob Faibussowitsch // Check if registered before we commit to actually register-finalizing. register_finalize_()
97acc0297cSJacob Faibussowitsch // is allowed to run its finalizer immediately
98acc0297cSJacob Faibussowitsch if (self.underlying().registered()) {
99acc0297cSJacob Faibussowitsch using decayed_type = util::decay_t<Self>;
100acc0297cSJacob Faibussowitsch
101acc0297cSJacob Faibussowitsch PetscCall(PetscCxxObjectRegisterFinalize(const_cast<decayed_type *>(std::addressof(self))));
102acc0297cSJacob Faibussowitsch }
103acc0297cSJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
104acc0297cSJacob Faibussowitsch }
105acc0297cSJacob Faibussowitsch
106acc0297cSJacob Faibussowitsch template <typename D>
1070e6b6b59SJacob Faibussowitsch template <typename... Args>
finalize_(Args &&...)108acc0297cSJacob Faibussowitsch inline constexpr PetscErrorCode RegisterFinalizeable<D>::finalize_(Args &&...) noexcept
109d71ae5a4SJacob Faibussowitsch {
1103ba16761SJacob Faibussowitsch return PETSC_SUCCESS;
1110e6b6b59SJacob Faibussowitsch }
1120e6b6b59SJacob Faibussowitsch
1130e6b6b59SJacob Faibussowitsch template <typename D>
1140e6b6b59SJacob Faibussowitsch template <typename... Args>
register_finalize_(Args &&...)115acc0297cSJacob Faibussowitsch inline constexpr PetscErrorCode RegisterFinalizeable<D>::register_finalize_(Args &&...) noexcept
116d71ae5a4SJacob Faibussowitsch {
1173ba16761SJacob Faibussowitsch return PETSC_SUCCESS;
1180e6b6b59SJacob Faibussowitsch }
1190e6b6b59SJacob Faibussowitsch
120503aa7efSJacob Faibussowitsch /*
121503aa7efSJacob Faibussowitsch RegisterFinalizeable::registered - Determine if the class instance is registered
122503aa7efSJacob Faibussowitsch
123503aa7efSJacob Faibussowitsch Notes:
124503aa7efSJacob Faibussowitsch Returns true if class is registered, false otherwise.
125503aa7efSJacob Faibussowitsch */
1260e6b6b59SJacob Faibussowitsch template <typename D>
registered() const127d71ae5a4SJacob Faibussowitsch inline bool RegisterFinalizeable<D>::registered() const noexcept
128d71ae5a4SJacob Faibussowitsch {
1290e6b6b59SJacob Faibussowitsch return registered_;
1300e6b6b59SJacob Faibussowitsch }
1310e6b6b59SJacob Faibussowitsch
132503aa7efSJacob Faibussowitsch /*
133503aa7efSJacob Faibussowitsch RegisterFinalizeable::finalize - Run the finalizer for a class
134503aa7efSJacob Faibussowitsch
135503aa7efSJacob Faibussowitsch Input Parameters:
136503aa7efSJacob Faibussowitsch
137503aa7efSJacob Faibussowitsch . ...args - A set of arguments to pass to the finalizer
138503aa7efSJacob Faibussowitsch
139503aa7efSJacob Faibussowitsch Notes:
140503aa7efSJacob Faibussowitsch It is not necessary to implement finalize_() in the derived class (though pretty much
141503aa7efSJacob Faibussowitsch pointless), a default (no-op) implementation is provided.
142503aa7efSJacob Faibussowitsch
143503aa7efSJacob Faibussowitsch Runs the member function finalize_() with args forwarded.
144503aa7efSJacob Faibussowitsch
145503aa7efSJacob Faibussowitsch "Unregisters" the class from PetscFinalize(). However, it is safe for finalize_() to
146503aa7efSJacob Faibussowitsch re-register itself (via register_finalize()). registered() is guaranteed to return false
147503aa7efSJacob Faibussowitsch inside finalize_().
148503aa7efSJacob Faibussowitsch */
1490e6b6b59SJacob Faibussowitsch template <typename D>
1500e6b6b59SJacob Faibussowitsch template <typename... Args>
finalize(Args &&...args)151d71ae5a4SJacob Faibussowitsch inline PetscErrorCode RegisterFinalizeable<D>::finalize(Args &&...args) noexcept
152d71ae5a4SJacob Faibussowitsch {
1530e6b6b59SJacob Faibussowitsch PetscFunctionBegin;
154acc0297cSJacob Faibussowitsch PetscCall(do_finalize_(*this, std::forward<Args>(args)...));
155acc0297cSJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
156503aa7efSJacob Faibussowitsch }
157acc0297cSJacob Faibussowitsch
158acc0297cSJacob Faibussowitsch template <typename D>
159acc0297cSJacob Faibussowitsch template <typename... Args>
finalize(Args &&...args) const160acc0297cSJacob Faibussowitsch inline PetscErrorCode RegisterFinalizeable<D>::finalize(Args &&...args) const noexcept
161acc0297cSJacob Faibussowitsch {
162acc0297cSJacob Faibussowitsch PetscFunctionBegin;
163acc0297cSJacob Faibussowitsch PetscCall(do_finalize_(*this, std::forward<Args>(args)...));
1643ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
1650e6b6b59SJacob Faibussowitsch }
1660e6b6b59SJacob Faibussowitsch
167503aa7efSJacob Faibussowitsch /*
168503aa7efSJacob Faibussowitsch RegisterFinalizeable::register_finalize - Register a finalizer to run during PetscFinalize()
169503aa7efSJacob Faibussowitsch
170503aa7efSJacob Faibussowitsch Input Parameters:
171503aa7efSJacob Faibussowitsch . ...args - Additional arguments to pass to the register_finalize_() hook
172503aa7efSJacob Faibussowitsch
173503aa7efSJacob Faibussowitsch Notes:
174503aa7efSJacob Faibussowitsch It is not necessary to implement register_finalize_() in the derived class. A default (no-op)
175503aa7efSJacob Faibussowitsch implementation is provided.
176503aa7efSJacob Faibussowitsch
177503aa7efSJacob Faibussowitsch Before registering the class, the register_finalize_() hook function is run. This is useful
178503aa7efSJacob Faibussowitsch for running any one-time setup code before registering. Subsequent invocations of this
179503aa7efSJacob Faibussowitsch function (as long as registered() returns true) will not run register_finalize_() again.
180503aa7efSJacob Faibussowitsch
181503aa7efSJacob Faibussowitsch The class is considered registered before calling the hook, that is registered() will always
182503aa7efSJacob Faibussowitsch return true inside register_finalize_(). register_finalize_() is allowed to immediately
183503aa7efSJacob Faibussowitsch un-register the class (via finalize()). In this case the finalizer does not run at
184503aa7efSJacob Faibussowitsch PetscFinalize(), and registered() returns false after this routine returns.
185503aa7efSJacob Faibussowitsch */
1860e6b6b59SJacob Faibussowitsch template <typename D>
1870e6b6b59SJacob Faibussowitsch template <typename... Args>
register_finalize(Args &&...args)188503aa7efSJacob Faibussowitsch inline PetscErrorCode RegisterFinalizeable<D>::register_finalize(Args &&...args) noexcept
189d71ae5a4SJacob Faibussowitsch {
1900e6b6b59SJacob Faibussowitsch PetscFunctionBegin;
191acc0297cSJacob Faibussowitsch PetscCall(do_register_finalize_(*this, std::forward<Args>(args)...));
192acc0297cSJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
193acc0297cSJacob Faibussowitsch }
194acc0297cSJacob Faibussowitsch
195acc0297cSJacob Faibussowitsch template <typename D>
196acc0297cSJacob Faibussowitsch template <typename... Args>
register_finalize(Args &&...args) const197acc0297cSJacob Faibussowitsch inline PetscErrorCode RegisterFinalizeable<D>::register_finalize(Args &&...args) const noexcept
198acc0297cSJacob Faibussowitsch {
199acc0297cSJacob Faibussowitsch PetscFunctionBegin;
200acc0297cSJacob Faibussowitsch PetscCall(do_register_finalize_(*this, std::forward<Args>(args)...));
2013ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
2020e6b6b59SJacob Faibussowitsch }
2030e6b6b59SJacob Faibussowitsch
2040e6b6b59SJacob Faibussowitsch } // namespace Petsc
205