Actual source code: register_finalize.hpp
1: #pragma once
3: #include <petscsys.h>
5: #include <petsc/private/cpp/crtp.hpp>
6: #include <petsc/private/cpp/type_traits.hpp>
8: template <typename T>
9: inline PetscErrorCode PetscCxxObjectRegisterFinalize(T *obj, MPI_Comm comm = PETSC_COMM_SELF) noexcept
10: {
11: PetscContainer contain = nullptr;
12: const auto finalizer = [](void **ptr) {
13: PetscFunctionBegin;
14: PetscCall(static_cast<T *>(*ptr)->finalize());
15: PetscFunctionReturn(PETSC_SUCCESS);
16: };
18: PetscFunctionBegin;
19: PetscAssertPointer(obj, 1);
20: PetscCall(PetscContainerCreate(comm, &contain));
21: PetscCall(PetscContainerSetPointer(contain, obj));
22: PetscCall(PetscContainerSetCtxDestroy(contain, std::move(finalizer)));
23: PetscCall(PetscObjectRegisterDestroy(reinterpret_cast<PetscObject>(contain)));
24: PetscFunctionReturn(PETSC_SUCCESS);
25: }
27: namespace Petsc
28: {
30: // ==========================================================================================
31: // RegisterFinalizeable
32: //
33: // A mixin class that enables registering a finalizer for a class instance to run during
34: // PetscFinalize(). Enables 3 public methods:
35: //
36: // 1. register_finalize() - Register the calling instance to run the member function
37: // finalize_() during PetscFinalize(). It only registers the class once.
38: // 2. finalize() - Run the member function finalize_() immediately.
39: // 3. registered() - Query whether you are registered.
40: // ==========================================================================================
41: template <typename Derived>
42: class RegisterFinalizeable : public util::crtp<RegisterFinalizeable, Derived> {
43: public:
44: using derived_type = Derived;
46: PETSC_NODISCARD bool registered() const noexcept;
47: template <typename... Args>
48: PetscErrorCode finalize(Args &&...) noexcept;
49: template <typename... Args>
50: PetscErrorCode finalize(Args &&...) const noexcept;
51: template <typename... Args>
52: PetscErrorCode register_finalize(Args &&...) noexcept;
53: template <typename... Args>
54: PetscErrorCode register_finalize(Args &&...) const noexcept;
56: private:
57: constexpr RegisterFinalizeable() noexcept = default;
58: friend derived_type;
60: template <typename Self, typename... Args>
61: static PetscErrorCode do_finalize_(Self &&, Args &&...) noexcept;
62: template <typename Self, typename... Args>
63: static PetscErrorCode do_register_finalize_(Self &&, Args &&...) noexcept;
65: // default implementations if the derived class does not want to implement them
66: template <typename... Args>
67: static constexpr PetscErrorCode finalize_(Args &&...) noexcept;
68: template <typename... Args>
69: static constexpr PetscErrorCode register_finalize_(Args &&...) noexcept;
71: mutable bool registered_ = false;
72: };
74: template <typename D>
75: template <typename Self, typename... Args>
76: inline PetscErrorCode RegisterFinalizeable<D>::do_finalize_(Self &&self, Args &&...args) noexcept
77: {
78: PetscFunctionBegin;
79: // order of setting registered_ to false matters here, if the finalizer wants to re-register
80: // it should be able to
81: if (self.underlying().registered()) {
82: self.registered_ = false;
83: PetscCall(self.underlying().finalize_(std::forward<Args>(args)...));
84: }
85: PetscFunctionReturn(PETSC_SUCCESS);
86: }
88: template <typename D>
89: template <typename Self, typename... Args>
90: inline PetscErrorCode RegisterFinalizeable<D>::do_register_finalize_(Self &&self, Args &&...args) noexcept
91: {
92: PetscFunctionBegin;
93: if (PetscLikely(self.underlying().registered())) PetscFunctionReturn(PETSC_SUCCESS);
94: self.registered_ = true;
95: PetscCall(self.underlying().register_finalize_(std::forward<Args>(args)...));
96: // Check if registered before we commit to actually register-finalizing. register_finalize_()
97: // is allowed to run its finalizer immediately
98: if (self.underlying().registered()) {
99: using decayed_type = util::decay_t<Self>;
101: PetscCall(PetscCxxObjectRegisterFinalize(const_cast<decayed_type *>(std::addressof(self))));
102: }
103: PetscFunctionReturn(PETSC_SUCCESS);
104: }
106: template <typename D>
107: template <typename... Args>
108: inline constexpr PetscErrorCode RegisterFinalizeable<D>::finalize_(Args &&...) noexcept
109: {
110: return PETSC_SUCCESS;
111: }
113: template <typename D>
114: template <typename... Args>
115: inline constexpr PetscErrorCode RegisterFinalizeable<D>::register_finalize_(Args &&...) noexcept
116: {
117: return PETSC_SUCCESS;
118: }
120: /*
121: RegisterFinalizeable::registered - Determine if the class instance is registered
123: Notes:
124: Returns true if class is registered, false otherwise.
125: */
126: template <typename D>
127: inline bool RegisterFinalizeable<D>::registered() const noexcept
128: {
129: return registered_;
130: }
132: /*
133: RegisterFinalizeable::finalize - Run the finalizer for a class
135: Input Parameters:
137: . ...args - A set of arguments to pass to the finalizer
139: Notes:
140: It is not necessary to implement finalize_() in the derived class (though pretty much
141: pointless), a default (no-op) implementation is provided.
143: Runs the member function finalize_() with args forwarded.
145: "Unregisters" the class from PetscFinalize(). However, it is safe for finalize_() to
146: re-register itself (via register_finalize()). registered() is guaranteed to return false
147: inside finalize_().
148: */
149: template <typename D>
150: template <typename... Args>
151: inline PetscErrorCode RegisterFinalizeable<D>::finalize(Args &&...args) noexcept
152: {
153: PetscFunctionBegin;
154: PetscCall(do_finalize_(*this, std::forward<Args>(args)...));
155: PetscFunctionReturn(PETSC_SUCCESS);
156: }
158: template <typename D>
159: template <typename... Args>
160: inline PetscErrorCode RegisterFinalizeable<D>::finalize(Args &&...args) const noexcept
161: {
162: PetscFunctionBegin;
163: PetscCall(do_finalize_(*this, std::forward<Args>(args)...));
164: PetscFunctionReturn(PETSC_SUCCESS);
165: }
167: /*
168: RegisterFinalizeable::register_finalize - Register a finalizer to run during PetscFinalize()
170: Input Parameters:
171: . ...args - Additional arguments to pass to the register_finalize_() hook
173: Notes:
174: It is not necessary to implement register_finalize_() in the derived class. A default (no-op)
175: implementation is provided.
177: Before registering the class, the register_finalize_() hook function is run. This is useful
178: for running any one-time setup code before registering. Subsequent invocations of this
179: function (as long as registered() returns true) will not run register_finalize_() again.
181: The class is considered registered before calling the hook, that is registered() will always
182: return true inside register_finalize_(). register_finalize_() is allowed to immediately
183: un-register the class (via finalize()). In this case the finalizer does not run at
184: PetscFinalize(), and registered() returns false after this routine returns.
185: */
186: template <typename D>
187: template <typename... Args>
188: inline PetscErrorCode RegisterFinalizeable<D>::register_finalize(Args &&...args) noexcept
189: {
190: PetscFunctionBegin;
191: PetscCall(do_register_finalize_(*this, std::forward<Args>(args)...));
192: PetscFunctionReturn(PETSC_SUCCESS);
193: }
195: template <typename D>
196: template <typename... Args>
197: inline PetscErrorCode RegisterFinalizeable<D>::register_finalize(Args &&...args) const noexcept
198: {
199: PetscFunctionBegin;
200: PetscCall(do_register_finalize_(*this, std::forward<Args>(args)...));
201: PetscFunctionReturn(PETSC_SUCCESS);
202: }
204: } // namespace Petsc