/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: SafeDestroy.hpp Date: 2022-07-19 Author: Reece ***/ #pragma once namespace AuUtil { namespace Detail { template struct AuHasDestroy { template static constexpr AuTrueType Test(decltype(&C::DestroyPrivate)); template static constexpr AuFalseType Test(...); using type = decltype(Test(0)); }; template struct AuHasDeconstruct { template static constexpr AuTrueType Test(decltype(&C::DeconstructPrivate)); template static constexpr AuFalseType Test(...); using type = decltype(Test(0)); }; template struct AuHasPreDeconstruct { template static constexpr AuTrueType Test(decltype(&C::PreDeconstructPrivate)); template static constexpr AuFalseType Test(...); using type = decltype(Test(0)); }; template constexpr inline bool AuHasDestroy_v = AuHasDestroy::type::value; template constexpr inline bool AuHasDesconstruct_v = AuHasDeconstruct::type::value; template constexpr inline bool AuHasPreDesconstruct_v = AuHasPreDeconstruct::type::value; } #define AU_SAFE_DESTROY(type) \ public: \ virtual ~type() \ { \ if (AuExchange(this->bDestroyCtrOnce_, true)) return; \ \ type :: _TryPreDeconstruct(this); \ \ this->Destroy(); \ \ type :: _TryDeconstruct(this); \ \ } \ \ inline void Destroy() \ { \ if (AuExchange(this->bDestroyDesOnce_, true)) return; \ \ type :: _TryDeconstructPrivate(this); \ } \ \ friend AuUtil::Detail::AuHasDestroy; \ friend AuUtil::Detail::AuHasDeconstruct; \ friend AuUtil::Detail::AuHasPreDeconstruct; \ \ private: \ bool bDestroyCtrOnce_ {}; \ bool bDestroyDesOnce_ {}; \ \ template \ static void _TryPreDeconstruct(T *that) \ { \ if constexpr (AuUtil::Detail::AuHasPreDesconstruct_v) \ { \ that->PreDeconstructPrivate(); \ } \ } \ \ template \ static void _TryDeconstruct(T *that) \ { \ if constexpr (AuUtil::Detail::AuHasDesconstruct_v) \ { \ that->DeconstructPrivate(); \ } \ } \ \ template \ static void _TryDeconstructPrivate(T *that) \ { \ if constexpr (AuUtil::Detail::AuHasDestroy_v) \ { \ that->DestroyPrivate(); \ } \ } \ \ public: } /** Defines #define AU_SAFE_DESTROY(type) Implements safe multiple-detor, and multiple ::Destroy() call, based destructible interfaces. Simply add AU_SAFE_DESTROY to the types body add arbitrarily add the following callback methods as needed void DestroyPrivate(void) - Generic called once object destroy void DeconstructPrivate(void) - Object destruction hook. Called once. Called After DestroyPrivate. void PreDeconstructPrivate(void) - Object destruction hook. Called once. Called before DestroyPrivate. These user defined functions may be private and/or virtual, if implemented at all. */