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