From d5f4f0f77fdc514fa6919a3b57065dbb3ceedf53 Mon Sep 17 00:00:00 2001 From: rich_sposato Date: Wed, 5 Apr 2006 22:56:58 +0000 Subject: [PATCH] Added StrongPtr class to Loki along with tests for StrongPtr. git-svn-id: svn://svn.code.sf.net/p/loki-lib/code/trunk@623 7ec92016-0320-0410-acc4-a06ded1c099a --- include/loki/StrongPtr.h | 1459 +++++++++++++++++++++++++++++++++ src/StrongPtr.cpp | 619 ++++++++++++++ test/SmartPtr/SmartPtr.dev | 118 +-- test/SmartPtr/SmartPtr.vcproj | 18 +- test/SmartPtr/base.h | 93 ++- test/SmartPtr/main.cpp | 104 +++ test/SmartPtr/strong.cpp | 935 +++++++++++++++++++++ 7 files changed, 3294 insertions(+), 52 deletions(-) create mode 100644 include/loki/StrongPtr.h create mode 100644 src/StrongPtr.cpp create mode 100644 test/SmartPtr/strong.cpp diff --git a/include/loki/StrongPtr.h b/include/loki/StrongPtr.h new file mode 100644 index 0000000..db4bc21 --- /dev/null +++ b/include/loki/StrongPtr.h @@ -0,0 +1,1459 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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_H +#define LOKI_STRONG_PTR_H + +#include +//#include + + +//////////////////////////////////////////////////////////////////////////////// +/// +/// \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 ) + { + 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 ) + { + 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 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 void DecStrongCount( void ) + { + assert( 0 < m_strongCount ); + --m_strongCount; + } + + 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. +//////////////////////////////////////////////////////////////////////////////// + +class 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 void DecStrongCount( void ) + { + m_Mutex.Lock(); + TwoRefCountInfo::DecStrongCount(); + m_Mutex.Unlock(); + } + + 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; +}; + +} // 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 in elsewhere. It is not thread safe, and is +/// intended for single-threaded environments. +//////////////////////////////////////////////////////////////////////////////// + +class 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 ); + } + + inline bool Release( bool strong ) + { + return Decrement( strong ); + } + + void Increment( bool strong ); + + bool Decrement( bool 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 * GetPointer( void ) const + { + return m_counts->GetPointer(); + } + + inline void * & GetPointerRef( void ) const + { + return m_counts->GetPointerRef(); + } + +private: + TwoRefCounts( void ); + TwoRefCounts & operator = ( const TwoRefCounts & ); + + /// 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 in elsewhere. +//////////////////////////////////////////////////////////////////////////////// + +class LockableTwoRefCounts +{ +protected: + + explicit LockableTwoRefCounts( bool strong ); + + LockableTwoRefCounts( const void * p, bool strong ); + + LockableTwoRefCounts( const LockableTwoRefCounts & rhs, bool strong ) : + m_counts( rhs.m_counts ) + { + Increment( strong ); + } + + 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 ); + + bool Decrement( bool strong ); + + bool HasStrongPointer( void ) const + { + return m_counts->HasStrongPointer(); + } + + void Swap( LockableTwoRefCounts & rhs ); + + void SetPointer( void * p ) + { + m_counts->SetPointer( p ); + } + + void ZapPointer( void ); + + 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; +}; + +//////////////////////////////////////////////////////////////////////////////// +/// \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 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::LOKI_DEFAULT_CONSTNESS +> +class StrongPtr + : public OwnershipPolicy + , public ConversionPolicy + , public CheckingPolicy< T * > + , public ResetPolicy< T > + , public DeletePolicy< T > +{ + + typedef OwnershipPolicy OP; + typedef CheckingPolicy< T * > KP; + typedef ResetPolicy< T > RP; + typedef ConversionPolicy CP; + typedef DeletePolicy< T > DP; + +public: + + 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::Result ExplicitArg; +#else + typedef const StoredType& ImplicitArg; + typedef typename Select::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 ), DP( rhs ), KP( rhs ), CP( 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 ), KP( rhs ), CP( 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( + StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs ) + : OP( rhs, Strong ), KP( rhs ), CP( rhs ), DP( rhs ) + { + } + + 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; + } + + 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 ( GetPointer() != rhs.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(); + DP::Delete( p ); + } + } + + 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; + } + + /** 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(); + } + + /// 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 ( GetPointer() == rhs.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 ( GetPointer() != rhs.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 ( GetPointer() < rhs.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.GetPointer() < 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.GetPointer() < 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 !( GetPointer() < rhs.GetPointer() ); + } + + inline bool operator ! () const // Enables "if ( !sp ) ..." + { + return ( 0 == OP::GetPointer() ); + } + + 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(); + } + +}; + +// ---------------------------------------------------------------------------- + +// 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.GetPointer() == 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.GetPointer() == 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.GetPointer() == 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.GetPointer() != 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.GetPointer() < 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 ( lhs < rhs.GetPointer() ); +} + +// 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 ( rhs < lhs.GetPointer() ); +} + +/// 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.GetPointer() < 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 !( rhs < lhs.GetPointer() ); +} + +/// 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.GetPointer() < 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.GetPointer() < 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 !( lhs < rhs.GetPointer() ); +} + +} // namespace Loki + +//////////////////////////////////////////////////////////////////////////////// +/// specialization of std::less for StrongPtr +/// \ingroup SmartPointerGroup +//////////////////////////////////////////////////////////////////////////////// + +namespace std +{ + 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 less< T * >()( lhs.GetPointer(), rhs.GetPointer() ); + } + }; +} + +//////////////////////////////////////////////////////////////////////////////// + +#endif // end file guardian + +// $Log$ +// Revision 1.1 2006/04/05 22:56:58 rich_sposato +// Added StrongPtr class to Loki along with tests for StrongPtr. +// diff --git a/src/StrongPtr.cpp b/src/StrongPtr.cpp new file mode 100644 index 0000000..88dac2a --- /dev/null +++ b/src/StrongPtr.cpp @@ -0,0 +1,619 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2006 Rich Sposato +// 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. +//////////////////////////////////////////////////////////////////////////////// + +// $Header$ + +// ---------------------------------------------------------------------------- + +#include + +#include +#include + +#include + +//#define DO_EXTRA_LOKI_TESTS +#ifdef DO_EXTRA_LOKI_TESTS + #include +#endif + + +// ---------------------------------------------------------------------------- + +namespace Loki +{ + +// ---------------------------------------------------------------------------- + +TwoRefCounts::TwoRefCounts( bool strong ) + : m_counts( NULL ) +{ + void * temp = SmallObject<>::operator new( + sizeof(Loki::Private::TwoRefCountInfo) ); + assert( temp != 0 ); + m_counts = new ( temp ) Loki::Private::TwoRefCountInfo( strong ); +} + +// ---------------------------------------------------------------------------- + +TwoRefCounts::TwoRefCounts( const void * p, bool strong ) + : m_counts( NULL ) +{ + void * temp = SmallObject<>::operator new( + sizeof(Loki::Private::TwoRefCountInfo) ); + assert( temp != 0 ); + void * p2 = const_cast< void * >( p ); + m_counts = new ( temp ) Loki::Private::TwoRefCountInfo( p2, strong ); +} + +// ---------------------------------------------------------------------------- + +void TwoRefCounts::Increment( bool strong ) +{ + if ( strong ) + { + m_counts->IncStrongCount(); + } + else + { + m_counts->IncWeakCount(); + } +} + +// ---------------------------------------------------------------------------- + +bool TwoRefCounts::Decrement( bool strong ) +{ + if ( strong ) + { + m_counts->DecStrongCount(); + } + else + { + m_counts->DecWeakCount(); + } + return !m_counts->HasStrongPointer(); +} + +// ---------------------------------------------------------------------------- + +void TwoRefCounts::Swap( TwoRefCounts & rhs ) +{ + std::swap( m_counts, rhs.m_counts ); +} + +// ---------------------------------------------------------------------------- + +void TwoRefCounts::ZapPointer( void ) +{ + assert( !m_counts->HasStrongPointer() ); + if ( m_counts->HasWeakPointer() ) + { + m_counts->ZapPointer(); + } + else + { + SmallObject<>::operator delete ( m_counts, + sizeof(Loki::Private::TwoRefCountInfo) ); + m_counts = NULL; + } +} + +// ---------------------------------------------------------------------------- + +LockableTwoRefCounts::LockableTwoRefCounts( bool strong ) + : m_counts( NULL ) +{ + void * temp = SmallObject<>::operator new( + sizeof(Loki::Private::LockableTwoRefCountInfo) ); + assert( temp != 0 ); + m_counts = new ( temp ) Loki::Private::LockableTwoRefCountInfo( strong ); +} + +// ---------------------------------------------------------------------------- + +LockableTwoRefCounts::LockableTwoRefCounts( const void * p, bool strong ) + : m_counts( NULL ) +{ + void * temp = SmallObject<>::operator new( + sizeof(Loki::Private::LockableTwoRefCountInfo) ); + assert( temp != 0 ); + void * p2 = const_cast< void * >( p ); + m_counts = new ( temp ) + Loki::Private::LockableTwoRefCountInfo( p2, strong ); +} + +// ---------------------------------------------------------------------------- + +void LockableTwoRefCounts::Increment( bool strong ) +{ + if ( strong ) + { + m_counts->IncStrongCount(); + } + else + { + m_counts->IncWeakCount(); + } +} + +// ---------------------------------------------------------------------------- + +bool LockableTwoRefCounts::Decrement( bool strong ) +{ + if ( strong ) + { + m_counts->DecStrongCount(); + } + else + { + m_counts->DecWeakCount(); + } + return !m_counts->HasStrongPointer(); +} + +// ---------------------------------------------------------------------------- + +void LockableTwoRefCounts::Swap( LockableTwoRefCounts & rhs ) +{ + std::swap( m_counts, rhs.m_counts ); +} + +// ---------------------------------------------------------------------------- + +void LockableTwoRefCounts::ZapPointer( void ) +{ + assert( !m_counts->HasStrongPointer() ); + if ( m_counts->HasWeakPointer() ) + { + m_counts->ZapPointer(); + } + else + { + SmallObject<>::operator delete ( m_counts, + sizeof(Loki::Private::LockableTwoRefCountInfo) ); + m_counts = NULL; + } +} + +// ---------------------------------------------------------------------------- +// +//namespace Private +//{ + +// ---------------------------------------------------------------------------- + +TwoRefLinks::TwoRefLinks( const void * p, bool strong ) + : m_strong( strong ) + , m_pointer( const_cast< void * >( p ) ) +{ + m_prev = m_next = this; +#ifdef DO_EXTRA_LOKI_TESTS + assert( CountPrevCycle( this ) == CountNextCycle( this ) ); +#endif +} + +// ---------------------------------------------------------------------------- + +TwoRefLinks::TwoRefLinks( const TwoRefLinks & rhs, bool strong ) + : m_strong( strong ) + , m_prev( const_cast< TwoRefLinks * >( &rhs ) ) + , m_next( rhs.m_next ) + , m_pointer( rhs.m_pointer ) +{ + m_prev->m_next = this; + m_next->m_prev = this; + +#ifdef DO_EXTRA_LOKI_TESTS + assert( m_prev->HasPrevNode( this ) ); + assert( m_next->HasNextNode( this ) ); + assert( rhs.m_next->HasNextNode( this ) ); + assert( rhs.m_prev->HasPrevNode( this ) ); + assert( CountPrevCycle( this ) == CountNextCycle( this ) ); + assert( CountPrevCycle( this ) == CountNextCycle( &rhs ) ); + assert( AllNodesHaveSamePointer() ); +#endif +} + +// ---------------------------------------------------------------------------- + +void TwoRefLinks::SetPointer( void * p ) +{ + TwoRefLinks * node = m_prev; + if ( ( this == node ) || ( 0 == node ) ) + return; + +#ifdef DO_EXTRA_LOKI_TESTS + assert( m_prev->HasPrevNode( this ) ); + assert( m_next->HasNextNode( this ) ); + assert( CountPrevCycle( this ) == CountNextCycle( this ) ); + assert( AllNodesHaveSamePointer() ); +#endif + + while ( node != this ) + { + node->m_pointer = p; + node = node->m_next; + } + m_pointer = node; + +#ifdef DO_EXTRA_LOKI_TESTS + assert( m_prev->HasPrevNode( this ) ); + assert( m_next->HasNextNode( this ) ); + assert( CountPrevCycle( this ) == CountNextCycle( this ) ); + assert( AllNodesHaveSamePointer() ); +#endif +} + +// ---------------------------------------------------------------------------- + +bool TwoRefLinks::Release( bool strong ) +{ + + assert( strong == m_strong ); +#ifdef DO_EXTRA_LOKI_TESTS + assert( m_prev->HasPrevNode( this ) ); + assert( m_next->HasNextNode( this ) ); + assert( CountPrevCycle( this ) == CountNextCycle( this ) ); + assert( AllNodesHaveSamePointer() ); +#endif + + if ( NULL == m_next ) + { + assert( NULL == m_prev ); + // Return false so it does not try to destroy shared object + // more than once. + return false; + } + else if (m_next == this) + { + assert(m_prev == this); + // Set these to NULL to prevent re-entrancy. + m_prev = NULL; + m_next = NULL; + // Last one in the cycle has to release the pointer. + return true; + } + +#ifdef DO_EXTRA_LOKI_TESTS + assert( this != m_prev ); + assert( NULL != m_prev ); + assert( m_prev->HasPrevNode( this ) ); + assert( m_next->HasNextNode( this ) ); +#endif + + // If a single node is strong, then return false so it won't release. + if ( HasStrongPointer() ) + { + // A cyclic chain of pointers is only as strong as the strongest link. + m_prev->m_next = m_next; + m_next->m_prev = m_prev; + return false; + } + + return true; +} + +// ---------------------------------------------------------------------------- + +void TwoRefLinks::ZapAllNodes( void ) +{ + TwoRefLinks * p = m_prev; + if ( ( this == p ) || ( 0 == p ) ) + return; +#ifdef DO_EXTRA_LOKI_TESTS + assert( AllNodesHaveSamePointer() ); +#endif + + while ( p != this ) + { + TwoRefLinks * p1 = p->m_prev; + p->m_pointer = 0; + p->m_next = p; + p->m_prev = p; + p = p1; + } + m_pointer = 0; +} + +// ---------------------------------------------------------------------------- + +void TwoRefLinks::Swap( TwoRefLinks & rhs ) +{ + +#ifdef DO_EXTRA_LOKI_TESTS + assert( m_prev->HasPrevNode( this ) ); + assert( m_next->HasNextNode( this ) ); + assert( CountPrevCycle( this ) == CountNextCycle( this ) ); + assert( AllNodesHaveSamePointer() ); + assert( rhs.AllNodesHaveSamePointer() ); +#endif + + std::swap( rhs.m_pointer, m_pointer ); + if (m_next == this) + { + // This is in a cycle by itself. + assert(m_prev == this); + if (rhs.m_next == &rhs) + { + assert(rhs.m_prev == &rhs); + // both are in 1-node cycles - thus there is nothing to do. + return; + } + m_prev = rhs.m_prev; + m_next = rhs.m_next; + m_prev->m_next = m_next->m_prev = this; + rhs.m_next = rhs.m_prev = &rhs; + return; + } + if (rhs.m_next == &rhs) + { + // rhs is in a cycle by itself. + assert( rhs.m_prev == &rhs ); +// rhs.Swap(*this); + rhs.m_prev = m_prev; + rhs.m_next = m_next; + m_prev->m_next = m_next->m_prev = &rhs; + m_next = m_prev = this; + return; + } + if (m_next == &rhs ) // rhs is next neighbour + { + if ( m_prev == &rhs ) + return; // cycle of 2 pointers - no need to swap. + std::swap(m_prev, m_next); + std::swap(rhs.m_prev, rhs.m_next); + std::swap(rhs.m_prev, m_next); + std::swap(rhs.m_prev->m_next,m_next->m_prev); + } + else if ( m_prev == &rhs ) // rhs is prev neighbor + { + if ( m_next == &rhs ) + return; // cycle of 2 pointers - no need to swap. + std::swap( m_prev, m_next ); + std::swap( rhs.m_next, rhs.m_prev ); + std::swap( rhs.m_next, m_prev ); + std::swap( rhs.m_next->m_prev, m_prev->m_next ); + } + else // not neighhbors + { + std::swap(m_prev, rhs.m_prev); + std::swap(m_next, rhs.m_next); + std::swap(m_prev->m_next, rhs.m_prev->m_next); + std::swap(m_next->m_prev, rhs.m_next->m_prev); + } + +#ifdef DO_EXTRA_LOKI_TESTS + assert( m_next == this ? m_prev == this : m_prev != this); + assert( m_prev == this ? m_next == this : m_next != this); + assert( m_prev->HasPrevNode( this ) ); + assert( m_next->HasNextNode( this ) ); + assert( CountPrevCycle( this ) == CountNextCycle( this ) ); + assert( rhs.m_prev->HasPrevNode( &rhs ) ); + assert( rhs.m_next->HasNextNode( &rhs ) ); + assert( CountPrevCycle( &rhs ) == CountNextCycle( &rhs ) ); + assert( AllNodesHaveSamePointer() ); + assert( rhs.AllNodesHaveSamePointer() ); +#endif + +} + +// ---------------------------------------------------------------------------- + +bool TwoRefLinks::AllNodesHaveSamePointer( void ) const +{ + const TwoRefLinks * next = m_next; + if ( NULL == next ) + return true; + do + { + if ( next->m_pointer != m_pointer ) + return false; + next = next->m_next; + } while ( next != this ); + return true; +} + +// ---------------------------------------------------------------------------- + +unsigned int TwoRefLinks::CountPrevCycle( const TwoRefLinks * pThis ) +{ + if ( NULL == pThis ) + return 0; + const TwoRefLinks * p = pThis->m_prev; + if ( NULL == p ) + return 0; + if ( pThis == p ) + return 1; + + unsigned int count = 1; + do + { + p = p->m_prev; + ++count; + } while ( p != pThis ); + + return count; +} + +// ---------------------------------------------------------------------------- + +unsigned int TwoRefLinks::CountNextCycle( const TwoRefLinks * pThis ) +{ + if ( NULL == pThis ) + return 0; + const TwoRefLinks * p = pThis->m_next; + if ( NULL == p ) + return 0; + if ( pThis == p ) + return 1; + + unsigned int count = 1; + while ( p != pThis ) + { + p = p->m_next; + ++count; + } + + return count; +} + +// ---------------------------------------------------------------------------- + +bool TwoRefLinks::HasPrevNode( const TwoRefLinks * p ) const +{ + if ( this == p ) + return true; + const TwoRefLinks * prev = m_prev; + if ( NULL == prev ) + return false; + while ( prev != this ) + { + if ( p == prev ) + return true; + prev = prev->m_prev; + } + return false; +} + +// ---------------------------------------------------------------------------- + +bool TwoRefLinks::HasNextNode( const TwoRefLinks * p ) const +{ + if ( this == p ) + return true; + const TwoRefLinks * next = m_next; + if ( NULL == next ) + return false; + while ( next != this ) + { + if ( p == next ) + return true; + next = next->m_next; + } + return false; +} + +// ---------------------------------------------------------------------------- + +bool TwoRefLinks::HasStrongPointer( void ) const +{ + const TwoRefLinks * next = m_next; + if ( NULL == next ) + return false; + while ( next != this ) + { + if ( next->m_strong ) + return true; + next = next->m_next; + } + return false; +} + +// ---------------------------------------------------------------------------- + +bool TwoRefLinks::Merge( TwoRefLinks & rhs ) +{ +#ifdef DO_EXTRA_LOKI_TESTS + std::cout << std::endl << __FUNCTION__ << " " << __LINE__ << std::endl; +#endif + + if ( NULL == m_next ) + { + assert( NULL == m_prev ); + return false; + } + TwoRefLinks * prhs = &rhs; + if ( prhs == this ) + return true; + if ( NULL == prhs->m_next ) + { + assert( NULL == prhs->m_prev ); + return true; + } + +#ifdef DO_EXTRA_LOKI_TESTS + std::cout << __FUNCTION__ << " " << __LINE__ << std::endl; +#endif + + assert( CountPrevCycle( this ) == CountNextCycle( this ) ); + assert( CountPrevCycle( prhs ) == CountNextCycle( prhs ) ); + // If rhs node is already in this cycle, then no need to merge. + if ( HasPrevNode( &rhs ) ) + { + assert( HasNextNode( &rhs ) ); + return true; + } + +#ifdef DO_EXTRA_LOKI_TESTS + std::cout << __FUNCTION__ << " " << __LINE__ << std::endl; +#endif + + if ( prhs == prhs->m_next ) + { +#ifdef DO_EXTRA_LOKI_TESTS + std::cout << __FUNCTION__ << " " << __LINE__ << std::endl; +#endif + /// rhs is in a cycle with 1 node. + assert( prhs->m_prev == prhs ); + prhs->m_prev = m_prev; + prhs->m_next = this; + m_prev->m_next = prhs; + m_prev = prhs; + } + else if ( this == m_next ) + { +#ifdef DO_EXTRA_LOKI_TESTS + std::cout << __FUNCTION__ << " " << __LINE__ << std::endl; +#endif + /// this is in a cycle with 1 node. + assert( m_prev == this ); + m_prev = prhs->m_prev; + m_next = prhs; + prhs->m_prev->m_next = this; + prhs->m_prev = this; + } + else + { +#ifdef DO_EXTRA_LOKI_TESTS + std::cout << __FUNCTION__ << " " << __LINE__ << std::endl; +#endif + m_next->m_prev = prhs->m_prev; + prhs->m_prev->m_next = m_prev; + m_next = prhs; + prhs->m_prev = this; + } + +#ifdef DO_EXTRA_LOKI_TESTS + std::cout << __FUNCTION__ << " " << __LINE__ << std::endl; +#endif + + assert( CountPrevCycle( this ) == CountNextCycle( this ) ); + +#ifdef DO_EXTRA_LOKI_TESTS + std::cout << __FUNCTION__ << " " << __LINE__ << std::endl; +#endif + return true; +} + +// ---------------------------------------------------------------------------- +// +//} // end namespace Private + +} // end namespace Loki + +// ---------------------------------------------------------------------------- + +// $Log$ +// Revision 1.1 2006/04/05 22:53:10 rich_sposato +// Added StrongPtr class to Loki along with tests for StrongPtr. +// diff --git a/test/SmartPtr/SmartPtr.dev b/test/SmartPtr/SmartPtr.dev index 81a1a45..e7ab8c0 100644 --- a/test/SmartPtr/SmartPtr.dev +++ b/test/SmartPtr/SmartPtr.dev @@ -1,11 +1,11 @@ [Project] FileName=SmartPtr.dev Name=SmartPtr -UnitCount=10 +UnitCount=12 Type=1 Ver=1 ObjFiles= -Includes=C:\Projects\loki\include +Includes=C:\DevCpp\include;C:\Projects\loki\include Libs= PrivateResource= ResourceIncludes= @@ -20,49 +20,49 @@ ObjectOutput= OverrideOutput=0 OverrideOutputName=SmartPtr.exe HostApplication= -Folders=Loki_Headers,Loki_Sources,Test +Folders=Headers,Sources,Tests CommandLine= UseCustomMakefile=0 CustomMakefile= IncludeVersionInfo=0 SupportXPThemes=0 CompilerSet=0 -CompilerSettings=1000001001001001000000 +CompilerSettings=0000001001001001000000 [Unit1] -FileName=..\..\src\Singleton.cpp +FileName=main.cpp CompileCpp=1 -Folder=Loki_Sources +Folder=Tests Compile=1 Link=1 -Priority=1 +Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit2] -FileName=..\..\src\SmallObj.cpp +FileName=..\..\src\Singleton.cpp CompileCpp=1 -Folder=Loki_Sources +Folder=Sources Compile=1 Link=1 -Priority=2 +Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit3] -FileName=..\..\src\SmartPtr.cpp +FileName=..\..\src\SmallObj.cpp CompileCpp=1 -Folder=Loki_Sources +Folder=Sources Compile=1 Link=1 -Priority=3 +Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit4] FileName=..\..\include\loki\Threads.h CompileCpp=1 -Folder=Loki_Headers +Folder=Headers Compile=1 Link=1 Priority=1000 @@ -70,9 +70,9 @@ OverrideBuildCmd=0 BuildCmd= [Unit5] -FileName=..\..\include\loki\ConstPolicy.h +FileName=..\..\include\loki\Singleton.h CompileCpp=1 -Folder=Loki_Headers +Folder=Headers Compile=1 Link=1 Priority=1000 @@ -80,9 +80,9 @@ OverrideBuildCmd=0 BuildCmd= [Unit6] -FileName=..\..\include\loki\Singleton.h +FileName=..\..\include\loki\SmallObj.h CompileCpp=1 -Folder=Loki_Headers +Folder=Headers Compile=1 Link=1 Priority=1000 @@ -90,39 +90,9 @@ OverrideBuildCmd=0 BuildCmd= [Unit7] -FileName=..\..\include\loki\SmallObj.h -CompileCpp=1 -Folder=Loki_Headers -Compile=1 -Link=1 -Priority=1000 -OverrideBuildCmd=0 -BuildCmd= - -[Unit8] FileName=..\..\include\loki\SmartPtr.h CompileCpp=1 -Folder=Loki_Headers -Compile=1 -Link=1 -Priority=1000 -OverrideBuildCmd=0 -BuildCmd= - -[Unit9] -FileName=main.cpp -CompileCpp=1 -Folder=Test -Compile=1 -Link=1 -Priority=1000 -OverrideBuildCmd=0 -BuildCmd= - -[Unit10] -FileName=base.h -CompileCpp=1 -Folder=Test +Folder=Headers Compile=1 Link=1 Priority=1000 @@ -147,3 +117,53 @@ ProductName= ProductVersion= AutoIncBuildNr=0 +[Unit8] +FileName=strong.cpp +CompileCpp=1 +Folder=Tests +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit9] +FileName=..\..\src\StrongPtr.cpp +CompileCpp=1 +Folder=Sources +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit10] +FileName=..\..\include\loki\StrongPtr.h +CompileCpp=1 +Folder=Headers +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit11] +FileName=..\..\src\SmartPtr.cpp +CompileCpp=1 +Folder=Sources +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit12] +FileName=base.h +CompileCpp=1 +Folder=Tests +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + diff --git a/test/SmartPtr/SmartPtr.vcproj b/test/SmartPtr/SmartPtr.vcproj index 15368d0..ff981f0 100644 --- a/test/SmartPtr/SmartPtr.vcproj +++ b/test/SmartPtr/SmartPtr.vcproj @@ -1,7 +1,7 @@ + + @@ -178,6 +182,18 @@ RelativePath="..\..\include\loki\SmartPtr.h" > + + + + + + diff --git a/test/SmartPtr/base.h b/test/SmartPtr/base.h index 2b9062a..d9bb59f 100644 --- a/test/SmartPtr/base.h +++ b/test/SmartPtr/base.h @@ -12,6 +12,8 @@ // $Header$ +#include + // ---------------------------------------------------------------------------- @@ -38,6 +40,8 @@ public: return new BaseClass(); } + void DoThat( void ) const {} + static inline bool AllDestroyed( void ) { return ( s_constructions == s_destructions ); @@ -82,7 +86,7 @@ public: // This function is used only for the DeepCopy policy. virtual BaseClass * Clone( void ) const { - return new BaseClass; + return new PublicSubClass; } }; @@ -94,13 +98,98 @@ public: // This function is used only for the DeepCopy policy. virtual BaseClass * Clone( void ) const { - return new BaseClass; + return new PrivateSubClass; } }; + +// ---------------------------------------------------------------------------- + +/** @class MimicCOM Acts like a COM object by having an intrusive ref count. + */ +class MimicCOM +{ +public: + MimicCOM( void ) + : m_count( 0 ) + , m_AddRefCount( 0 ) + , m_ReleaseCount( 0 ) + { + s_constructions++; + } + + virtual ~MimicCOM( void ) + { + s_destructions++; + } + + void AddRef( void ) + { + m_count++; + m_AddRefCount++; + } + + void Release( void ) + { + m_ReleaseCount++; + assert( 0 < m_count ); + m_count--; + if ( 0 == m_count ) + { + /** @note I consider "delete this;" to be very unsafe! I'm only + using it here for the purpose of testing. + */ + delete this; + } + } + + void DoThat( void ) {} + + static inline bool AllDestroyed( void ) + { + return ( s_constructions == s_destructions ); + } + + static inline bool ExtraConstructions( void ) + { + return ( s_constructions > s_destructions ); + } + + static inline bool ExtraDestructions( void ) + { + return ( s_constructions < s_destructions ); + } + + static inline unsigned int GetCtorCount( void ) + { + return s_constructions; + } + + static inline unsigned int GetDtorCount( void ) + { + return s_destructions; + } + +private: + /// Not implemented. + MimicCOM( const MimicCOM & ); + /// Not implemented. + MimicCOM & operator = ( const MimicCOM & ); + + static unsigned int s_constructions; + static unsigned int s_destructions; + + unsigned int m_count; + unsigned int m_AddRefCount; + unsigned int m_ReleaseCount; +}; + // ---------------------------------------------------------------------------- // $Log$ +// Revision 1.2 2006/04/05 22:53:12 rich_sposato +// Added StrongPtr class to Loki along with tests for StrongPtr. +// // Revision 1.1 2006/03/20 21:14:16 rich_sposato // Adding base.h to CVS. // diff --git a/test/SmartPtr/main.cpp b/test/SmartPtr/main.cpp index 624d3b1..55741b1 100644 --- a/test/SmartPtr/main.cpp +++ b/test/SmartPtr/main.cpp @@ -27,10 +27,31 @@ using namespace Loki; extern void DoStrongRefCountTests( void ); extern void DoStrongRefLinkTests( void ); +extern void DoStrongReleaseTests( void ); +extern void DoWeakCycleTests( void ); +extern void DoStrongConstTests( void ); +extern void DoStrongForwardReferenceTest( void ); unsigned int BaseClass::s_constructions = 0; unsigned int BaseClass::s_destructions = 0; +unsigned int MimicCOM::s_constructions = 0; +unsigned int MimicCOM::s_destructions = 0; + + +// ---------------------------------------------------------------------------- + +/// Used to check if SmartPtr can be used with a forward-reference. +class Thingy; + +typedef Loki::SmartPtr< Thingy, RefCounted, DisallowConversion, + AssertCheck, DefaultSPStorage, PropagateConst > + Thingy_DefaultStorage_ptr; + +typedef Loki::SmartPtr< Thingy, RefCounted, DisallowConversion, + AssertCheck, HeapStorage, PropagateConst > + Thingy_HeapStorage_ptr; + // ---------------------------------------------------------------------------- @@ -53,6 +74,8 @@ typedef Loki::SmartPtr< BaseClass, RefCounted, DisallowConversion, NonConstBase_RefCount_NoConvert_Assert_Propagate_ptr; +// ---------------------------------------------------------------------------- + /// @note These 5 are used for testing ownership policies. typedef Loki::SmartPtr< BaseClass, COMRefCounted, DisallowConversion, AssertCheck, DefaultSPStorage, DontPropagateConst > @@ -74,6 +97,9 @@ typedef Loki::SmartPtr< BaseClass, NoCopy, DisallowConversion, AssertCheck, DefaultSPStorage, DontPropagateConst > NonConstBase_NoCopy_NoConvert_Assert_DontPropagate_ptr; + +// ---------------------------------------------------------------------------- + /// @note These 2 are used for testing inheritance. typedef Loki::SmartPtr< PublicSubClass, RefCounted, DisallowConversion, AssertCheck, DefaultSPStorage, DontPropagateConst > @@ -84,6 +110,14 @@ typedef Loki::SmartPtr< PrivateSubClass, RefCounted, DisallowConversion, PrivateSub_RefCount_NoConvert_Assert_DontPropagate_ptr; +// ---------------------------------------------------------------------------- + +/// @note Used for testing how well SmartPtr works with COM objects. +typedef Loki::SmartPtr< MimicCOM, COMRefCounted, DisallowConversion, + AssertCheck, DefaultSPStorage, DontPropagateConst > + MimicCOM_ptr; + + // ---------------------------------------------------------------------------- void DoConstConversionTests( void ) @@ -303,6 +337,8 @@ void DoRefLinkSwapTests( void ) BaseClass * pBaseClass = new BaseClass; NonConstBase_RefLink_NoConvert_Assert_DontPropagate_ptr p1( pBaseClass ); NonConstBase_RefLink_NoConvert_Assert_DontPropagate_ptr p2( new BaseClass ); + p1->DoThat(); + p2->DoThat(); NonConstBase_RefLink_NoConvert_Assert_DontPropagate_ptr p3( p1 ); NonConstBase_RefLink_NoConvert_Assert_DontPropagate_ptr p4( p2 ); @@ -785,6 +821,7 @@ void DoRefLinkTests( void ) assert( w3 ); assert( w4 ); assert( dtorCount + 1 == BaseClass::GetDtorCount() ); + w3->DoThat(); } assert( ctorCount + 2 == BaseClass::GetCtorCount() ); assert( dtorCount + 2 == BaseClass::GetDtorCount() ); @@ -902,16 +939,80 @@ void DoRefLinkNullPointerTests( void ) // ---------------------------------------------------------------------------- +void DoComRefTest( void ) +{ + + const unsigned int ctorCount = MimicCOM::GetCtorCount(); + const unsigned int dtorCount = MimicCOM::GetDtorCount(); + assert( MimicCOM::AllDestroyed() ); + { + MimicCOM_ptr p1; + } + assert( MimicCOM::AllDestroyed() ); + assert( ctorCount == MimicCOM::GetCtorCount() ); + assert( dtorCount == MimicCOM::GetDtorCount() ); + + { + MimicCOM_ptr p1( new MimicCOM ); + } + assert( ctorCount+1 == MimicCOM::GetCtorCount() ); + assert( dtorCount+1 == MimicCOM::GetDtorCount() ); + + { + MimicCOM_ptr p2( new MimicCOM ); + MimicCOM_ptr p3( p2 ); + MimicCOM_ptr p4; + p4 = p2; + } + assert( ctorCount+2 == MimicCOM::GetCtorCount() ); + assert( dtorCount+2 == MimicCOM::GetDtorCount() ); +} + +// ---------------------------------------------------------------------------- + +void DoForwardReferenceTest( void ) +{ + /** @note These lines should cause the compiler to make a warning message + about attempting to delete an undefined type. But it should not produce + any error messages. + */ + Thingy_DefaultStorage_ptr p1; + Thingy_DefaultStorage_ptr p2( p1 ); + Thingy_DefaultStorage_ptr p3; + p3 = p2; + + /** @note These lines should cause the compiler to make an error message + about attempting to call the destructor for an undefined type. + */ + //Thingy_HeapStorage_ptr p4; + //Thingy_HeapStorage_ptr p5( p4 ); + //Thingy_HeapStorage_ptr p6; + //p6 = p5; +} + +// ---------------------------------------------------------------------------- + int main( unsigned int , const char * [] ) { DoRefLinkTests(); + DoStrongRefCountTests(); + DoStrongRefLinkTests(); + DoStrongReleaseTests(); + DoWeakCycleTests(); + + DoForwardReferenceTest(); + DoStrongForwardReferenceTest(); DoRefCountNullPointerTests(); DoRefLinkNullPointerTests(); DoRefCountSwapTests(); DoRefLinkSwapTests(); + + DoComRefTest(); + + DoStrongConstTests(); DoConstConversionTests(); DoOwnershipConversionTests(); DoInheritanceConversionTests(); @@ -930,6 +1031,9 @@ int main( unsigned int , const char * [] ) // ---------------------------------------------------------------------------- // $Log$ +// Revision 1.5 2006/04/05 22:53:12 rich_sposato +// Added StrongPtr class to Loki along with tests for StrongPtr. +// // Revision 1.4 2006/03/21 20:50:22 syntheticpp // fix include error // diff --git a/test/SmartPtr/strong.cpp b/test/SmartPtr/strong.cpp new file mode 100644 index 0000000..d249115 --- /dev/null +++ b/test/SmartPtr/strong.cpp @@ -0,0 +1,935 @@ +//////////////////////////////////////////////////////////////////////////////// +// Test program for The Loki Library +// Copyright (c) 2006 Richard Sposato +// 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 authors make no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// + +// $Header$ + +// ---------------------------------------------------------------------------- + +#include + +#include +#include + +#include "base.h" + + +// ---------------------------------------------------------------------------- + +using namespace std; +using namespace Loki; + + +// ---------------------------------------------------------------------------- + +/// Used to check if SmartPtr can be used with a forward-reference. +class Thingy; + +typedef Loki::StrongPtr< Thingy, true, TwoRefCounts, DisallowConversion, + AssertCheck, CantResetWithStrong, DeleteSingle, DontPropagateConst > + Thingy_DeleteSingle_ptr; + +typedef Loki::StrongPtr< Thingy, true, TwoRefCounts, DisallowConversion, + AssertCheck, CantResetWithStrong, DeleteUsingFree, DontPropagateConst > + Thingy_DeleteUsingFree_ptr; + +typedef Loki::StrongPtr< Thingy, true, TwoRefCounts, DisallowConversion, + AssertCheck, CantResetWithStrong, DeleteNothing, DontPropagateConst > + Thingy_DeleteNothing_ptr; + + +// ---------------------------------------------------------------------------- + +class Earth; +class Moon; + +typedef Loki::StrongPtr< Earth, false, TwoRefCounts, DisallowConversion, + AssertCheck, CantResetWithStrong, DeleteSingle, DontPropagateConst > + Earth_WeakPtr; + +typedef Loki::StrongPtr< Earth, true, TwoRefCounts, DisallowConversion, + AssertCheck, AllowReset, DeleteSingle, DontPropagateConst > + Earth_StrongPtr; + +typedef Loki::StrongPtr< Moon, false, TwoRefCounts, DisallowConversion, + AssertCheck, CantResetWithStrong, DeleteSingle, DontPropagateConst > + Moon_WeakPtr; + +typedef Loki::StrongPtr< Moon, true, TwoRefCounts, DisallowConversion, + AssertCheck, AllowReset, DeleteSingle, DontPropagateConst > + Moon_StrongPtr; + +// ---------------------------------------------------------------------------- + +class Earth +{ +public: + + Earth( void ) : m_moon() + { + s_constructions++; + } + + ~Earth( void ) + { + s_destructions++; + } + + void SetMoon( const Moon_StrongPtr & p ); + + void SetMoon( const Moon_WeakPtr & p ); + + static inline bool AllDestroyed( void ) + { + return ( s_constructions == s_destructions ); + } + + static inline bool ExtraConstructions( void ) + { + return ( s_constructions > s_destructions ); + } + + static inline bool ExtraDestructions( void ) + { + return ( s_constructions < s_destructions ); + } + + static inline unsigned int GetCtorCount( void ) + { + return s_constructions; + } + + static inline unsigned int GetDtorCount( void ) + { + return s_destructions; + } + +private: + /// Not implemented. + Earth( const Earth & ); + /// Not implemented. + Earth & operator = ( const Earth & ); + + static unsigned int s_constructions; + static unsigned int s_destructions; + + Moon_WeakPtr m_moon; +}; + +unsigned int Earth::s_constructions = 0; +unsigned int Earth::s_destructions = 0; + +// ---------------------------------------------------------------------------- + +class Moon +{ +public: + + Moon( void ) : m_earth() + { + s_constructions++; + } + + ~Moon( void ) + { + s_destructions++; + } + + void SetEarth( const Earth_WeakPtr & p ); + + void SetEarth( const Earth_StrongPtr & p ); + + static inline bool AllDestroyed( void ) + { + return ( s_constructions == s_destructions ); + } + + static inline bool ExtraConstructions( void ) + { + return ( s_constructions > s_destructions ); + } + + static inline bool ExtraDestructions( void ) + { + return ( s_constructions < s_destructions ); + } + + static inline unsigned int GetCtorCount( void ) + { + return s_constructions; + } + + static inline unsigned int GetDtorCount( void ) + { + return s_destructions; + } + +private: + /// Not implemented. + Moon( const Moon & ); + /// Not implemented. + Moon & operator = ( const Moon & ); + + static unsigned int s_constructions; + static unsigned int s_destructions; + Earth_WeakPtr m_earth; +}; + +unsigned int Moon::s_constructions = 0; +unsigned int Moon::s_destructions = 0; + +// ---------------------------------------------------------------------------- + +void Moon::SetEarth( const Earth_WeakPtr & p ) +{ + m_earth = p; +} + +// ---------------------------------------------------------------------------- + +void Moon::SetEarth( const Earth_StrongPtr & p ) +{ + m_earth = p; +} + +// ---------------------------------------------------------------------------- + +void Earth::SetMoon( const Moon_WeakPtr & p ) +{ + m_moon = p; +} + +// ---------------------------------------------------------------------------- + +void Earth::SetMoon( const Moon_StrongPtr & p ) +{ + m_moon = p; +} + +// ---------------------------------------------------------------------------- + +typedef Loki::StrongPtr< BaseClass, false, TwoRefCounts, DisallowConversion, + AssertCheck, CantResetWithStrong, DeleteSingle, DontPropagateConst > + NonConstBase_WeakCount_NoConvert_Assert_NoPropagate_ptr; + +typedef Loki::StrongPtr< BaseClass, true, TwoRefCounts, DisallowConversion, + NoCheck, CantResetWithStrong, DeleteSingle, DontPropagateConst > + NonConstBase_StrongCount_NoConvert_NoCheck_NoPropagate_ptr; + +typedef Loki::StrongPtr< BaseClass, false, TwoRefLinks, DisallowConversion, + AssertCheck, CantResetWithStrong, DeleteSingle, DontPropagateConst > + NonConstBase_WeakLink_NoConvert_Assert_NoPropagate_ptr; + +typedef Loki::StrongPtr< BaseClass, true, TwoRefLinks, DisallowConversion, + NoCheck, CantResetWithStrong, DeleteSingle, DontPropagateConst > + NonConstBase_StrongLink_NoConvert_NoCheck_NoPropagate_ptr; + +typedef Loki::StrongPtr< BaseClass, false, TwoRefCounts, DisallowConversion, + AssertCheck, AllowReset, DeleteSingle, DontPropagateConst > + NonConstBase_WeakCount_NoConvert_Assert_Reset_NoPropagate_ptr; + +typedef Loki::StrongPtr< BaseClass, true, TwoRefCounts, DisallowConversion, + NoCheck, AllowReset, DeleteSingle, DontPropagateConst > + NonConstBase_StrongCount_NoConvert_NoCheck_Reset_NoPropagate_ptr; + +/// @note Used for const propagation tests. +typedef Loki::StrongPtr< const BaseClass, true, TwoRefCounts, DisallowConversion, + NoCheck, CantResetWithStrong, DeleteSingle, PropagateConst > + ConstBase_StrongCount_NoConvert_NoCheck_Propagate_ptr; + +typedef Loki::StrongPtr< const BaseClass, false, TwoRefCounts, DisallowConversion, + AssertCheck, CantResetWithStrong, DeleteSingle, PropagateConst > + ConstBase_WeakCount_NoConvert_Assert_Propagate_ptr; + +// ---------------------------------------------------------------------------- + +void DoStrongRefCountTests( void ) +{ + + BaseClass * pNull = NULL; + const unsigned int ctorCount = BaseClass::GetCtorCount(); + const unsigned int dtorCount = BaseClass::GetDtorCount(); + assert( BaseClass::GetCtorCount() == BaseClass::GetDtorCount() ); + + { + NonConstBase_WeakCount_NoConvert_Assert_NoPropagate_ptr w0; + NonConstBase_StrongCount_NoConvert_NoCheck_NoPropagate_ptr s0; + NonConstBase_WeakCount_NoConvert_Assert_NoPropagate_ptr w1( w0 ); + + // Copy from weak to strong is available. + NonConstBase_StrongCount_NoConvert_NoCheck_NoPropagate_ptr s1( w0 ); + // Assignment from weak to strong is available. + s1 = w1; + + // Converting from strong to weak is available. + NonConstBase_WeakCount_NoConvert_Assert_NoPropagate_ptr w2( s0 ); + // Assignment from strong to weak is available. + w1 = s1; + + assert( !s0 ); + assert( !s1 ); + assert( !w0 ); + assert( !w1 ); + assert( s1 == pNull ); + assert( s0 == pNull ); + assert( w1 == pNull ); + assert( w1 == pNull ); + assert( pNull == s0 ); + assert( pNull == s1 ); + assert( pNull == w0 ); + assert( pNull == w1 ); + assert( s0 == s0 ); + assert( s1 == s1 ); + assert( w0 == w0 ); + assert( w1 == w1 ); + assert( s1 == s0 ); + assert( s0 == s1 ); + assert( w0 == s0 ); + assert( s0 == w0 ); + assert( w0 == w1 ); + assert( w1 == w0 ); + assert( w0 == w1 ); + assert( w1 == s1 ); + assert( s1 == w1 ); + assert( s1 <= s0 ); + assert( s1 >= s0 ); + assert( s0 <= s1 ); + assert( s0 >= s1 ); + assert( w0 <= s0 ); + assert( w0 >= s0 ); + assert( s0 <= w0 ); + assert( s0 >= w0 ); + assert( w1 <= w0 ); + assert( w1 >= w0 ); + assert( w0 <= w1 ); + assert( w0 >= w1 ); + assert( !( s1 < s0 ) ); + assert( !( s1 > s0 ) ); + assert( !( s0 < s1 ) ); + assert( !( s0 > s1 ) ); + assert( !( w0 < s0 ) ); + assert( !( w0 > s0 ) ); + assert( !( s0 < w0 ) ); + assert( !( s0 > w0 ) ); + assert( !( w1 < w0 ) ); + assert( !( w1 > w0 ) ); + assert( !( w0 < w1 ) ); + assert( !( w0 > w1 ) ); + assert( !( w0 < pNull ) ); + assert( !( w0 > pNull ) ); + assert( !( pNull < w0 ) ); + assert( !( pNull > w0 ) ); + } + assert( ctorCount == BaseClass::GetCtorCount() ); + assert( dtorCount == BaseClass::GetDtorCount() ); + + { + NonConstBase_WeakCount_NoConvert_Assert_NoPropagate_ptr w1( new BaseClass ); + NonConstBase_WeakCount_NoConvert_Assert_NoPropagate_ptr w2( new BaseClass ); + assert( w1 != w2 ); + assert( w1 ); + assert( w2 ); + w1 = w2; + assert( w1 == w2 ); + assert( w1 ); + assert( w2 ); + assert( dtorCount + 1 == BaseClass::GetDtorCount() ); + } + assert( ctorCount + 2 == BaseClass::GetCtorCount() ); + assert( dtorCount + 2 == BaseClass::GetDtorCount() ); + + { + NonConstBase_StrongCount_NoConvert_NoCheck_NoPropagate_ptr s1( new BaseClass ); + NonConstBase_StrongCount_NoConvert_NoCheck_NoPropagate_ptr s2( new BaseClass ); + assert( s1 != s2 ); + assert( s1 ); + assert( s2 ); + s1 = s2; + assert( s1 == s2 ); + assert( s1 ); + assert( s2 ); + assert( dtorCount + 3 == BaseClass::GetDtorCount() ); + } + assert( ctorCount + 4 == BaseClass::GetCtorCount() ); + assert( dtorCount + 4 == BaseClass::GetDtorCount() ); + assert( BaseClass::GetCtorCount() == BaseClass::GetDtorCount() ); + + { + NonConstBase_WeakCount_NoConvert_Assert_NoPropagate_ptr w1( new BaseClass ); + NonConstBase_WeakCount_NoConvert_Assert_NoPropagate_ptr w2( new BaseClass ); + NonConstBase_StrongCount_NoConvert_NoCheck_NoPropagate_ptr s1( w1 ); + NonConstBase_StrongCount_NoConvert_NoCheck_NoPropagate_ptr s2( w2 ); + + // prove basic stuff. + assert( w1 != w2 ); + assert( s1 != s2 ); + assert( s1 == w1 ); + assert( s2 == w2 ); + assert( s1 ); + assert( s2 ); + assert( w1 ); + assert( w2 ); + + // prove a weak pointer can be re-assigned to another without affecting + // any strong co-pointers. and that no objects were released. + w1 = w2; // w1 == w2 == s2 s1 + assert( w1 == w2 ); + assert( s1 != s2 ); + assert( s1 != w1 ); + assert( s1 != w2 ); + assert( s2 == w1 ); + assert( w1 ); + assert( w2 ); + assert( s1 ); + assert( s2 ); + assert( dtorCount + 4 == BaseClass::GetDtorCount() ); + + // Prove they all point to same thing. + s1 = s2; // w1 == w2 == s2 == s1 + // and prove that one of them released the object. + assert( dtorCount + 5 == BaseClass::GetDtorCount() ); + assert( w1 == w2 ); + assert( s1 == s2 ); + assert( s1 == w1 ); + assert( s1 == w2 ); + assert( s2 == w1 ); + assert( w1 ); + assert( w2 ); + assert( s1 ); + assert( s2 ); + } + assert( ctorCount + 6 == BaseClass::GetCtorCount() ); + assert( dtorCount + 6 == BaseClass::GetDtorCount() ); + + { + NonConstBase_WeakCount_NoConvert_Assert_NoPropagate_ptr w1( new BaseClass ); + NonConstBase_WeakCount_NoConvert_Assert_NoPropagate_ptr w2( new BaseClass ); + NonConstBase_StrongCount_NoConvert_NoCheck_NoPropagate_ptr s1( w1 ); + NonConstBase_StrongCount_NoConvert_NoCheck_NoPropagate_ptr s2( w2 ); + + // prove basic stuff. w1 == s1 w2 == s2 + assert( w1 != w2 ); + assert( s1 != s2 ); + assert( s1 == w1 ); + assert( s2 == w2 ); + assert( s1 ); + assert( s2 ); + assert( w1 ); + assert( w2 ); + + // prove a strong pointer can be re-assigned to another weak pointer, + // and that any weak co-pointers released the object. + s1 = w2; // s1 == w2 == s2 w1 + assert( w1 != w2 ); + assert( s1 == s2 ); + assert( s1 != w1 ); + assert( s1 == w2 ); + assert( s2 != w1 ); + assert( !w1 ); + assert( w2 ); + assert( s1 ); + assert( s2 ); + assert( dtorCount + 7 == BaseClass::GetDtorCount() ); + + // Prove that when strong pointer is re-assigned, object + // is not destroyed if another strong co-pointer exists. + s1 = w1; // w1 == s1 w2 == s2 + // and prove that none of them released an object. + assert( dtorCount + 7 == BaseClass::GetDtorCount() ); + assert( w1 != w2 ); + assert( s1 != s2 ); + assert( s1 == w1 ); + assert( s2 == w2 ); + assert( !s1 ); + assert( s2 ); + assert( !w1 ); + assert( w2 ); + } + assert( ctorCount + 8 == BaseClass::GetCtorCount() ); + assert( dtorCount + 8 == BaseClass::GetDtorCount() ); +} + +// ---------------------------------------------------------------------------- + +void DoStrongConstTests( void ) +{ + + const unsigned int ctorCount = BaseClass::GetCtorCount(); + const unsigned int dtorCount = BaseClass::GetDtorCount(); + assert( BaseClass::GetCtorCount() == BaseClass::GetDtorCount() ); + + { + NonConstBase_WeakCount_NoConvert_Assert_NoPropagate_ptr w1( new BaseClass ); + const NonConstBase_WeakCount_NoConvert_Assert_NoPropagate_ptr w2( w1 ); + NonConstBase_StrongCount_NoConvert_NoCheck_NoPropagate_ptr s1( w1 ); + const NonConstBase_StrongCount_NoConvert_NoCheck_NoPropagate_ptr s2( w2 ); + + const BaseClass & cbw1 = *w1; + cbw1.DoThat(); + const BaseClass & cbw2 = *w2; + cbw2.DoThat(); + const BaseClass & cbs1 = *s1; + cbs1.DoThat(); + const BaseClass & cbs2 = *s2; + cbs2.DoThat(); + + BaseClass & bw1 = *w1; + bw1.DoThat(); + BaseClass & bw2 = *w2; + bw2.DoThat(); + BaseClass & bs1 = *s1; + bs1.DoThat(); + BaseClass & bs2 = *s2; + bs2.DoThat(); + } + assert( ctorCount + 1 == BaseClass::GetCtorCount() ); + assert( dtorCount + 1 == BaseClass::GetDtorCount() ); + + { + ConstBase_WeakCount_NoConvert_Assert_Propagate_ptr w1( new BaseClass ); + const ConstBase_WeakCount_NoConvert_Assert_Propagate_ptr w2( w1 ); + ConstBase_StrongCount_NoConvert_NoCheck_Propagate_ptr s1( w1 ); + const ConstBase_StrongCount_NoConvert_NoCheck_Propagate_ptr s2( w2 ); + + const BaseClass & cbw1 = *w1; + cbw1.DoThat(); + const BaseClass & cbw2 = *w2; + cbw2.DoThat(); + const BaseClass & cbs1 = *s1; + cbs1.DoThat(); + const BaseClass & cbs2 = *s2; + cbs2.DoThat(); + + /** @note These are illegal because constness is propagated by the + StrongPtr's policy. Your compiler should produce error messages if + you attempt to compile these lines. + */ + //BaseClass & bw1 = *w1; + //bw1.DoThat(); + //BaseClass & bw2 = *w2; + //bw2.DoThat(); + //BaseClass & bs1 = *s1; + //bs1.DoThat(); + //BaseClass & bs2 = *s2; + //bs2.DoThat(); + } + assert( ctorCount + 2 == BaseClass::GetCtorCount() ); + assert( dtorCount + 2 == BaseClass::GetDtorCount() ); +} + +// ---------------------------------------------------------------------------- + +void DoStrongReleaseTests( void ) +{ + + BaseClass * pNull = NULL; + const unsigned int ctorCount = BaseClass::GetCtorCount(); + const unsigned int dtorCount = BaseClass::GetDtorCount(); + assert( BaseClass::GetCtorCount() == BaseClass::GetDtorCount() ); + + { + // These are tests of pointers that don't allow reset or release if + // there is at least 1 strong pointer. Ironically, this means that + // if only 1 strong pointer holds onto an object, and you call Release + // using that strong pointer, it can't release itself. + + NonConstBase_WeakCount_NoConvert_Assert_NoPropagate_ptr w1( new BaseClass ); + NonConstBase_WeakCount_NoConvert_Assert_NoPropagate_ptr w2( new BaseClass ); + NonConstBase_StrongCount_NoConvert_NoCheck_NoPropagate_ptr s1( w1 ); + NonConstBase_StrongCount_NoConvert_NoCheck_NoPropagate_ptr s2( w2 ); + + // Prove that neither weak nor strong pointers can be + // released if any co-pointer is strong. + bool released = ReleaseAll( w2, pNull ); + assert( !released ); + + released = ReleaseAll( w1, pNull ); + assert( !released ); + + released = ReleaseAll( s1, pNull ); + assert( !released ); + + released = ReleaseAll( s2, pNull ); + assert( !released ); + + // Prove that weak and strong pointers can be reset only + // if stored pointer matches parameter pointer - or there + // are no strong co-pointers. + bool reset = ResetAll( w2, pNull ); + assert( !reset ); + + reset = ResetAll( w1, pNull ); + assert( !reset ); + + reset = ResetAll( s1, pNull ); + assert( !reset ); + + reset = ResetAll( s2, pNull ); + assert( !reset ); + + s2 = pNull; + assert( dtorCount + 1 == BaseClass::GetDtorCount() ); + reset = ResetAll( w2, pNull ); + assert( reset ); + + reset = ResetAll( w1, pNull ); + assert( !reset ); + + reset = ResetAll( s1, pNull ); + assert( !reset ); + + reset = ResetAll( s2, pNull ); + assert( reset ); + } + assert( ctorCount + 2 == BaseClass::GetCtorCount() ); + assert( dtorCount + 2 == BaseClass::GetDtorCount() ); + + { + // These are tests of pointers that do allow reset and release even + // if a strong pointer exists. + + NonConstBase_WeakCount_NoConvert_Assert_Reset_NoPropagate_ptr w1( new BaseClass ); + NonConstBase_StrongCount_NoConvert_NoCheck_Reset_NoPropagate_ptr w2( new BaseClass ); + NonConstBase_WeakCount_NoConvert_Assert_Reset_NoPropagate_ptr s1( w1 ); + NonConstBase_StrongCount_NoConvert_NoCheck_Reset_NoPropagate_ptr s2( w2 ); + + BaseClass * thing = NULL; + bool released = ReleaseAll( w2, thing ); + assert( released ); + assert( NULL != thing ); + delete thing; + assert( dtorCount + 3 == BaseClass::GetDtorCount() ); + + released = ReleaseAll( s1, thing ); + assert( released ); + assert( NULL != thing ); + delete thing; + assert( dtorCount + 4 == BaseClass::GetDtorCount() ); + + released = ReleaseAll( w1, thing ); + assert( released ); + assert( NULL == thing ); + + released = ReleaseAll( s2, thing ); + assert( released ); + assert( NULL == thing ); + + // Prove that weak and strong pointers can be reset + // only if stored pointer matches parameter pointer + // - even if there are strong co-pointers. + bool reset = ResetAll( w2, pNull ); + assert( reset ); + + reset = ResetAll( w1, pNull ); + assert( reset ); + + reset = ResetAll( s1, pNull ); + assert( reset ); + + reset = ResetAll( s2, pNull ); + assert( reset ); + assert( ctorCount + 4 == BaseClass::GetCtorCount() ); + assert( dtorCount + 4 == BaseClass::GetDtorCount() ); + + s2 = new BaseClass; + s1 = new BaseClass; + reset = ResetAll( w2, pNull ); + assert( reset ); + + reset = ResetAll( w1, pNull ); + assert( reset ); + } + assert( ctorCount + 6 == BaseClass::GetCtorCount() ); + assert( dtorCount + 6 == BaseClass::GetDtorCount() ); +} + +// ---------------------------------------------------------------------------- + +void DoStrongRefLinkTests( void ) +{ + + BaseClass * pNull = NULL; + const unsigned int ctorCount = BaseClass::GetCtorCount(); + const unsigned int dtorCount = BaseClass::GetDtorCount(); + assert( BaseClass::GetCtorCount() == BaseClass::GetDtorCount() ); + + { + NonConstBase_WeakLink_NoConvert_Assert_NoPropagate_ptr w0; + NonConstBase_WeakLink_NoConvert_Assert_NoPropagate_ptr w1; + NonConstBase_StrongLink_NoConvert_NoCheck_NoPropagate_ptr s0; + NonConstBase_StrongLink_NoConvert_NoCheck_NoPropagate_ptr s1; + assert( !s0 ); + assert( !s1 ); + assert( s0 == s1 ); + assert( s1 == pNull ); + assert( s0 == pNull ); + assert( pNull == s0 ); + assert( pNull == s1 ); + assert( s1 == s0 ); + assert( s1 == s1 ); + assert( s0 == s0 ); + assert( s0 == s1 ); + assert( s1 <= s0 ); + assert( s1 >= s0 ); + assert( s0 <= s1 ); + assert( s0 >= s1 ); + assert( !( s1 < s0 ) ); + assert( !( s1 > s0 ) ); + assert( !( s0 < s1 ) ); + assert( !( s0 > s1 ) ); + assert( !w0 ); + assert( !w1 ); + assert( w0 == pNull ); + assert( s0 == pNull ); + assert( pNull == s0 ); + assert( pNull == w0 ); + assert( w0 == s0 ); + assert( w0 == w0 ); + assert( s0 == s0 ); + assert( s0 == w0 ); + assert( w0 <= s0 ); + assert( w0 >= s0 ); + assert( s0 <= w0 ); + assert( s0 >= w0 ); + assert( !( w0 < s0 ) ); + assert( !( w0 > s0 ) ); + assert( !( s0 < w0 ) ); + assert( !( s0 > w0 ) ); + assert( w0 == w1 ); + assert( w1 == pNull ); + assert( w0 == pNull ); + assert( pNull == w0 ); + assert( pNull == w1 ); + assert( w1 == w0 ); + assert( w1 == w1 ); + assert( w0 == w0 ); + assert( w0 == w1 ); + assert( w1 <= w0 ); + assert( w1 >= w0 ); + assert( w0 <= w1 ); + assert( w0 >= w1 ); + assert( !( w1 < w0 ) ); + assert( !( w1 > w0 ) ); + assert( !( w0 < w1 ) ); + assert( !( w0 > w1 ) ); + } + assert( ctorCount == BaseClass::GetCtorCount() ); + assert( dtorCount == BaseClass::GetDtorCount() ); + + { + NonConstBase_WeakLink_NoConvert_Assert_NoPropagate_ptr w3( new BaseClass ); + NonConstBase_WeakLink_NoConvert_Assert_NoPropagate_ptr w4( new BaseClass ); + assert( w3 != w4 ); + assert( w3 ); + assert( w4 ); + w3 = w4; + assert( w3 == w4 ); + assert( w3 ); + assert( w4 ); + assert( dtorCount + 1 == BaseClass::GetDtorCount() ); + } + assert( ctorCount + 2 == BaseClass::GetCtorCount() ); + assert( dtorCount + 2 == BaseClass::GetDtorCount() ); + + { + NonConstBase_StrongLink_NoConvert_NoCheck_NoPropagate_ptr s3( new BaseClass ); + NonConstBase_StrongLink_NoConvert_NoCheck_NoPropagate_ptr s4( new BaseClass ); + assert( s3 != s4 ); + assert( s3 ); + assert( s4 ); + s3 = s4; + assert( s3 == s4 ); + assert( s3 ); + assert( s4 ); + assert( dtorCount + 3 == BaseClass::GetDtorCount() ); + } + assert( ctorCount + 4 == BaseClass::GetCtorCount() ); + assert( dtorCount + 4 == BaseClass::GetDtorCount() ); + assert( BaseClass::GetCtorCount() == BaseClass::GetDtorCount() ); + +} + +// ---------------------------------------------------------------------------- + +void DoWeakCycleTests( void ) +{ + + const unsigned int ctorCountMoon = Moon::GetCtorCount(); + const unsigned int dtorCountMoon = Moon::GetDtorCount(); + assert( Moon::AllDestroyed() ); + const unsigned int ctorCountEarth = Earth::GetCtorCount(); + const unsigned int dtorCountEarth = Earth::GetDtorCount(); + assert( Earth::AllDestroyed() ); + + { + Earth_WeakPtr ew0; + Moon_WeakPtr mw0; + } + assert( Moon::AllDestroyed() ); + assert( Moon::GetCtorCount() == ctorCountMoon ); + assert( Moon::GetDtorCount() == dtorCountMoon ); + assert( Earth::AllDestroyed() ); + assert( Earth::GetCtorCount() == ctorCountEarth ); + assert( Earth::GetDtorCount() == dtorCountEarth ); + + { + Earth_WeakPtr ew1( new Earth ); + } + assert( Earth::AllDestroyed() ); + assert( Earth::GetCtorCount() == ctorCountEarth+1 ); + assert( Earth::GetDtorCount() == dtorCountEarth+1 ); + + { + Moon_WeakPtr mw1( new Moon ); + } + assert( Moon::AllDestroyed() ); + assert( Moon::GetCtorCount() == ctorCountMoon+1 ); + assert( Moon::GetDtorCount() == dtorCountMoon+1 ); + + { + Earth_WeakPtr ew1( new Earth ); + Moon_WeakPtr mw1( new Moon ); + ew1->SetMoon( mw1 ); + } + assert( Moon::AllDestroyed() ); + assert( Moon::GetCtorCount() == ctorCountMoon+2 ); + assert( Moon::GetDtorCount() == dtorCountMoon+2 ); + assert( Earth::AllDestroyed() ); + assert( Earth::GetCtorCount() == ctorCountEarth+2 ); + assert( Earth::GetDtorCount() == dtorCountEarth+2 ); + + { + Earth_WeakPtr ew1( new Earth ); + Moon_WeakPtr mw1( new Moon ); + mw1->SetEarth( ew1 ); + } + assert( Moon::AllDestroyed() ); + assert( Moon::GetCtorCount() == ctorCountMoon+3 ); + assert( Moon::GetDtorCount() == dtorCountMoon+3 ); + assert( Earth::AllDestroyed() ); + assert( Earth::GetCtorCount() == ctorCountEarth+3 ); + assert( Earth::GetDtorCount() == dtorCountEarth+3 ); + + { + Earth_WeakPtr ew1( new Earth ); + Moon_WeakPtr mw1( new Moon ); + ew1->SetMoon( mw1 ); + mw1->SetEarth( ew1 ); + } + assert( Moon::AllDestroyed() ); + assert( Moon::GetCtorCount() == ctorCountMoon+4 ); + assert( Moon::GetDtorCount() == dtorCountMoon+4 ); + assert( Earth::AllDestroyed() ); + assert( Earth::GetCtorCount() == ctorCountEarth+4 ); + assert( Earth::GetDtorCount() == dtorCountEarth+4 ); + + { + Earth_StrongPtr es1( new Earth ); + Moon_StrongPtr ms1( new Moon ); + } + assert( Moon::AllDestroyed() ); + assert( Moon::GetCtorCount() == ctorCountMoon+5 ); + assert( Moon::GetDtorCount() == dtorCountMoon+5 ); + assert( Earth::AllDestroyed() ); + assert( Earth::GetCtorCount() == ctorCountEarth+5 ); + assert( Earth::GetDtorCount() == dtorCountEarth+5 ); + + { + Earth_StrongPtr es1( new Earth ); + Moon_StrongPtr ms1( new Moon ); + es1->SetMoon( ms1 ); + ms1->SetEarth( es1 ); + } + assert( Moon::AllDestroyed() ); + assert( Moon::GetCtorCount() == ctorCountMoon+6 ); + assert( Moon::GetDtorCount() == dtorCountMoon+6 ); + assert( Earth::AllDestroyed() ); + assert( Earth::GetCtorCount() == ctorCountEarth+6 ); + assert( Earth::GetDtorCount() == dtorCountEarth+6 ); + + { + Earth_StrongPtr es1( new Earth ); + Moon_StrongPtr ms1( new Moon ); + { + Earth_WeakPtr ew1( es1 ); + Moon_WeakPtr mw1( ms1 ); + ew1->SetMoon( mw1 ); + mw1->SetEarth( ew1 ); + } + // Note that dtor counts have not changed from previous test. + assert( Moon::GetCtorCount() == ctorCountMoon+7 ); + assert( Moon::GetDtorCount() == dtorCountMoon+6 ); + assert( Earth::GetCtorCount() == ctorCountEarth+7 ); + assert( Earth::GetDtorCount() == dtorCountEarth+6 ); + } + assert( Moon::AllDestroyed() ); + assert( Moon::GetCtorCount() == ctorCountMoon+7 ); + assert( Moon::GetDtorCount() == dtorCountMoon+7 ); + assert( Earth::AllDestroyed() ); + assert( Earth::GetCtorCount() == ctorCountEarth+7 ); + assert( Earth::GetDtorCount() == dtorCountEarth+7 ); + + { + Earth_StrongPtr es1; + Moon_StrongPtr ms1; + { + Earth_WeakPtr ew1( new Earth ); + Moon_WeakPtr mw1( new Moon ); + ew1->SetMoon( mw1 ); + mw1->SetEarth( ew1 ); + es1 = ew1; + ms1 = mw1; + } + // Note that dtor counts have not changed from previous test. + assert( Moon::GetCtorCount() == ctorCountMoon+8 ); + assert( Moon::GetDtorCount() == dtorCountMoon+7 ); + assert( Earth::GetCtorCount() == ctorCountEarth+8 ); + assert( Earth::GetDtorCount() == dtorCountEarth+7 ); + } + assert( Moon::AllDestroyed() ); + assert( Moon::GetCtorCount() == ctorCountMoon+8 ); + assert( Moon::GetDtorCount() == dtorCountMoon+8 ); + assert( Earth::AllDestroyed() ); + assert( Earth::GetCtorCount() == ctorCountEarth+8 ); + assert( Earth::GetDtorCount() == dtorCountEarth+8 ); +} + +// ---------------------------------------------------------------------------- + +void DoStrongForwardReferenceTest( void ) +{ + /** @note These lines should cause the compiler to make a warning message + about attempting to delete an undefined type. But it should not produce + any error messages. + */ + Thingy_DeleteSingle_ptr p1; + Thingy_DeleteSingle_ptr p2( p1 ); + Thingy_DeleteSingle_ptr p3; + p3 = p1; + + /** @note These lines should cause the compiler to make an error message + about attempting to call the destructor for an undefined type. + */ + //Thingy_DeleteUsingFree_ptr p4; + //Thingy_DeleteUsingFree_ptr p5( p4 ); + //Thingy_DeleteUsingFree_ptr p6; + //p6 = p4; + + /** @note These lines should cause the compiler to make neither a warning + nor an error message even though the type is undefined. + */ + Thingy_DeleteNothing_ptr p7; + Thingy_DeleteNothing_ptr p8( p7 ); + Thingy_DeleteNothing_ptr p9; + p9 = p7; +} + +// ----------------------------------------------------------------------------