xref: /petsc/include/petsc/private/cpp/register_finalize.hpp (revision 5aa9e7a84219fd02c28259db46d5f928fe59e824)
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 template <typename Derived>
37 class RegisterFinalizeable : public util::crtp<Derived, RegisterFinalizeable> {
38 public:
39   using derived_type = Derived;
40   using crtp_type    = util::crtp<Derived, RegisterFinalizeable>;
41 
42   PETSC_NODISCARD bool registered() const noexcept;
43   template <typename... Args>
44   PETSC_NODISCARD PetscErrorCode finalize(Args &&...) noexcept;
45   template <typename... Args>
46   PETSC_NODISCARD PetscErrorCode register_finalize(MPI_Comm comm = PETSC_COMM_SELF, Args &&...) noexcept;
47 
48 private:
49   constexpr RegisterFinalizeable() = default;
50   friend derived_type;
51 
52   // default implementations if the derived class does not want to implement them
53   template <typename... Args>
54   PETSC_NODISCARD static PetscErrorCode finalize_(Args &&...) noexcept;
55   template <typename... Args>
56   PETSC_NODISCARD static PetscErrorCode register_finalize_(Args &&...) noexcept;
57 
58   bool registered_ = false;
59 };
60 
61 template <typename D>
62 template <typename... Args>
63 inline PetscErrorCode RegisterFinalizeable<D>::finalize_(Args &&...) noexcept
64 {
65   return 0;
66 }
67 
68 template <typename D>
69 template <typename... Args>
70 inline PetscErrorCode RegisterFinalizeable<D>::register_finalize_(Args &&...) noexcept
71 {
72   return 0;
73 }
74 
75 template <typename D>
76 inline bool RegisterFinalizeable<D>::registered() const noexcept
77 {
78   return registered_;
79 }
80 
81 template <typename D>
82 template <typename... Args>
83 inline PetscErrorCode RegisterFinalizeable<D>::finalize(Args &&...args) noexcept
84 {
85   PetscFunctionBegin;
86   // order of registered_ matters here, if the finalizer wants to re-register it should be able to
87   registered_ = false;
88   PetscCall(this->underlying().finalize_(std::forward<Args>(args)...));
89   PetscFunctionReturn(0);
90 }
91 
92 template <typename D>
93 template <typename... Args>
94 inline PetscErrorCode RegisterFinalizeable<D>::register_finalize(MPI_Comm comm, Args &&...args) noexcept
95 {
96   PetscFunctionBegin;
97   if (PetscLikely(this->underlying().registered())) PetscFunctionReturn(0);
98   registered_ = true;
99   PetscCall(this->underlying().register_finalize_(std::forward<Args>(args)...));
100   PetscCall(PetscCxxObjectRegisterFinalize(this, comm));
101   PetscFunctionReturn(0);
102 }
103 
104 } // namespace Petsc
105 
106 #endif // __cplusplus
107 
108 #endif // PETSC_CPP_REGISTER_FINALIZE_HPP
109