Added 3 new policy classes to support single-owner smart
pointers. Fixed 2 obscure bugs in TwoRefLinks policy. git-svn-id: svn://svn.code.sf.net/p/loki-lib/code/trunk@1080 7ec92016-0320-0410-acc4-a06ded1c099a
This commit is contained in:
parent
21f46072bd
commit
a381009fee
1 changed files with 477 additions and 86 deletions
|
@ -33,6 +33,42 @@
|
||||||
namespace Loki
|
namespace Loki
|
||||||
{
|
{
|
||||||
|
|
||||||
|
namespace Private
|
||||||
|
{
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
OneOwnerRefCountInfo::OneOwnerRefCountInfo( SingleOwnerRefCount * ptr )
|
||||||
|
: m_pointer( NULL )
|
||||||
|
, m_strongPtr( ptr )
|
||||||
|
, m_weakCount( ( NULL == ptr ) ? 1 : 0 )
|
||||||
|
{
|
||||||
|
assert( NULL != this );
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
OneOwnerRefCountInfo::OneOwnerRefCountInfo( const void * p,
|
||||||
|
SingleOwnerRefCount * ptr )
|
||||||
|
: m_pointer( p )
|
||||||
|
, m_strongPtr( ptr )
|
||||||
|
, m_weakCount( ( NULL == ptr ) ? 1 : 0 )
|
||||||
|
{
|
||||||
|
assert( NULL != this );
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void OneOwnerRefCountInfo::SetStrongCoPtr( SingleOwnerRefCount * ptr )
|
||||||
|
{
|
||||||
|
assert( NULL != this );
|
||||||
|
m_strongPtr = ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
} // end namespace Private
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
TwoRefCounts::TwoRefCounts( bool strong )
|
TwoRefCounts::TwoRefCounts( bool strong )
|
||||||
|
@ -111,7 +147,7 @@ bool TwoRefCounts::Decrement( bool strong )
|
||||||
|
|
||||||
void TwoRefCounts::Swap( TwoRefCounts & rhs )
|
void TwoRefCounts::Swap( TwoRefCounts & rhs )
|
||||||
{
|
{
|
||||||
std::swap( m_counts, rhs.m_counts );
|
::std::swap( m_counts, rhs.m_counts );
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -133,6 +169,164 @@ void TwoRefCounts::ZapPointer( void )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
SingleOwnerRefCount::SingleOwnerRefCount( bool strong )
|
||||||
|
: m_info( NULL )
|
||||||
|
{
|
||||||
|
assert( NULL != this );
|
||||||
|
|
||||||
|
void * temp = SmallObject<>::operator new(
|
||||||
|
sizeof(Loki::Private::OneOwnerRefCountInfo) );
|
||||||
|
#ifdef DO_EXTRA_LOKI_TESTS
|
||||||
|
assert( temp != 0 );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SingleOwnerRefCount * ptr = ( strong ) ? this : NULL;
|
||||||
|
m_info = new ( temp ) ::Loki::Private::OneOwnerRefCountInfo( ptr );
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
SingleOwnerRefCount::SingleOwnerRefCount( const void * p, bool strong )
|
||||||
|
: m_info( NULL )
|
||||||
|
{
|
||||||
|
assert( NULL != this );
|
||||||
|
|
||||||
|
void * temp = SmallObject<>::operator new(
|
||||||
|
sizeof(Loki::Private::OneOwnerRefCountInfo) );
|
||||||
|
#ifdef DO_EXTRA_LOKI_TESTS
|
||||||
|
assert( temp != 0 );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SingleOwnerRefCount * ptr = ( strong ) ? this : NULL;
|
||||||
|
m_info = new ( temp ) ::Loki::Private::OneOwnerRefCountInfo( p, ptr );
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
SingleOwnerRefCount::SingleOwnerRefCount( const SingleOwnerRefCount & rhs,
|
||||||
|
bool strong )
|
||||||
|
: m_info( NULL )
|
||||||
|
{
|
||||||
|
assert( NULL != this );
|
||||||
|
|
||||||
|
if ( strong && rhs.HasStrongPointer() )
|
||||||
|
{
|
||||||
|
throw ::std::logic_error( StrongPtr_Single_Owner_Exception_Message );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_info = rhs.m_info;
|
||||||
|
if ( strong )
|
||||||
|
{
|
||||||
|
m_info->SetStrongCoPtr( this );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_info->IncWeakCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
SingleOwnerRefCount::SingleOwnerRefCount( const SingleOwnerRefCount & rhs,
|
||||||
|
bool isNull, bool strong )
|
||||||
|
: m_info( NULL )
|
||||||
|
{
|
||||||
|
assert( NULL != this );
|
||||||
|
|
||||||
|
if ( isNull )
|
||||||
|
{
|
||||||
|
void * temp = SmallObject<>::operator new(
|
||||||
|
sizeof(Loki::Private::OneOwnerRefCountInfo) );
|
||||||
|
#ifdef DO_EXTRA_LOKI_TESTS
|
||||||
|
assert( temp != 0 );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SingleOwnerRefCount * ptr = ( strong ) ? this : NULL;
|
||||||
|
m_info = new ( temp ) ::Loki::Private::OneOwnerRefCountInfo( ptr );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( strong && rhs.HasStrongPointer() )
|
||||||
|
{
|
||||||
|
throw ::std::logic_error( StrongPtr_Single_Owner_Exception_Message );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_info = rhs.m_info;
|
||||||
|
if ( strong )
|
||||||
|
{
|
||||||
|
m_info->SetStrongCoPtr( this );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_info->IncWeakCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void SingleOwnerRefCount::Swap( SingleOwnerRefCount & rhs )
|
||||||
|
{
|
||||||
|
assert( NULL != this );
|
||||||
|
|
||||||
|
if ( IsStrong() && rhs.IsStrong() )
|
||||||
|
{
|
||||||
|
// These two strong pointers are trading resources.
|
||||||
|
SingleOwnerRefCount * temp = rhs.m_info->GetStrongCoPointer();
|
||||||
|
rhs.m_info->SetStrongCoPtr( this );
|
||||||
|
m_info->SetStrongCoPtr( temp );
|
||||||
|
}
|
||||||
|
::std::swap( m_info, rhs.m_info );
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool SingleOwnerRefCount::Release( bool strong )
|
||||||
|
{
|
||||||
|
assert( NULL != this );
|
||||||
|
|
||||||
|
assert( strong == IsStrong() );
|
||||||
|
if ( strong )
|
||||||
|
{
|
||||||
|
m_info->SetStrongCoPtr( NULL );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert( 0 < m_info->GetWeakCount() );
|
||||||
|
m_info->DecWeakCount();
|
||||||
|
const bool noOwner = ( !m_info->HasStrongPointer() );
|
||||||
|
return ( ( 0 == m_info->GetWeakCount() ) && noOwner );
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void SingleOwnerRefCount::ZapPointer( void )
|
||||||
|
{
|
||||||
|
assert( !m_info->HasStrongPointer() );
|
||||||
|
if ( m_info->HasWeakPointer() )
|
||||||
|
{
|
||||||
|
m_info->ZapPointer();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SmallObject<>::operator delete ( m_info,
|
||||||
|
sizeof(Loki::Private::OneOwnerRefCountInfo) );
|
||||||
|
m_info = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void SingleOwnerRefCount::SetPointer( void * p )
|
||||||
|
{
|
||||||
|
assert( NULL != this );
|
||||||
|
if ( IsStrong() || ( 1 == m_info->GetWeakCount() ) )
|
||||||
|
{
|
||||||
|
// Only a strong pointer or the last weak pointer may change a resource.
|
||||||
|
m_info->SetPointer( p );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -142,9 +336,7 @@ TwoRefLinks::TwoRefLinks( const void * p, bool strong )
|
||||||
, m_prev( this )
|
, m_prev( this )
|
||||||
, m_next( this )
|
, m_next( this )
|
||||||
{
|
{
|
||||||
#ifdef DO_EXTRA_LOKI_TESTS
|
assert( IsValid() );
|
||||||
assert( CountPrevCycle( this ) == CountNextCycle( this ) );
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -159,14 +351,11 @@ TwoRefLinks::TwoRefLinks( const TwoRefLinks & rhs, bool strong )
|
||||||
m_next->m_prev = this;
|
m_next->m_prev = this;
|
||||||
|
|
||||||
#ifdef DO_EXTRA_LOKI_TESTS
|
#ifdef DO_EXTRA_LOKI_TESTS
|
||||||
assert( m_prev->HasPrevNode( this ) );
|
|
||||||
assert( m_next->HasNextNode( this ) );
|
|
||||||
assert( rhs.m_next->HasNextNode( this ) );
|
assert( rhs.m_next->HasNextNode( this ) );
|
||||||
assert( rhs.m_prev->HasPrevNode( this ) );
|
assert( rhs.m_prev->HasPrevNode( this ) );
|
||||||
assert( CountPrevCycle( this ) == CountNextCycle( this ) );
|
|
||||||
assert( CountPrevCycle( this ) == CountNextCycle( &rhs ) );
|
assert( CountPrevCycle( this ) == CountNextCycle( &rhs ) );
|
||||||
assert( AllNodesHaveSamePointer() );
|
|
||||||
#endif
|
#endif
|
||||||
|
assert( IsValid() );
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -177,6 +366,8 @@ TwoRefLinks::TwoRefLinks( const TwoRefLinks & rhs, bool isNull, bool strong )
|
||||||
, m_next( ( isNull ) ? 0 : rhs.m_next )
|
, m_next( ( isNull ) ? 0 : rhs.m_next )
|
||||||
, m_strong( strong )
|
, m_strong( strong )
|
||||||
{
|
{
|
||||||
|
assert( rhs.IsValid() );
|
||||||
|
|
||||||
if ( isNull )
|
if ( isNull )
|
||||||
{
|
{
|
||||||
m_prev = m_next = this;
|
m_prev = m_next = this;
|
||||||
|
@ -185,16 +376,24 @@ TwoRefLinks::TwoRefLinks( const TwoRefLinks & rhs, bool isNull, bool strong )
|
||||||
{
|
{
|
||||||
m_prev->m_next = this;
|
m_prev->m_next = this;
|
||||||
m_next->m_prev = 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_next->HasNextNode( this ) );
|
||||||
assert( rhs.m_prev->HasPrevNode( this ) );
|
assert( rhs.m_prev->HasPrevNode( this ) );
|
||||||
assert( CountPrevCycle( this ) == CountNextCycle( this ) );
|
|
||||||
assert( CountPrevCycle( this ) == CountNextCycle( &rhs ) );
|
assert( CountPrevCycle( this ) == CountNextCycle( &rhs ) );
|
||||||
assert( AllNodesHaveSamePointer() );
|
}
|
||||||
#endif
|
assert( IsValid() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
TwoRefLinks::~TwoRefLinks( void )
|
||||||
|
{
|
||||||
|
assert( IsValid() );
|
||||||
|
|
||||||
|
if ( ( NULL != m_prev ) && ( this != m_prev ) )
|
||||||
|
{
|
||||||
|
TwoRefLinks * next = m_next;
|
||||||
|
m_prev->m_next = next;
|
||||||
|
m_next->m_prev = m_prev;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,60 +401,41 @@ TwoRefLinks::TwoRefLinks( const TwoRefLinks & rhs, bool isNull, bool strong )
|
||||||
|
|
||||||
void TwoRefLinks::SetPointer( void * p )
|
void TwoRefLinks::SetPointer( void * p )
|
||||||
{
|
{
|
||||||
TwoRefLinks * node = m_prev;
|
assert( IsValid() );
|
||||||
if ( ( this == node ) || ( 0 == node ) )
|
|
||||||
return;
|
|
||||||
|
|
||||||
#ifdef DO_EXTRA_LOKI_TESTS
|
TwoRefLinks * node = m_next;
|
||||||
assert( m_prev->HasPrevNode( this ) );
|
if ( ( this == node ) || ( NULL == node ) )
|
||||||
assert( m_next->HasNextNode( this ) );
|
{
|
||||||
assert( CountPrevCycle( this ) == CountNextCycle( this ) );
|
m_pointer = p;
|
||||||
assert( AllNodesHaveSamePointer() );
|
return;
|
||||||
#endif
|
}
|
||||||
|
|
||||||
while ( node != this )
|
while ( node != this )
|
||||||
{
|
{
|
||||||
node->m_pointer = p;
|
node->m_pointer = p;
|
||||||
node = node->m_next;
|
node = node->m_next;
|
||||||
}
|
}
|
||||||
m_pointer = node;
|
m_pointer = p;
|
||||||
|
|
||||||
#ifdef DO_EXTRA_LOKI_TESTS
|
assert( IsValid() );
|
||||||
assert( m_prev->HasPrevNode( this ) );
|
|
||||||
assert( m_next->HasNextNode( this ) );
|
|
||||||
assert( CountPrevCycle( this ) == CountNextCycle( this ) );
|
|
||||||
assert( AllNodesHaveSamePointer() );
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
bool TwoRefLinks::Release( bool strong )
|
bool TwoRefLinks::Release( bool strong )
|
||||||
{
|
{
|
||||||
|
assert( IsValid() );
|
||||||
(void)strong;
|
|
||||||
#ifdef DO_EXTRA_LOKI_TESTS
|
|
||||||
assert( strong == m_strong );
|
assert( strong == m_strong );
|
||||||
assert( m_prev->HasPrevNode( this ) );
|
(void)strong;
|
||||||
assert( m_next->HasNextNode( this ) );
|
|
||||||
assert( CountPrevCycle( this ) == CountNextCycle( this ) );
|
|
||||||
assert( AllNodesHaveSamePointer() );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if ( NULL == m_next )
|
if ( NULL == m_next )
|
||||||
{
|
{
|
||||||
#ifdef DO_EXTRA_LOKI_TESTS
|
|
||||||
assert( NULL == m_prev );
|
|
||||||
#endif
|
|
||||||
// Return false so it does not try to destroy shared object
|
// Return false so it does not try to destroy shared object
|
||||||
// more than once.
|
// more than once.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if ( m_next == this )
|
else if ( m_next == this )
|
||||||
{
|
{
|
||||||
#ifdef DO_EXTRA_LOKI_TESTS
|
|
||||||
assert(m_prev == this);
|
|
||||||
#endif
|
|
||||||
// Set these to NULL to prevent re-entrancy.
|
// Set these to NULL to prevent re-entrancy.
|
||||||
m_prev = NULL;
|
m_prev = NULL;
|
||||||
m_next = NULL;
|
m_next = NULL;
|
||||||
|
@ -263,22 +443,21 @@ bool TwoRefLinks::Release( bool strong )
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DO_EXTRA_LOKI_TESTS
|
|
||||||
assert( this != m_prev );
|
assert( this != m_prev );
|
||||||
assert( NULL != 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 a single node is strong, then return false so it won't release.
|
||||||
if ( HasStrongPointer() )
|
if ( HasStrongPointer() )
|
||||||
{
|
{
|
||||||
// A cyclic chain of pointers is only as strong as the strongest link.
|
// A cyclic chain of pointers is only as strong as the strongest link.
|
||||||
m_prev->m_next = m_next;
|
m_prev->m_next = m_next;
|
||||||
m_next->m_prev = m_prev;
|
m_next->m_prev = m_prev;
|
||||||
|
m_next = this;
|
||||||
|
m_prev = this;
|
||||||
|
assert( IsValid() );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert( IsValid() );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,8 +465,10 @@ bool TwoRefLinks::Release( bool strong )
|
||||||
|
|
||||||
void TwoRefLinks::ZapAllNodes( void )
|
void TwoRefLinks::ZapAllNodes( void )
|
||||||
{
|
{
|
||||||
|
assert( IsValid() );
|
||||||
|
|
||||||
TwoRefLinks * p = m_prev;
|
TwoRefLinks * p = m_prev;
|
||||||
if ( ( this == p ) || ( 0 == p ) )
|
if ( ( this == p ) || ( NULL == p ) )
|
||||||
return;
|
return;
|
||||||
#ifdef DO_EXTRA_LOKI_TESTS
|
#ifdef DO_EXTRA_LOKI_TESTS
|
||||||
assert( AllNodesHaveSamePointer() );
|
assert( AllNodesHaveSamePointer() );
|
||||||
|
@ -296,28 +477,28 @@ void TwoRefLinks::ZapAllNodes( void )
|
||||||
while ( p != this )
|
while ( p != this )
|
||||||
{
|
{
|
||||||
TwoRefLinks * p1 = p->m_prev;
|
TwoRefLinks * p1 = p->m_prev;
|
||||||
p->m_pointer = 0;
|
p->m_pointer = NULL;
|
||||||
p->m_next = p;
|
p->m_next = p;
|
||||||
p->m_prev = p;
|
p->m_prev = p;
|
||||||
p = p1;
|
p = p1;
|
||||||
}
|
}
|
||||||
m_pointer = 0;
|
m_pointer = NULL;
|
||||||
|
m_next = this;
|
||||||
|
m_prev = this;
|
||||||
|
|
||||||
|
assert( IsValid() );
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
void TwoRefLinks::Swap( TwoRefLinks & rhs )
|
void TwoRefLinks::Swap( TwoRefLinks & rhs )
|
||||||
{
|
{
|
||||||
|
assert( IsValid() );
|
||||||
|
assert( rhs.IsValid() );
|
||||||
|
if ( GetPointer() == rhs.GetPointer() )
|
||||||
|
return;
|
||||||
|
|
||||||
#ifdef DO_EXTRA_LOKI_TESTS
|
::std::swap( rhs.m_pointer, m_pointer );
|
||||||
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)
|
if (m_next == this)
|
||||||
{
|
{
|
||||||
#ifdef DO_EXTRA_LOKI_TESTS
|
#ifdef DO_EXTRA_LOKI_TESTS
|
||||||
|
@ -376,19 +557,8 @@ void TwoRefLinks::Swap( TwoRefLinks & rhs )
|
||||||
std::swap(m_next->m_prev, rhs.m_next->m_prev);
|
std::swap(m_next->m_prev, rhs.m_next->m_prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DO_EXTRA_LOKI_TESTS
|
assert( IsValid() );
|
||||||
assert( m_next == this ? m_prev == this : m_prev != this);
|
assert( rhs.IsValid() );
|
||||||
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
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -457,6 +627,7 @@ bool TwoRefLinks::HasPrevNode( const TwoRefLinks * p ) const
|
||||||
{
|
{
|
||||||
if ( this == p )
|
if ( this == p )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
const TwoRefLinks * prev = m_prev;
|
const TwoRefLinks * prev = m_prev;
|
||||||
if ( NULL == prev )
|
if ( NULL == prev )
|
||||||
return false;
|
return false;
|
||||||
|
@ -475,6 +646,7 @@ bool TwoRefLinks::HasNextNode( const TwoRefLinks * p ) const
|
||||||
{
|
{
|
||||||
if ( this == p )
|
if ( this == p )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
const TwoRefLinks * next = m_next;
|
const TwoRefLinks * next = m_next;
|
||||||
if ( NULL == next )
|
if ( NULL == next )
|
||||||
return false;
|
return false;
|
||||||
|
@ -491,6 +663,8 @@ bool TwoRefLinks::HasNextNode( const TwoRefLinks * p ) const
|
||||||
|
|
||||||
bool TwoRefLinks::HasStrongPointer( void ) const
|
bool TwoRefLinks::HasStrongPointer( void ) const
|
||||||
{
|
{
|
||||||
|
assert( IsValid() );
|
||||||
|
|
||||||
const TwoRefLinks * next = m_next;
|
const TwoRefLinks * next = m_next;
|
||||||
if ( NULL == next )
|
if ( NULL == next )
|
||||||
return false;
|
return false;
|
||||||
|
@ -507,12 +681,12 @@ bool TwoRefLinks::HasStrongPointer( void ) const
|
||||||
|
|
||||||
bool TwoRefLinks::Merge( TwoRefLinks & rhs )
|
bool TwoRefLinks::Merge( TwoRefLinks & rhs )
|
||||||
{
|
{
|
||||||
|
assert( IsValid() );
|
||||||
|
assert( rhs.IsValid() );
|
||||||
|
|
||||||
if ( NULL == m_next )
|
if ( NULL == m_next )
|
||||||
{
|
{
|
||||||
#ifdef DO_EXTRA_LOKI_TESTS
|
|
||||||
assert( NULL == m_prev );
|
assert( NULL == m_prev );
|
||||||
#endif
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
TwoRefLinks * prhs = &rhs;
|
TwoRefLinks * prhs = &rhs;
|
||||||
|
@ -520,14 +694,11 @@ bool TwoRefLinks::Merge( TwoRefLinks & rhs )
|
||||||
return true;
|
return true;
|
||||||
if ( NULL == prhs->m_next )
|
if ( NULL == prhs->m_next )
|
||||||
{
|
{
|
||||||
#ifdef DO_EXTRA_LOKI_TESTS
|
|
||||||
assert( NULL == prhs->m_prev );
|
assert( NULL == prhs->m_prev );
|
||||||
#endif
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DO_EXTRA_LOKI_TESTS
|
#ifdef DO_EXTRA_LOKI_TESTS
|
||||||
assert( CountPrevCycle( this ) == CountNextCycle( this ) );
|
|
||||||
assert( CountPrevCycle( prhs ) == CountNextCycle( prhs ) );
|
assert( CountPrevCycle( prhs ) == CountNextCycle( prhs ) );
|
||||||
#endif
|
#endif
|
||||||
// If rhs node is already in this cycle, then no need to merge.
|
// If rhs node is already in this cycle, then no need to merge.
|
||||||
|
@ -542,9 +713,7 @@ bool TwoRefLinks::Merge( TwoRefLinks & rhs )
|
||||||
if ( prhs == prhs->m_next )
|
if ( prhs == prhs->m_next )
|
||||||
{
|
{
|
||||||
/// rhs is in a cycle with 1 node.
|
/// rhs is in a cycle with 1 node.
|
||||||
#ifdef DO_EXTRA_LOKI_TESTS
|
|
||||||
assert( prhs->m_prev == prhs );
|
assert( prhs->m_prev == prhs );
|
||||||
#endif
|
|
||||||
prhs->m_prev = m_prev;
|
prhs->m_prev = m_prev;
|
||||||
prhs->m_next = this;
|
prhs->m_next = this;
|
||||||
m_prev->m_next = prhs;
|
m_prev->m_next = prhs;
|
||||||
|
@ -553,9 +722,7 @@ bool TwoRefLinks::Merge( TwoRefLinks & rhs )
|
||||||
else if ( this == m_next )
|
else if ( this == m_next )
|
||||||
{
|
{
|
||||||
/// this is in a cycle with 1 node.
|
/// this is in a cycle with 1 node.
|
||||||
#ifdef DO_EXTRA_LOKI_TESTS
|
|
||||||
assert( m_prev == this );
|
assert( m_prev == this );
|
||||||
#endif
|
|
||||||
m_prev = prhs->m_prev;
|
m_prev = prhs->m_prev;
|
||||||
m_next = prhs;
|
m_next = prhs;
|
||||||
prhs->m_prev->m_next = this;
|
prhs->m_prev->m_next = this;
|
||||||
|
@ -571,7 +738,7 @@ bool TwoRefLinks::Merge( TwoRefLinks & rhs )
|
||||||
|
|
||||||
|
|
||||||
#ifdef DO_EXTRA_LOKI_TESTS
|
#ifdef DO_EXTRA_LOKI_TESTS
|
||||||
assert( CountPrevCycle( this ) == CountNextCycle( this ) );
|
assert( IsValid() );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -579,6 +746,230 @@ bool TwoRefLinks::Merge( TwoRefLinks & rhs )
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
unsigned int TwoRefLinks::GetStrongPointerCount( void ) const
|
||||||
|
{
|
||||||
|
assert( IsValid() );
|
||||||
|
|
||||||
|
unsigned int strongCount = ( m_strong ) ? 1 : 0;
|
||||||
|
const TwoRefLinks * next = m_next;
|
||||||
|
if ( ( this == next ) || ( NULL == next ) )
|
||||||
|
return strongCount;
|
||||||
|
|
||||||
|
while ( next != this )
|
||||||
|
{
|
||||||
|
if ( next->m_strong )
|
||||||
|
{
|
||||||
|
++strongCount;
|
||||||
|
}
|
||||||
|
next = next->m_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return strongCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const TwoRefLinks * TwoRefLinks::GetNextStrongPointer( void ) const
|
||||||
|
{
|
||||||
|
assert( IsValid() );
|
||||||
|
|
||||||
|
for ( const TwoRefLinks * next = m_next;
|
||||||
|
( next != this ); next = next->m_next )
|
||||||
|
{
|
||||||
|
if ( next->m_strong )
|
||||||
|
{
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool TwoRefLinks::IsValid( void ) const
|
||||||
|
{
|
||||||
|
assert( NULL != this );
|
||||||
|
|
||||||
|
const bool isThisNext = ( m_next == this );
|
||||||
|
const bool isThisPrev = ( m_prev == this );
|
||||||
|
assert( isThisNext == isThisPrev );
|
||||||
|
(void)isThisNext;
|
||||||
|
(void)isThisPrev;
|
||||||
|
|
||||||
|
const bool isNextNull = ( m_next == NULL );
|
||||||
|
const bool isPrevNull = ( m_prev == NULL );
|
||||||
|
assert( isNextNull == isPrevNull );
|
||||||
|
(void)isNextNull;
|
||||||
|
(void)isPrevNull;
|
||||||
|
|
||||||
|
if ( NULL != m_prev )
|
||||||
|
{
|
||||||
|
assert( NULL != m_next );
|
||||||
|
assert( this == m_next->m_prev );
|
||||||
|
assert( this == m_prev->m_next );
|
||||||
|
assert( m_prev->HasPrevNode( this ) );
|
||||||
|
}
|
||||||
|
if ( NULL != m_next )
|
||||||
|
{
|
||||||
|
assert( NULL != m_prev );
|
||||||
|
assert( this == m_next->m_prev );
|
||||||
|
assert( this == m_prev->m_next );
|
||||||
|
assert( m_next->HasNextNode( this ) );
|
||||||
|
}
|
||||||
|
const unsigned int prevCycleCount = CountPrevCycle( this );
|
||||||
|
const unsigned int nextCycleCount = CountNextCycle( this );
|
||||||
|
assert( prevCycleCount == nextCycleCount );
|
||||||
|
(void)prevCycleCount;
|
||||||
|
(void)nextCycleCount;
|
||||||
|
|
||||||
|
assert( AllNodesHaveSamePointer() );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
SingleOwnerRefLinks::SingleOwnerRefLinks( bool strong )
|
||||||
|
: TwoRefLinks( strong )
|
||||||
|
{
|
||||||
|
assert( NULL != this );
|
||||||
|
const unsigned int strongCount = GetStrongPointerCount();
|
||||||
|
if ( 1 < strongCount )
|
||||||
|
{
|
||||||
|
throw ::std::logic_error( StrongPtr_Single_Owner_Exception_Message );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
SingleOwnerRefLinks::SingleOwnerRefLinks( const void * p, bool strong )
|
||||||
|
: TwoRefLinks( p, strong )
|
||||||
|
{
|
||||||
|
assert( NULL != this );
|
||||||
|
const unsigned int strongCount = GetStrongPointerCount();
|
||||||
|
if ( 1 < strongCount )
|
||||||
|
{
|
||||||
|
throw ::std::logic_error( StrongPtr_Single_Owner_Exception_Message );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
SingleOwnerRefLinks::SingleOwnerRefLinks( const SingleOwnerRefLinks & rhs, bool strong )
|
||||||
|
: TwoRefLinks( rhs, strong )
|
||||||
|
{
|
||||||
|
assert( NULL != this );
|
||||||
|
const unsigned int strongCount = rhs.GetStrongPointerCount();
|
||||||
|
if ( 1 < strongCount )
|
||||||
|
{
|
||||||
|
throw ::std::logic_error( StrongPtr_Single_Owner_Exception_Message );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
SingleOwnerRefLinks::SingleOwnerRefLinks( const SingleOwnerRefLinks & rhs,
|
||||||
|
bool isNull, bool strong )
|
||||||
|
: TwoRefLinks( rhs, isNull, strong )
|
||||||
|
{
|
||||||
|
assert( NULL != this );
|
||||||
|
const unsigned int strongCount = GetStrongPointerCount();
|
||||||
|
if ( 1 < strongCount )
|
||||||
|
{
|
||||||
|
throw ::std::logic_error( StrongPtr_Single_Owner_Exception_Message );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
SingleOwnerRefLinks::~SingleOwnerRefLinks( void )
|
||||||
|
{
|
||||||
|
assert( NULL != this );
|
||||||
|
const unsigned int strongCount = GetStrongPointerCount();
|
||||||
|
// Use assert instead of throw inside a destructor.
|
||||||
|
assert( strongCount < 2 );
|
||||||
|
(void)strongCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void SingleOwnerRefLinks::Swap( SingleOwnerRefLinks & rhs )
|
||||||
|
{
|
||||||
|
assert( NULL != this );
|
||||||
|
if ( GetPointer() == rhs.GetPointer() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
const unsigned int lhsStrongCount = GetStrongPointerCount();
|
||||||
|
if ( 1 < lhsStrongCount )
|
||||||
|
{
|
||||||
|
throw ::std::logic_error( StrongPtr_Single_Owner_Exception_Message );
|
||||||
|
}
|
||||||
|
const unsigned int rhsStrongCount = rhs.GetStrongPointerCount();
|
||||||
|
if ( 1 < rhsStrongCount )
|
||||||
|
{
|
||||||
|
throw ::std::logic_error( StrongPtr_Single_Owner_Exception_Message );
|
||||||
|
}
|
||||||
|
|
||||||
|
TwoRefLinks::Swap( rhs );
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool SingleOwnerRefLinks::Merge( SingleOwnerRefLinks & rhs )
|
||||||
|
{
|
||||||
|
assert( NULL != this );
|
||||||
|
|
||||||
|
const unsigned int lhsStrongCount = GetStrongPointerCount();
|
||||||
|
if ( 1 < lhsStrongCount )
|
||||||
|
{
|
||||||
|
throw ::std::logic_error( StrongPtr_Single_Owner_Exception_Message );
|
||||||
|
}
|
||||||
|
const unsigned int rhsStrongCount = rhs.GetStrongPointerCount();
|
||||||
|
if ( 1 < rhsStrongCount )
|
||||||
|
{
|
||||||
|
throw ::std::logic_error( StrongPtr_Single_Owner_Exception_Message );
|
||||||
|
}
|
||||||
|
if ( 1 < lhsStrongCount + rhsStrongCount )
|
||||||
|
{
|
||||||
|
throw ::std::logic_error( StrongPtr_Single_Owner_Exception_Message );
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool success = TwoRefLinks::Merge( rhs );
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool SingleOwnerRefLinks::Release( bool strong )
|
||||||
|
{
|
||||||
|
assert( NULL != this );
|
||||||
|
|
||||||
|
if ( strong )
|
||||||
|
{
|
||||||
|
const TwoRefLinks * pStrong = GetNextStrongPointer();
|
||||||
|
if ( this != pStrong )
|
||||||
|
{
|
||||||
|
// There is another strong pointer in this linked pointer cycle,
|
||||||
|
// so just return false to prevent this strong pointer from
|
||||||
|
// deleting the same resource multiple times.
|
||||||
|
TwoRefLinks::Release( strong );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned int strongCount = GetStrongPointerCount();
|
||||||
|
// Use assert instead of throw because Release function only gets called
|
||||||
|
// from StrongPtr destructor, and destructors must not throw exceptions.
|
||||||
|
assert( strongCount < 2 );
|
||||||
|
(void)strongCount;
|
||||||
|
|
||||||
|
const bool doZap = TwoRefLinks::Release( strong );
|
||||||
|
return doZap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
#if defined( _MSC_VER )
|
#if defined( _MSC_VER )
|
||||||
#pragma warning( pop )
|
#pragma warning( pop )
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue