2022-07-19 14:21:35 +00:00
/***
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 < class T >
struct AuHasDestroy
{
template < class C > static constexpr AuTrueType Test ( decltype ( & C : : DestroyPrivate ) ) ;
template < class C > static constexpr AuFalseType Test ( . . . ) ;
using type = decltype ( Test < T > ( 0 ) ) ;
} ;
template < class T >
struct AuHasDeconstruct
{
template < class C > static constexpr AuTrueType Test ( decltype ( & C : : DeconstructPrivate ) ) ;
template < class C > static constexpr AuFalseType Test ( . . . ) ;
using type = decltype ( Test < T > ( 0 ) ) ;
} ;
template < class T >
struct AuHasPreDeconstruct
{
template < class C > static constexpr AuTrueType Test ( decltype ( & C : : PreDeconstructPrivate ) ) ;
template < class C > static constexpr AuFalseType Test ( . . . ) ;
using type = decltype ( Test < T > ( 0 ) ) ;
} ;
template < class T >
constexpr inline bool AuHasDestroy_v = AuHasDestroy < T > : : type : : value ;
template < class T >
constexpr inline bool AuHasDesconstruct_v = AuHasDeconstruct < T > : : type : : value ;
template < class T >
constexpr inline bool AuHasPreDesconstruct_v = AuHasPreDeconstruct < T > : : type : : value ;
}
# define AU_SAFE_DESTROY(type) \
public : \
virtual ~ type ( ) \
{ \
2022-09-26 18:01:46 +00:00
if ( AuAtomicTestAndSet ( & this - > uCurrentState_ , 2 ) ) \
2022-09-12 20:40:16 +00:00
{ \
2022-09-26 18:01:46 +00:00
return ; \
2022-09-12 20:40:16 +00:00
} \
2022-07-19 14:21:35 +00:00
\
type : : _TryPreDeconstruct < type > ( this ) ; \
\
this - > Destroy ( ) ; \
\
type : : _TryDeconstruct < type > ( this ) ; \
\
} \
\
inline void Destroy ( ) \
{ \
2022-09-26 18:01:46 +00:00
if ( AuAtomicTestAndSet ( & this - > uCurrentState_ , 1 ) ) \
2022-09-12 20:40:16 +00:00
{ \
2022-09-26 18:01:46 +00:00
return ; \
2022-09-12 20:40:16 +00:00
} \
2022-07-19 14:21:35 +00:00
\
type : : _TryDeconstructPrivate < type > ( this ) ; \
} \
\
friend AuUtil : : Detail : : AuHasDestroy < type > ; \
friend AuUtil : : Detail : : AuHasDeconstruct < type > ; \
friend AuUtil : : Detail : : AuHasPreDeconstruct < type > ; \
\
private : \
2022-09-12 20:40:16 +00:00
AuUInt32 uCurrentState_ { } ; \
2022-07-19 14:21:35 +00:00
\
template < typename T > \
static void _TryPreDeconstruct ( T * that ) \
{ \
if constexpr ( AuUtil : : Detail : : AuHasPreDesconstruct_v < T > ) \
{ \
that - > PreDeconstructPrivate ( ) ; \
} \
} \
\
template < typename T > \
static void _TryDeconstruct ( T * that ) \
{ \
if constexpr ( AuUtil : : Detail : : AuHasDesconstruct_v < T > ) \
{ \
that - > DeconstructPrivate ( ) ; \
} \
} \
\
template < typename T > \
static void _TryDeconstructPrivate ( T * that ) \
{ \
if constexpr ( AuUtil : : Detail : : AuHasDestroy_v < T > ) \
{ \
that - > DestroyPrivate ( ) ; \
} \
} \
\
public :
}
/**
2022-09-12 20:40:16 +00:00
Safe destroy objects :
* implement a builtin : : Destroy function for objects whose ownership is expectantly shared instead of explicitly owned ( eg : overlapped io resources over simplier utility class objects with explicit an release function )
* allow the user to define : : DestroyPrivate , : : DeconstructPrivate , and : : * Pre * DeconstructPrivate methods in their class
* forces virtual destruction to prevent hidden leaks
note : The real reason we do this is bc " some projects " expect the destruction implementation itself to be a virtual destructor ( an implicitly overloaded virtual , if it were a regular method ) .
That way API objects can call a ` virtual ~ IInterface ( ) ` and nuke safely nuke away the underlying safe - destroy object by using the builtin " everyone has this destruct method " destructor ;
bypassing the need for a ` virtual Destroy ( ) = 0 ; ` and alternative an AU_SAFE_DESTROY .
* enable safe explicit double ~ Type ( ) support ; however , some objects in your STL may not support this behaviour ( eg : AuFunction )
workaround : implement explicit : : Deconstruct ( ) with AuResetMember calls to fixup the UB
* allows for an arbitrary amount of Type : : Destroy ( ) and Type : : ~ Type ( ) calls across multiple threads
Usage :
Defines # define AU_SAFE_DESTROY ( type )
2022-07-19 14:21:35 +00:00
2022-09-12 20:40:16 +00:00
Simply add AU_SAFE_DESTROY to the types body add arbitrarily add the following callback methods as needed
2022-07-19 14:21:35 +00:00
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 .
2022-09-12 20:40:16 +00:00
These user defined functions may be private and / or virtual , if implemented at all .
2022-07-19 14:21:35 +00:00
*/