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
This commit is contained in:
rich_sposato 2006-04-05 22:56:58 +00:00
parent 0201647cdc
commit d5f4f0f77f
7 changed files with 3294 additions and 52 deletions

1459
include/loki/StrongPtr.h Normal file

File diff suppressed because it is too large Load diff

619
src/StrongPtr.cpp Normal file
View file

@ -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 <loki/StrongPtr.h>
#include <memory.h>
#include <cassert>
#include <loki/SmallObj.h>
//#define DO_EXTRA_LOKI_TESTS
#ifdef DO_EXTRA_LOKI_TESTS
#include <iostream>
#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.
//

View file

@ -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=

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8,00"
Version="8.00"
Name="SmartPtr"
ProjectGUID="{D7AB4FEF-E7AF-443D-93A5-37F323F2042D}"
RootNamespace="SmartPtr"
@ -150,6 +150,10 @@
<References>
</References>
<Files>
<File
RelativePath=".\base.h"
>
</File>
<File
RelativePath=".\main.cpp"
>
@ -178,6 +182,18 @@
RelativePath="..\..\include\loki\SmartPtr.h"
>
</File>
<File
RelativePath=".\strong.cpp"
>
</File>
<File
RelativePath="..\..\src\StrongPtr.cpp"
>
</File>
<File
RelativePath="..\..\include\loki\StrongPtr.h"
>
</File>
<File
RelativePath="..\..\include\loki\Threads.h"
>

View file

@ -12,6 +12,8 @@
// $Header$
#include <assert.h>
// ----------------------------------------------------------------------------
@ -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.
//

View file

@ -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
//

935
test/SmartPtr/strong.cpp Normal file
View file

@ -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 <loki/StrongPtr.h>
#include <iostream>
#include <cassert>
#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;
}
// ----------------------------------------------------------------------------