diff options
author | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:01:29 +0200 |
---|---|---|
committer | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:01:29 +0200 |
commit | 9a2a524f1e311853d08050be2dcdddc09ac7759a (patch) | |
tree | d8e4a24169fce88c2d89931d58514889a0bcb0ea /shared/loki/StrongPtr.h | |
parent | 2.3 (diff) | |
download | FreeFileSync-9a2a524f1e311853d08050be2dcdddc09ac7759a.tar.gz FreeFileSync-9a2a524f1e311853d08050be2dcdddc09ac7759a.tar.bz2 FreeFileSync-9a2a524f1e311853d08050be2dcdddc09ac7759a.zip |
3.0
Diffstat (limited to 'shared/loki/StrongPtr.h')
-rw-r--r-- | shared/loki/StrongPtr.h | 1697 |
1 files changed, 1697 insertions, 0 deletions
diff --git a/shared/loki/StrongPtr.h b/shared/loki/StrongPtr.h new file mode 100644 index 00000000..7ec9766f --- /dev/null +++ b/shared/loki/StrongPtr.h @@ -0,0 +1,1697 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2006 Rich Sposato +// The copyright on this file is protected under the terms of the MIT license. +// +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author makes no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_STRONG_PTR_INC_ +#define LOKI_STRONG_PTR_INC_ + +// $Id: StrongPtr.h 914 2008-12-19 00:39:29Z rich_sposato $ + + +#include <loki/SmartPtr.h> +#if defined (LOKI_OBJECT_LEVEL_THREADING) || defined (LOKI_CLASS_LEVEL_THREADING) + #include <loki/Threads.h> +#endif + + +//////////////////////////////////////////////////////////////////////////////// +/// +/// \par Terminology +/// These terms are used within this file's comments. +/// -# StrongPtr : Class used to implement both strong and weak pointers. The +/// second template parameter determines if a StrongPtr is weak or strong. +/// -# Strong pointer : A pointer that claims ownership of a shared object. +/// When the last strong copointer dies, the object is destroyed even if +/// there are weak copointers. +/// -# Weak pointer : A pointer that does not own the shared object it points +/// to. It only destroys the shared object if there no strong copointers +/// exist when it dies. +/// -# Copointers : All the pointers that refer to the same shared object. +/// The copointers must have the same ownership policy, but the other +/// policies may be different. +/// -# Pointee : The shared object. +/// +/// \par OwnershipPolicy +/// The ownership policy has the pointer to the actual object, and it also +/// keeps track of the strong and weak copointers so that it can know if any +/// strong copointers remain. The plain pointer it maintains is stored as a +/// void pointer, which allows the ownership policy classes to be monolithic +/// classes instead of template classes. As monolithic classes, they reduce +/// amount of code-bloat. +/// +/// \par Writing Your Own OwnershipPolicy +/// If you write your own policy, you must implement these 12 functions: +/// -# explicit YourPolicy( bool strong ) +/// -# YourPolicy( void * p, bool strong ) +/// -# YourPolicy( const YourPolicy & rhs, bool strong ) +/// -# bool Release( bool strong ) +/// -# void Increment( bool strong ) +/// -# bool Decrement( bool strong ) +/// -# bool HasStrongPointer( void ) const +/// -# void Swap( YourPolicy & rhs ) +/// -# void SetPointer( void * p ) +/// -# void ZapPointer( void ) +/// -# void * GetPointer( void ) const +/// -# void * & GetPointerRef( void ) const +/// It is strongly recommended that all 12 of these functions be protected +/// instead of public. These two functions are optional for single-threaded +/// policies, but required for multi-threaded policies: +/// -# void Lock( void ) const +/// -# void Unlock( void ) const +/// This function is entirely optional: +/// -# bool Merge( TwoRefLinks & rhs ) +/// +/// \par DeletePolicy +/// The delete policy provides a mechanism to destroy an object and a default +/// value for an uninitialized pointer. You can override this policy with +/// your own when using the Singleton, NullObject, or Prototype design +/// patterns. +/// +/// \par Writing Your Own DeletePolicy +/// If you write your own policy, you must implement these 3 functions: +/// -# void static Delete( const P * p ) +/// -# static P * Default( void ) +/// -# void Swap( YourResetPolicy & ) +/// +/// \par ResetPolicy +/// A reset policy tells the ReleaseAll and ResetAll functions whether they +/// should release or reset the StrongPtr copointers. These functions do +/// not affect just one StrongPtr, but all copointers. That is unlike +/// SmartPtr where the Release and Reset functions only affect 1 SmartPtr, +/// and leave all copointers untouched. A useful trick you can do with the +/// ResetPolicy is to not allow reset when a strong pointer exists, and then +/// use the NoCheck policy for all strong pointers. The reset policy +/// guarantees the strong pointers always have a valid pointee, so checking +/// is not required; but weak pointers may still require checking. +/// +/// \par Writing Your Own ResetPolicy +/// If you write your own policy, you must implement these 2 functions: +/// -# bool OnReleaseAll( bool ) const +/// -# bool OnResetAll( bool ) const +/// The bool parameter means that this was called with a strong pointer or +/// one of its copointers is strong. The return value means the pointer +/// can be reset or released. +/// +/// \defgroup StrongPointerOwnershipGroup StrongPtr Ownership policies +/// \ingroup SmartPointerGroup +/// \defgroup StrongPointerDeleteGroup Delete policies +/// \ingroup SmartPointerGroup +/// \defgroup StrongPointerResetGroup Reset policies +/// \ingroup SmartPointerGroup +//////////////////////////////////////////////////////////////////////////////// + + +namespace Loki +{ + + +//////////////////////////////////////////////////////////////////////////////// +/// \class DeleteUsingFree +/// +/// \ingroup StrongPointerDeleteGroup +/// Implementation of the DeletePolicy used by StrongPtr. Uses explicit call +/// to T's destructor followed by call to free. This policy is useful for +/// managing the lifetime of pointers to structs returned by C functions. +//////////////////////////////////////////////////////////////////////////////// + +template < class P > +class DeleteUsingFree +{ +public: + inline void static Delete( const P * p ) + { + if ( 0 != p ) + { + p->~P(); + ::free( p ); + } + } + + /// Provides default value to initialize the pointer + inline static P * Default( void ) + { + return 0; + } + + inline void Swap( DeleteUsingFree & ) {} +}; + +//////////////////////////////////////////////////////////////////////////////// +/// \class DeleteNothing +/// +/// \ingroup StrongPointerDeleteGroup +/// Implementation of the DeletePolicy used by StrongPtr. This will never +/// delete anything. You can use this policy with pointers to an undefined +/// type or a pure interface class with a protected destructor. +//////////////////////////////////////////////////////////////////////////////// + +template < class P > +class DeleteNothing +{ +public: + inline static void Delete( const P * ) + { + // Do nothing at all! + } + + inline static P * Default( void ) + { + return 0; + } + + inline void Swap( DeleteNothing & ) {} +}; + +//////////////////////////////////////////////////////////////////////////////// +/// \class DeleteSingle +/// +/// \ingroup StrongPointerDeleteGroup +/// Implementation of the DeletePolicy used by StrongPtr. This deletes just +/// one shared object. This is the default class for the DeletePolicy. +//////////////////////////////////////////////////////////////////////////////// + +template < class P > +class DeleteSingle +{ +public: + inline static void Delete( const P * p ) + { + /** @note If you see an error message about a negative subscript, that + means your are attempting to use Loki to delete an incomplete type. + Please don't use this policy with incomplete types; you may want to + use DeleteNothing instead. + */ + typedef char Type_Must_Be_Defined[ sizeof(P) ? 1 : -1 ]; + delete p; + } + + inline static P * Default( void ) + { + return 0; + } + + inline void Swap( DeleteSingle & ) {} +}; + +//////////////////////////////////////////////////////////////////////////////// +/// \class DeleteArray +/// +/// \ingroup StrongPointerDeleteGroup +/// Implementation of the DeletePolicy used by StrongPtr. This deletes an +/// array of shared objects. +//////////////////////////////////////////////////////////////////////////////// + +template < class P > +class DeleteArray +{ +public: + inline static void Delete( const P * p ) + { + /** @note If you see an error message about a negative subscript, that + means your are attempting to use Loki to delete an incomplete type. + Please don't use this policy with incomplete types; you may want to + use DeleteNothing instead. + */ + typedef char Type_Must_Be_Defined[ sizeof(P) ? 1 : -1 ]; + delete [] p; + } + + inline static P * Default( void ) + { + return 0; + } + + inline void Swap( DeleteArray & ) {} +}; + +//////////////////////////////////////////////////////////////////////////////// +/// \class CantResetWithStrong +/// +/// \ingroup StrongPointerResetGroup +/// Implementation of the ResetPolicy used by StrongPtr. This is the default +/// ResetPolicy for StrongPtr. It forbids reset and release only if a strong +/// copointer exists. +//////////////////////////////////////////////////////////////////////////////// + +template < class P > +struct CantResetWithStrong +{ + inline bool OnReleaseAll( bool hasStrongPtr ) const + { + return ! hasStrongPtr; + } + + inline bool OnResetAll( bool hasStrongPtr ) const + { + return ! hasStrongPtr; + } +}; + +//////////////////////////////////////////////////////////////////////////////// +/// \class AllowReset +/// +/// \ingroup StrongPointerResetGroup +/// Implementation of the ResetPolicy used by StrongPtr. It allows reset and +/// release under any circumstance. +//////////////////////////////////////////////////////////////////////////////// + +template < class P > +struct AllowReset +{ + inline bool OnReleaseAll( bool ) const + { + return true; + } + inline bool OnResetAll( bool ) const + { + return true; + } +}; + +//////////////////////////////////////////////////////////////////////////////// +/// \class NeverReset +/// +/// \ingroup StrongPointerResetGroup +/// Implementation of the ResetPolicy used by StrongPtr. It forbids reset and +/// release under any circumstance. +//////////////////////////////////////////////////////////////////////////////// + +template < class P > +struct NeverReset +{ + inline bool OnReleaseAll( bool ) const + { + return false; + } + inline bool OnResetAll( bool ) const + { + return false; + } +}; + +// ---------------------------------------------------------------------------- + +namespace Private +{ + +//////////////////////////////////////////////////////////////////////////////// +/// \class TwoRefCountInfo +/// +/// \ingroup StrongPointerOwnershipGroup +/// Implementation detail for reference counting strong and weak pointers. +/// It maintains a void pointer and 2 reference counts. Since it is just a +/// class for managing implementation details, it is not intended to be used +/// directly - which is why it is in a private namespace. Each instance is a +/// shared resource for all copointers, and there should be only one of these +/// for each set of copointers. This class is small, trivial, and inline. +//////////////////////////////////////////////////////////////////////////////// + +class LOKI_EXPORT TwoRefCountInfo +{ +public: + + inline explicit TwoRefCountInfo( bool strong ) + : m_pointer( 0 ) + , m_strongCount( strong ? 1 : 0 ) + , m_weakCount( strong ? 0 : 1 ) + { + } + + inline TwoRefCountInfo( void * p, bool strong ) + : m_pointer( p ) + , m_strongCount( strong ? 1 : 0 ) + , m_weakCount( strong ? 0 : 1 ) + { + } + + inline ~TwoRefCountInfo( void ) + { + assert( 0 == m_strongCount ); + assert( 0 == m_weakCount ); + } + + inline bool HasStrongPointer( void ) const + { + return ( 0 < m_strongCount ); + } + + inline bool HasWeakPointer( void ) const + { + return ( 0 < m_weakCount ); + } + + inline void IncStrongCount( void ) + { + ++m_strongCount; + } + + inline void IncWeakCount( void ) + { + ++m_weakCount; + } + + inline bool DecStrongCount( void ) + { + assert( 0 < m_strongCount ); + --m_strongCount; + const bool isZero = ( 0 == m_strongCount ); + return isZero; + } + + inline void DecWeakCount( void ) + { + assert( 0 < m_weakCount ); + --m_weakCount; + } + + inline void ZapPointer( void ) + { + m_pointer = 0; + } + + void SetPointer( void * p ) + { + m_pointer = p; + } + + inline void * GetPointer( void ) const + { + return m_pointer; + } + + inline void * & GetPointerRef( void ) const + { + return const_cast< void * & >( m_pointer ); + } + +private: + /// Copy-constructor not implemented. + TwoRefCountInfo( const TwoRefCountInfo & ); + /// Copy-assignment operator not implemented. + TwoRefCountInfo & operator = ( const TwoRefCountInfo & ); + + void * m_pointer; + unsigned int m_strongCount; + unsigned int m_weakCount; +}; + +//////////////////////////////////////////////////////////////////////////////// +/// \class LockableTwoRefCountInfo +/// +/// \ingroup StrongPointerOwnershipGroup +/// Implementation detail for thread-safe reference counting for strong and +/// weak pointers. It uses TwoRefCountInfo to manage the pointer and counts. +/// All this does is provide a thread safety mechanism. Since it is just a +/// class for managing implementation details, it is not intended to be used +/// directly - which is why it is in a private namespace. Each instance is a +/// shared resource for all copointers, and there should be only one of these +/// for each set of copointers. This class is small, trivial, and inline. +/// +/// \note This class is not designed for use with a single-threaded model. +/// Tests using a single-threaded model will not run properly, but tests in a +/// multi-threaded model with either class-level-locking or object-level-locking +/// do run properly. +//////////////////////////////////////////////////////////////////////////////// + +#if defined (LOKI_OBJECT_LEVEL_THREADING) || defined (LOKI_CLASS_LEVEL_THREADING) + +class LOKI_EXPORT LockableTwoRefCountInfo + : private Loki::Private::TwoRefCountInfo +{ +public: + + inline explicit LockableTwoRefCountInfo( bool strong ) + : TwoRefCountInfo( strong ) + , m_Mutex() + { + } + + LockableTwoRefCountInfo( void * p, bool strong ) + : TwoRefCountInfo( p, strong ) + , m_Mutex() + { + } + + inline ~LockableTwoRefCountInfo( void ) + { + } + + inline void Lock( void ) const + { + m_Mutex.Lock(); + } + + inline void Unlock( void ) const + { + m_Mutex.Unlock(); + } + + inline bool HasStrongPointer( void ) const + { + m_Mutex.Lock(); + const bool has = TwoRefCountInfo::HasStrongPointer(); + m_Mutex.Unlock(); + return has; + } + + inline bool HasWeakPointer( void ) const + { + m_Mutex.Lock(); + const bool has = TwoRefCountInfo::HasWeakPointer(); + m_Mutex.Unlock(); + return has; + } + + inline void IncStrongCount( void ) + { + m_Mutex.Lock(); + TwoRefCountInfo::IncStrongCount(); + m_Mutex.Unlock(); + } + + inline void IncWeakCount( void ) + { + m_Mutex.Lock(); + TwoRefCountInfo::IncWeakCount(); + m_Mutex.Unlock(); + } + + inline bool DecStrongCount( void ) + { + m_Mutex.Lock(); + const bool isZero = TwoRefCountInfo::DecStrongCount(); + m_Mutex.Unlock(); + return isZero; + } + + inline void DecWeakCount( void ) + { + m_Mutex.Lock(); + TwoRefCountInfo::DecWeakCount(); + m_Mutex.Unlock(); + } + + inline void ZapPointer( void ) + { + m_Mutex.Lock(); + TwoRefCountInfo::ZapPointer(); + m_Mutex.Unlock(); + } + + void SetPointer( void * p ) + { + m_Mutex.Lock(); + TwoRefCountInfo::SetPointer( p ); + m_Mutex.Unlock(); + } + + inline void * GetPointer( void ) const + { + return TwoRefCountInfo::GetPointer(); + } + + inline void * & GetPointerRef( void ) const + { + return TwoRefCountInfo::GetPointerRef(); + } + +private: + /// Default constructor is not available. + LockableTwoRefCountInfo( void ); + /// Copy constructor is not available. + LockableTwoRefCountInfo( const LockableTwoRefCountInfo & ); + /// Copy-assignment operator is not available. + LockableTwoRefCountInfo & operator = ( const LockableTwoRefCountInfo & ); + + mutable LOKI_DEFAULT_MUTEX m_Mutex; +}; + +#endif // if object-level-locking or class-level-locking + +} // end namespace Private + +//////////////////////////////////////////////////////////////////////////////// +/// \class TwoRefCounts +/// +/// \ingroup StrongPointerOwnershipGroup +/// This implementation of StrongPtr's OwnershipPolicy uses a pointer to a +/// shared instance of TwoRefCountInfo. This is the default policy for +/// OwnershipPolicy. Some functions are trivial enough to be inline, while +/// others are implemented elsewhere. It is not thread safe, and is intended +/// for single-threaded environments. +//////////////////////////////////////////////////////////////////////////////// + +class LOKI_EXPORT TwoRefCounts +{ +protected: + + explicit TwoRefCounts( bool strong ); + + TwoRefCounts( const void * p, bool strong ); + + TwoRefCounts( const TwoRefCounts & rhs, bool strong ) : + m_counts( rhs.m_counts ) + { + Increment( strong ); + } + + /** The destructor does not need to do anything since the call to + ZapPointer inside StrongPtr::~StrongPtr will do the cleanup which + this dtor would have done. + */ + inline ~TwoRefCounts( void ) {} + + inline bool Release( bool strong ) + { + return Decrement( strong ); + } + + bool HasStrongPointer( void ) const + { + return m_counts->HasStrongPointer(); + } + + void Swap( TwoRefCounts & rhs ); + + void SetPointer( void * p ) + { + m_counts->SetPointer( p ); + } + + void ZapPointer( void ); + + inline void * & GetPointerRef( void ) const + { + return m_counts->GetPointerRef(); + } + + inline void * GetPointer( void ) const + { + return m_counts->GetPointer(); + } + +private: + TwoRefCounts( void ); + TwoRefCounts & operator = ( const TwoRefCounts & ); + + void Increment( bool strong ); + + bool Decrement( bool strong ); + + /// Pointer to all shared data. + Loki::Private::TwoRefCountInfo * m_counts; +}; + +//////////////////////////////////////////////////////////////////////////////// +/// \class LockableTwoRefCounts +/// +/// \ingroup StrongPointerOwnershipGroup +/// This implementation of StrongPtr's OwnershipPolicy uses a pointer to a +/// shared instance of LockableTwoRefCountInfo. It behaves very similarly to +/// TwoRefCounts, except that it provides thread-safety. Some functions are +/// trivial enough to be inline, while others are implemented elsewhere. +/// +/// \note This class is not designed for use with a single-threaded model. +/// Tests using a single-threaded model will not run properly, but tests in a +/// multi-threaded model with either class-level-locking or object-level-locking +/// do run properly. +//////////////////////////////////////////////////////////////////////////////// + +#if defined (LOKI_OBJECT_LEVEL_THREADING) || defined (LOKI_CLASS_LEVEL_THREADING) + +class LOKI_EXPORT LockableTwoRefCounts +{ + typedef SmallValueObject< ::Loki::ClassLevelLockable > ThreadSafePointerAllocator; + +protected: + + explicit LockableTwoRefCounts( bool strong ) + : m_counts( NULL ) + { + void * temp = ThreadSafePointerAllocator::operator new( + sizeof(Loki::Private::LockableTwoRefCountInfo) ); +#ifdef DO_EXTRA_LOKI_TESTS + assert( temp != 0 ); +#endif + m_counts = new ( temp ) Loki::Private::LockableTwoRefCountInfo( strong ); + } + + LockableTwoRefCounts( const void * p, bool strong ) + : m_counts( NULL ) + { + void * temp = ThreadSafePointerAllocator::operator new( + sizeof(Loki::Private::LockableTwoRefCountInfo) ); +#ifdef DO_EXTRA_LOKI_TESTS + assert( temp != 0 ); +#endif + void * p2 = const_cast< void * >( p ); + m_counts = new ( temp ) + Loki::Private::LockableTwoRefCountInfo( p2, strong ); + } + + LockableTwoRefCounts( const LockableTwoRefCounts & rhs, bool strong ) : + m_counts( rhs.m_counts ) + { + Increment( strong ); + } + + /** The destructor does not need to do anything since the call to + ZapPointer inside StrongPtr::~StrongPtr will do the cleanup which + this dtor would have done. + */ + inline ~LockableTwoRefCounts( void ) {} + + inline void Lock( void ) const + { + m_counts->Lock(); + } + + inline void Unlock( void ) const + { + m_counts->Unlock(); + } + + inline bool Release( bool strong ) + { + return Decrement( strong ); + } + + void Increment( bool strong ) + { + if ( strong ) + { + m_counts->IncStrongCount(); + } + else + { + m_counts->IncWeakCount(); + } + } + + bool Decrement( bool strong ) + { + bool noStrongPointers = false; + if ( strong ) + { + noStrongPointers = m_counts->DecStrongCount(); + } + else + { + m_counts->DecWeakCount(); + noStrongPointers = !m_counts->HasStrongPointer(); + } + return noStrongPointers; + } + + bool HasStrongPointer( void ) const + { + return m_counts->HasStrongPointer(); + } + + void Swap( LockableTwoRefCounts & rhs ) + { + std::swap( m_counts, rhs.m_counts ); + } + + void SetPointer( void * p ) + { + m_counts->SetPointer( p ); + } + + void ZapPointer( void ) + { +#ifdef DO_EXTRA_LOKI_TESTS + assert( !m_counts->HasStrongPointer() ); +#endif + if ( m_counts->HasWeakPointer() ) + { + m_counts->ZapPointer(); + } + else + { + ThreadSafePointerAllocator::operator delete ( m_counts, + sizeof(Loki::Private::LockableTwoRefCountInfo) ); + m_counts = NULL; + } + } + + inline void * GetPointer( void ) const + { + return m_counts->GetPointer(); + } + + inline void * & GetPointerRef( void ) const + { + return m_counts->GetPointerRef(); + } + +private: + LockableTwoRefCounts( void ); + LockableTwoRefCounts & operator = ( const LockableTwoRefCounts & ); + + /// Pointer to all shared data. + Loki::Private::LockableTwoRefCountInfo * m_counts; +}; + +#endif // if object-level-locking or class-level-locking + +//////////////////////////////////////////////////////////////////////////////// +/// \class TwoRefLinks +/// +/// \ingroup StrongPointerOwnershipGroup +/// This implementation of StrongPtr's OwnershipPolicy uses a doubly-linked +/// cycle of copointers to a shared object. Some functions are trivial enough +/// to be inline, while others are implemented in elsewhere. It is not thread +/// safe, and is intended for single-threaded environments. +//////////////////////////////////////////////////////////////////////////////// + +class LOKI_EXPORT TwoRefLinks +{ +protected: + + inline explicit TwoRefLinks( bool strong ) + : m_pointer( 0 ) + , m_strong( strong ) + { + m_prev = m_next = this; + } + + TwoRefLinks( const void * p, bool strong ); + + TwoRefLinks( const TwoRefLinks & rhs, bool strong ); + + bool Release( bool strong ); + + void Swap( TwoRefLinks & rhs ); + + bool Merge( TwoRefLinks & rhs ); + + bool HasStrongPointer( void ) const; + + inline void ZapPointer( void ) + { + ZapAllNodes(); + } + + void SetPointer( void * p ); + + inline void * GetPointer( void ) const + { + return m_pointer; + } + + inline void * & GetPointerRef( void ) const + { + return const_cast< void * & >( m_pointer ); + } + +private: + static unsigned int CountPrevCycle( const TwoRefLinks * pThis ); + static unsigned int CountNextCycle( const TwoRefLinks * pThis ); + + /// Not implemented. + TwoRefLinks( void ); + /// Not implemented. + TwoRefLinks & operator = ( const TwoRefLinks & ); + + bool HasPrevNode( const TwoRefLinks * p ) const; + bool HasNextNode( const TwoRefLinks * p ) const; + bool AllNodesHaveSamePointer( void ) const; + void ZapAllNodes( void ); + + void * m_pointer; + mutable TwoRefLinks * m_prev; + mutable TwoRefLinks * m_next; + const bool m_strong; +}; + +//////////////////////////////////////////////////////////////////////////////// +/// \class StrongPtr +/// +/// \ingroup SmartPointerGroup +/// +/// \param Strong default = true, +/// \param OwnershipPolicy default = TwoRefCounts, +/// \param ConversionPolicy default = DisallowConversion, +/// \param CheckingPolicy default = AssertCheck, +/// \param ResetPolicy default = CantResetWithStrong, +/// \param DeletePolicy default = DeleteSingle +/// \param ConstnessPolicy default = LOKI_DEFAULT_CONSTNESS +//////////////////////////////////////////////////////////////////////////////// + +template +< + typename T, + bool Strong = true, + class OwnershipPolicy = Loki::TwoRefCounts, + class ConversionPolicy = Loki::DisallowConversion, + template < class > class CheckingPolicy = Loki::AssertCheck, + template < class > class ResetPolicy = Loki::CantResetWithStrong, + template < class > class DeletePolicy = Loki::DeleteSingle, + template < class > class ConstnessPolicy = LOKI_DEFAULT_CONSTNESS +> +class StrongPtr + : public OwnershipPolicy + , public ConversionPolicy + , public CheckingPolicy< T * > + , public ResetPolicy< T > + , public DeletePolicy< T > +{ + typedef ConversionPolicy CP; + typedef CheckingPolicy< T * > KP; + typedef ResetPolicy< T > RP; + typedef DeletePolicy< T > DP; + +public: + + typedef OwnershipPolicy OP; + + typedef T * StoredType; // the type of the pointer + typedef T * PointerType; // type returned by operator-> + typedef T & ReferenceType; // type returned by operator* + + typedef typename ConstnessPolicy< T >::Type * ConstPointerType; + typedef typename ConstnessPolicy< T >::Type & ConstReferenceType; + +private: + struct NeverMatched {}; + +#ifdef LOKI_SMARTPTR_CONVERSION_CONSTRUCTOR_POLICY + typedef typename Select< CP::allow, const StoredType&, NeverMatched>::Result ImplicitArg; + typedef typename Select<!CP::allow, const StoredType&, NeverMatched>::Result ExplicitArg; +#else + typedef const StoredType& ImplicitArg; + typedef typename Select<false, const StoredType&, NeverMatched>::Result ExplicitArg; +#endif + +public: + + StrongPtr( void ) : OP( Strong ) + { + KP::OnDefault( GetPointer() ); + } + + explicit StrongPtr( ExplicitArg p ) : OP( p, Strong ) + { + KP::OnInit( GetPointer() ); + } + + StrongPtr( ImplicitArg p ) : OP( p, Strong ) + { + KP::OnInit( GetPointer() ); + } + + StrongPtr( const StrongPtr & rhs ) + : OP( rhs, Strong ), CP( rhs ), KP( rhs ), DP( rhs ) + { + } + + template + < + typename T1, + bool S1, + class OP1, + class CP1, + template < class > class KP1, + template < class > class RP1, + template < class > class DP1, + template < class > class CNP1 + > + StrongPtr( + const StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs ) + : OP( rhs, Strong ) + { + } + + template + < + typename T1, + bool S1, + class OP1, + class CP1, + template < class > class KP1, + template < class > class RP1, + template < class > class DP1, + template < class > class CNP1 + > + StrongPtr( + StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs ) + : OP( rhs, Strong ) + { + } + + StrongPtr( RefToValue< StrongPtr > rhs ) + : OP( rhs, Strong ), KP( rhs ), CP( rhs ), DP( rhs ) + { + } + + operator RefToValue< StrongPtr >( void ) + { + return RefToValue< StrongPtr >( *this ); + } + + StrongPtr & operator = ( const StrongPtr & rhs ) + { + if ( GetPointer() != rhs.GetPointer() ) + { + StrongPtr temp( rhs ); + temp.Swap( *this ); + } + return *this; + } + + StrongPtr & operator = ( T * p ) + { + if ( GetPointer() != p ) + { + StrongPtr temp( p ); + Swap( temp ); + } + return *this; + } + + template + < + typename T1, + bool S1, + class OP1, + class CP1, + template < class > class KP1, + template < class > class RP1, + template < class > class DP1, + template < class > class CNP1 + > + StrongPtr & operator = ( + const StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs ) + { + if ( !rhs.Equals( GetPointer() ) ) + { + StrongPtr temp( rhs ); + temp.Swap( *this ); + } + return *this; + } + + bool IsStrong( void ) const + { + return Strong; + } + + void Swap( StrongPtr & rhs ) + { + OP::Swap( rhs ); + CP::Swap( rhs ); + KP::Swap( rhs ); + DP::Swap( rhs ); + } + + ~StrongPtr() + { + if ( OP::Release( Strong ) ) + { + // Must zap the pointer before deleteing the object. Otherwise a + // cycle of weak pointers will lead to recursion, which leads to + // to deleting the shared object multiple times, which leads to + // undefined behavior. Therefore, this must get pointer before + // zapping it, and then delete the temp pointer. + T * p = GetPointer(); + OP::ZapPointer(); + if ( p != 0 ) + { + DP::Delete( p ); + } + } + } + +#ifdef LOKI_ENABLE_FRIEND_TEMPLATE_TEMPLATE_PARAMETER_WORKAROUND + + // old non standard in class definition of friends + friend bool ReleaseAll( StrongPtr & sp, + typename StrongPtr::StoredType & p ) + { + if ( !sp.RP::OnReleaseAll( sp.IsStrong() || sp.OP::HasStrongPointer() ) ) + { + return false; + } + p = sp.GetPointer(); + sp.OP::SetPointer( sp.DP::Default() ); + return true; + } + + friend bool ResetAll( StrongPtr & sp, + typename StrongPtr::StoredType p ) + { + if ( sp.OP::GetPointer() == p ) + { + return true; + } + if ( !sp.RP::OnResetAll( sp.IsStrong() || sp.OP::HasStrongPointer() ) ) + { + return false; + } + sp.DP::Delete( sp.GetPointer() ); + sp.OP::SetPointer( p ); + return true; + } + +#else + + template + < + typename T1, + bool S1, + class OP1, + class CP1, + template < class > class KP1, + template < class > class RP1, + template < class > class DP1, + template < class > class CNP1 + > + friend bool ReleaseAll( StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & sp, + typename StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 >::StoredType & p ); + + + template + < + typename T1, + bool S1, + class OP1, + class CP1, + template < class > class KP1, + template < class > class RP1, + template < class > class DP1, + template < class > class CNP1 + > + friend bool ResetAll( StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & sp, + typename StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 >::StoredType p ); + +#endif + + + /** Merges ownership of two StrongPtr's that point to same shared object + but are not copointers. Requires Merge function in OwnershipPolicy. + \return True for success, false if not pointer to same object. + */ + template + < + typename T1, + bool S1, + class OP1, + class CP1, + template < class > class KP1, + template < class > class RP1, + template < class > class DP1, + template < class > class CNP1 + > + bool Merge( StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs ) + { + if ( OP::GetPointer() != rhs.OP::GetPointer() ) + { + return false; + } + return OP::Merge( rhs ); + } + + /** Locks StrongPtr so other threads can't affect pointer. Requires the + OwnershipPolicy to have Lock function. + */ + void Lock( void ) + { + OP::Lock(); + } + + /** Unlocks StrongPtr so other threads can affect pointer. Requires the + OwnershipPolicy to have Unlock function. + */ + void Unlock( void ) + { + OP::Unlock(); + } + + PointerType operator -> () + { + KP::OnDereference( GetPointer() ); + return GetPointer(); + } + + ConstPointerType operator -> () const + { + KP::OnDereference( GetPointer() ); + return GetPointer(); + } + + ReferenceType operator * () + { + KP::OnDereference( GetPointer() ); + return * GetPointer(); + } + + ConstReferenceType operator * () const + { + KP::OnDereference( GetPointer() ); + return * GetPointer(); + } + + /// Helper function which can be called to avoid exposing GetPointer function. + template < class T1 > + bool Equals( const T1 * p ) const + { + return ( GetPointer() == p ); + } + + /// Helper function which can be called to avoid exposing GetPointer function. + template < class T1 > + bool LessThan( const T1 * p ) const + { + return ( GetPointer() < p ); + } + + /// Helper function which can be called to avoid exposing GetPointer function. + template < class T1 > + bool GreaterThan( const T1 * p ) const + { + return ( GetPointer() > p ); + } + + /// Equality comparison operator is templated to handle ambiguity. + template + < + typename T1, + bool S1, + class OP1, + class CP1, + template < class > class KP1, + template < class > class RP1, + template < class > class DP1, + template < class > class CNP1 + > + bool operator == ( + const StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs ) const + { + return ( rhs.Equals( GetPointer() ) ); + } + + /// Inequality comparison operator is templated to handle ambiguity. + template + < + typename T1, + bool S1, + class OP1, + class CP1, + template < class > class KP1, + template < class > class RP1, + template < class > class DP1, + template < class > class CNP1 + > + bool operator != ( + const StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs ) const + { + return !( rhs.Equals( GetPointer() ) ); + } + + /// Less-than comparison operator is templated to handle ambiguity. + template + < + typename T1, + bool S1, + class OP1, + class CP1, + template < class > class KP1, + template < class > class RP1, + template < class > class DP1, + template < class > class CNP1 + > + bool operator < ( + const StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs ) const + { + return ( rhs.GreaterThan( GetPointer() ) ); + } + + /// Greater-than comparison operator is templated to handle ambiguity. + template + < + typename T1, + bool S1, + class OP1, + class CP1, + template < class > class KP1, + template < class > class RP1, + template < class > class DP1, + template < class > class CNP1 + > + inline bool operator > ( + const StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs ) const + { + return ( rhs.LessThan( GetPointer() ) ); + } + + /// Less-than-or-equal-to operator is templated to handle ambiguity. + template + < + typename T1, + bool S1, + class OP1, + class CP1, + template < class > class KP1, + template < class > class RP1, + template < class > class DP1, + template < class > class CNP1 + > + inline bool operator <= ( + const StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs ) const + { + return !( rhs.LessThan( GetPointer() ) ); + } + + /// Greater-than-or-equal-to operator is templated to handle ambiguity. + template + < + typename T1, + bool S1, + class OP1, + class CP1, + template < class > class KP1, + template < class > class RP1, + template < class > class DP1, + template < class > class CNP1 + > + inline bool operator >= ( + const StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs ) const + { + return !( rhs.GreaterThan( GetPointer() ) ); + } + + inline bool operator ! () const // Enables "if ( !sp ) ..." + { + return ( 0 == OP::GetPointer() ); + } + +protected: + + inline PointerType GetPointer( void ) + { + return reinterpret_cast< PointerType >( OP::GetPointer() ); + } + + inline ConstPointerType GetPointer( void ) const + { + return reinterpret_cast< ConstPointerType >( OP::GetPointer() ); + } + +private: + + inline ReferenceType GetPointerRef( void ) + { + return reinterpret_cast< ReferenceType >( OP::GetPointerRef() ); + } + + inline ConstReferenceType GetPointerRef( void ) const + { + return reinterpret_cast< ConstReferenceType >( OP::GetPointerRef() ); + } + + // Helper for enabling 'if (sp)' + struct Tester + { + Tester(int) {} + void dummy() {} + }; + + typedef void (Tester::*unspecified_boolean_type_)(); + + typedef typename Select< CP::allow, Tester, unspecified_boolean_type_ >::Result + unspecified_boolean_type; + +public: + // enable 'if (sp)' + operator unspecified_boolean_type() const + { + return !*this ? 0 : &Tester::dummy; + } + +private: + // Helper for disallowing automatic conversion + struct Insipid + { + Insipid(PointerType) {} + }; + + typedef typename Select< CP::allow, PointerType, Insipid >::Result + AutomaticConversionResult; + +public: + operator AutomaticConversionResult() const + { + return GetPointer(); + } + +}; + +// ---------------------------------------------------------------------------- + +// friend functions + +#ifndef LOKI_ENABLE_FRIEND_TEMPLATE_TEMPLATE_PARAMETER_WORKAROUND + +template +< + typename U, + typename T, + bool S, + class OP, + class CP, + template < class > class KP, + template < class > class RP, + template < class > class DP, + template < class > class CNP +> +bool ReleaseAll( StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & sp, + typename StrongPtr< T, S, OP, CP, KP, RP, DP, CNP >::StoredType & p ) +{ + if ( !sp.RP<T>::OnReleaseAll( sp.IsStrong() || sp.OP::HasStrongPointer() ) ) + { + return false; + } + p = sp.GetPointer(); + sp.OP::SetPointer( sp.DP<T>::Default() ); + return true; +} + +template +< + typename U, + typename T, + bool S, + class OP, + class CP, + template < class > class KP, + template < class > class RP, + template < class > class DP, + template < class > class CNP +> +bool ResetAll( StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & sp, + typename StrongPtr< T, S, OP, CP, KP, RP, DP, CNP >::StoredType p ) +{ + if ( sp.OP::GetPointer() == p ) + { + return true; + } + if ( !sp.RP<T>::OnResetAll( sp.IsStrong() || sp.OP::HasStrongPointer() ) ) + { + return false; + } + sp.DP<T>::Delete( sp.GetPointer() ); + sp.OP::SetPointer( p ); + return true; +} +#endif + + +// free comparison operators for class template StrongPtr + +/// operator== for lhs = StrongPtr, rhs = raw pointer +/// \ingroup SmartPointerGroup +template +< + typename U, + typename T, + bool S, + class OP, + class CP, + template < class > class KP, + template < class > class RP, + template < class > class DP, + template < class > class CNP +> +inline bool operator == ( + const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & lhs, U * rhs ) +{ + return ( lhs.Equals( rhs ) ); +} + +/// operator== for lhs = raw pointer, rhs = StrongPtr +/// \ingroup SmartPointerGroup +template +< + typename U, + typename T, + bool S, + class OP, + class CP, + template < class > class KP, + template < class > class RP, + template < class > class DP, + template < class > class CNP +> +inline bool operator == ( U * lhs, + const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & rhs ) +{ + return ( rhs.Equals( lhs ) ); +} + +/// operator!= for lhs = StrongPtr, rhs = raw pointer +/// \ingroup SmartPointerGroup +template +< + typename U, + typename T, + bool S, + class OP, + class CP, + template < class > class KP, + template < class > class RP, + template < class > class DP, + template < class > class CNP +> +inline bool operator != ( + const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & lhs, U * rhs ) +{ + return !( lhs.Equals( rhs ) ); +} + +/// operator!= for lhs = raw pointer, rhs = StrongPtr +/// \ingroup SmartPointerGroup +template +< + typename U, + typename T, + bool S, + class OP, + class CP, + template < class > class KP, + template < class > class RP, + template < class > class DP, + template < class > class CNP +> +inline bool operator != ( U * lhs, + const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & rhs ) +{ + return !( rhs.Equals( lhs ) ); +} + +/// operator< for lhs = StrongPtr, rhs = raw pointer +/// \ingroup SmartPointerGroup +template +< + typename U, + typename T, + bool S, + class OP, + class CP, + template < class > class KP, + template < class > class RP, + template < class > class DP, + template < class > class CNP +> +inline bool operator < ( + const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & lhs, U * rhs ) +{ + return ( lhs.LessThan( rhs ) ); +} + +/// operator< for lhs = raw pointer, rhs = StrongPtr +/// \ingroup SmartPointerGroup +template +< + typename U, + typename T, + bool S, + class OP, + class CP, + template < class > class KP, + template < class > class RP, + template < class > class DP, + template < class > class CNP +> +inline bool operator < ( U * lhs, + const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & rhs ) +{ + return ( rhs.GreaterThan( lhs ) ); +} + +// operator> for lhs = StrongPtr, rhs = raw pointer +/// \ingroup SmartPointerGroup +template +< + typename U, + typename T, + bool S, + class OP, + class CP, + template < class > class KP, + template < class > class RP, + template < class > class DP, + template < class > class CNP +> +inline bool operator > ( + const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & lhs, U * rhs ) +{ + return ( lhs.GreaterThan( rhs ) ); +} + +/// operator> for lhs = raw pointer, rhs = StrongPtr +/// \ingroup SmartPointerGroup +template +< + typename U, + typename T, + bool S, + class OP, + class CP, + template < class > class KP, + template < class > class RP, + template < class > class DP, + template < class > class CNP +> +inline bool operator > ( U * lhs, + const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & rhs ) +{ + return ( rhs.LessThan( lhs ) ); +} + +/// operator<= for lhs = StrongPtr, rhs = raw pointer +/// \ingroup SmartPointerGroup +template +< + typename U, + typename T, + bool S, + class OP, + class CP, + template < class > class KP, + template < class > class RP, + template < class > class DP, + template < class > class CNP +> +inline bool operator <= ( + const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & lhs, U * rhs ) +{ + return !( lhs.GreaterThan( rhs ) ); +} + +/// operator<= for lhs = raw pointer, rhs = StrongPtr +/// \ingroup SmartPointerGroup +template +< + typename U, + typename T, + bool S, + class OP, + class CP, + template < class > class KP, + template < class > class RP, + template < class > class DP, + template < class > class CNP +> +inline bool operator <= ( U * lhs, + const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & rhs ) +{ + return !( rhs.LessThan( lhs ) ); +} + +/// operator>= for lhs = StrongPtr, rhs = raw pointer +/// \ingroup SmartPointerGroup +template +< + typename U, + typename T, + bool S, + class OP, + class CP, + template < class > class KP, + template < class > class RP, + template < class > class DP, + template < class > class CNP +> +inline bool operator >= ( + const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & lhs, U * rhs ) +{ + return !( lhs.LessThan( rhs ) ); +} + +/// operator>= for lhs = raw pointer, rhs = StrongPtr +/// \ingroup SmartPointerGroup +template +< + typename U, + typename T, + bool S, + class OP, + class CP, + template < class > class KP, + template < class > class RP, + template < class > class DP, + template < class > class CNP +> +inline bool operator >= ( U * lhs, + const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & rhs ) +{ + return !( rhs.GreaterThan( lhs ) ); +} + +} // namespace Loki + +namespace std +{ + //////////////////////////////////////////////////////////////////////////////// + /// specialization of std::less for StrongPtr + /// \ingroup SmartPointerGroup + //////////////////////////////////////////////////////////////////////////////// + template + < + typename T, + bool S, + class OP, + class CP, + template < class > class KP, + template < class > class RP, + template < class > class DP, + template < class > class CNP + > + struct less< Loki::StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > > + : public binary_function< + Loki::StrongPtr< T, S, OP, CP, KP, RP, DP, CNP >, + Loki::StrongPtr< T, S, OP, CP, KP, RP, DP, CNP >, bool > + { + bool operator () ( + const Loki::StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & lhs, + const Loki::StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & rhs ) const + { + return ( lhs < rhs ); + } + }; +} + +//////////////////////////////////////////////////////////////////////////////// + +#endif // end file guardian + |