StrongPtr.cpp

00001 
00002 // The Loki Library
00003 // Copyright (c) 2006 Rich Sposato
00004 // Permission to use, copy, modify, distribute and sell this software for any 
00005 //     purpose is hereby granted without fee, provided that the above copyright 
00006 //     notice appear in all copies and that both that copyright notice and this 
00007 //     permission notice appear in supporting documentation.
00008 // The author makes no representations about the 
00009 //     suitability of this software for any purpose. It is provided "as is" 
00010 //     without express or implied warranty.
00012 
00013 // $Id: StrongPtr.cpp 807 2007-02-25 12:49:19Z syntheticpp $
00014 
00015 
00016 #include <loki/StrongPtr.h>
00017 
00018 #include <memory.h>
00019 #ifdef DO_EXTRA_LOKI_TESTS
00020     #include <cassert>
00021 #endif
00022 
00023 #include <loki/SmallObj.h>
00024 
00025 
00026 // ----------------------------------------------------------------------------
00027 
00028 namespace Loki
00029 {
00030 
00031 // ----------------------------------------------------------------------------
00032 
00033 TwoRefCounts::TwoRefCounts( bool strong )
00034     : m_counts( NULL )
00035 {
00036     void * temp = SmallObject<>::operator new(
00037         sizeof(Loki::Private::TwoRefCountInfo) );
00038 #ifdef DO_EXTRA_LOKI_TESTS
00039     assert( temp != 0 );
00040 #endif
00041     m_counts = new ( temp ) Loki::Private::TwoRefCountInfo( strong );
00042 }
00043 
00044 // ----------------------------------------------------------------------------
00045 
00046 TwoRefCounts::TwoRefCounts( const void * p, bool strong )
00047     : m_counts( NULL )
00048 {
00049     void * temp = SmallObject<>::operator new(
00050         sizeof(Loki::Private::TwoRefCountInfo) );
00051 #ifdef DO_EXTRA_LOKI_TESTS
00052     assert( temp != 0 );
00053 #endif
00054     void * p2 = const_cast< void * >( p );
00055     m_counts = new ( temp ) Loki::Private::TwoRefCountInfo( p2, strong );
00056 }
00057 
00058 // ----------------------------------------------------------------------------
00059 
00060 void TwoRefCounts::Increment( bool strong )
00061 {
00062     if ( strong )
00063     {
00064         m_counts->IncStrongCount();
00065     }
00066     else
00067     {
00068         m_counts->IncWeakCount();
00069     }
00070 }
00071 
00072 // ----------------------------------------------------------------------------
00073 
00074 bool TwoRefCounts::Decrement( bool strong )
00075 {
00076     if ( strong )
00077     {
00078         m_counts->DecStrongCount();
00079     }
00080     else
00081     {
00082         m_counts->DecWeakCount();
00083     }
00084     return !m_counts->HasStrongPointer();
00085 }
00086 
00087 // ----------------------------------------------------------------------------
00088 
00089 void TwoRefCounts::Swap( TwoRefCounts & rhs )
00090 {
00091     std::swap( m_counts, rhs.m_counts );
00092 }
00093 
00094 // ----------------------------------------------------------------------------
00095 
00096 void TwoRefCounts::ZapPointer( void )
00097 {
00098 #ifdef DO_EXTRA_LOKI_TESTS
00099     assert( !m_counts->HasStrongPointer() );
00100 #endif
00101     if ( m_counts->HasWeakPointer() )
00102     {
00103         m_counts->ZapPointer();
00104     }
00105     else
00106     {
00107         SmallObject<>::operator delete ( m_counts,
00108             sizeof(Loki::Private::TwoRefCountInfo) );
00109         m_counts = NULL;
00110     }
00111 }
00112 
00113 
00114 // ----------------------------------------------------------------------------
00115 
00116 TwoRefLinks::TwoRefLinks( const void * p, bool strong )
00117     : m_pointer( const_cast< void * >( p ) )
00118     , m_strong( strong )
00119 {
00120     m_prev = m_next = this;
00121 #ifdef DO_EXTRA_LOKI_TESTS
00122     assert( CountPrevCycle( this ) == CountNextCycle( this ) );
00123 #endif
00124 }
00125 
00126 // ----------------------------------------------------------------------------
00127 
00128 TwoRefLinks::TwoRefLinks( const TwoRefLinks & rhs, bool strong )
00129     : m_pointer( rhs.m_pointer )
00130     , m_prev( const_cast< TwoRefLinks * >( &rhs ) )
00131     , m_next( rhs.m_next )
00132     , m_strong( strong )
00133 {
00134     m_prev->m_next = this;
00135     m_next->m_prev = this;
00136 
00137 #ifdef DO_EXTRA_LOKI_TESTS
00138     assert( m_prev->HasPrevNode( this ) );
00139     assert( m_next->HasNextNode( this ) );
00140     assert( rhs.m_next->HasNextNode( this ) );
00141     assert( rhs.m_prev->HasPrevNode( this ) );
00142     assert( CountPrevCycle( this ) == CountNextCycle( this ) );
00143     assert( CountPrevCycle( this ) == CountNextCycle( &rhs ) );
00144     assert( AllNodesHaveSamePointer() );
00145 #endif
00146 }
00147 
00148 // ----------------------------------------------------------------------------
00149 
00150 void TwoRefLinks::SetPointer( void * p )
00151 {
00152     TwoRefLinks * node = m_prev;
00153     if ( ( this == node ) || ( 0 == node ) )
00154         return;
00155 
00156 #ifdef DO_EXTRA_LOKI_TESTS
00157     assert( m_prev->HasPrevNode( this ) );
00158     assert( m_next->HasNextNode( this ) );
00159     assert( CountPrevCycle( this ) == CountNextCycle( this ) );
00160     assert( AllNodesHaveSamePointer() );
00161 #endif
00162 
00163     while ( node != this )
00164     {
00165         node->m_pointer = p;
00166         node = node->m_next;
00167     }
00168     m_pointer = node;
00169 
00170 #ifdef DO_EXTRA_LOKI_TESTS
00171     assert( m_prev->HasPrevNode( this ) );
00172     assert( m_next->HasNextNode( this ) );
00173     assert( CountPrevCycle( this ) == CountNextCycle( this ) );
00174     assert( AllNodesHaveSamePointer() );
00175 #endif
00176 }
00177 
00178 // ----------------------------------------------------------------------------
00179 
00180 bool TwoRefLinks::Release( bool strong )
00181 {
00182 
00183     (void)strong;
00184 #ifdef DO_EXTRA_LOKI_TESTS
00185     assert( strong == m_strong );
00186     assert( m_prev->HasPrevNode( this ) );
00187     assert( m_next->HasNextNode( this ) );
00188     assert( CountPrevCycle( this ) == CountNextCycle( this ) );
00189     assert( AllNodesHaveSamePointer() );
00190 #endif
00191 
00192     if ( NULL == m_next )
00193     {
00194 #ifdef DO_EXTRA_LOKI_TESTS
00195         assert( NULL == m_prev );
00196 #endif
00197         // Return false so it does not try to destroy shared object
00198         // more than once.
00199         return false;
00200     }
00201     else if (m_next == this)
00202     {   
00203 #ifdef DO_EXTRA_LOKI_TESTS
00204         assert(m_prev == this);
00205 #endif
00206         // Set these to NULL to prevent re-entrancy.
00207         m_prev = NULL;
00208         m_next = NULL;
00209         // Last one in the cycle has to release the pointer.
00210         return true;
00211     }
00212 
00213 #ifdef DO_EXTRA_LOKI_TESTS
00214     assert( this != m_prev );
00215     assert( NULL != m_prev );
00216     assert( m_prev->HasPrevNode( this ) );
00217     assert( m_next->HasNextNode( this ) );
00218 #endif
00219 
00220     // If a single node is strong, then return false so it won't release.
00221     if ( HasStrongPointer() )
00222     {
00223         // A cyclic chain of pointers is only as strong as the strongest link.
00224         m_prev->m_next = m_next;
00225         m_next->m_prev = m_prev;
00226         return false;
00227     }
00228 
00229     return true;
00230 }
00231 
00232 // ----------------------------------------------------------------------------
00233 
00234 void TwoRefLinks::ZapAllNodes( void )
00235 {
00236     TwoRefLinks * p = m_prev;
00237     if ( ( this == p ) || ( 0 == p ) )
00238         return;
00239 #ifdef DO_EXTRA_LOKI_TESTS
00240     assert( AllNodesHaveSamePointer() );
00241 #endif
00242 
00243     while ( p != this )
00244     {
00245         TwoRefLinks * p1 = p->m_prev;
00246         p->m_pointer = 0;
00247         p->m_next = p;
00248         p->m_prev = p;
00249         p = p1;
00250     }
00251     m_pointer = 0;
00252 }
00253 
00254 // ----------------------------------------------------------------------------
00255 
00256 void TwoRefLinks::Swap( TwoRefLinks & rhs )
00257 {
00258 
00259 #ifdef DO_EXTRA_LOKI_TESTS
00260     assert( m_prev->HasPrevNode( this ) );
00261     assert( m_next->HasNextNode( this ) );
00262     assert( CountPrevCycle( this ) == CountNextCycle( this ) );
00263     assert( AllNodesHaveSamePointer() );
00264     assert( rhs.AllNodesHaveSamePointer() );
00265 #endif
00266 
00267     std::swap( rhs.m_pointer, m_pointer );
00268     if (m_next == this)
00269     {
00270 #ifdef DO_EXTRA_LOKI_TESTS
00271         // This is in a cycle by itself.
00272         assert(m_prev == this);
00273 #endif
00274         if (rhs.m_next == &rhs)
00275         {
00276 #ifdef DO_EXTRA_LOKI_TESTS
00277             assert(rhs.m_prev == &rhs);
00278 #endif
00279             // both are in 1-node cycles - thus there is nothing to do.
00280             return;
00281         }
00282         m_prev = rhs.m_prev;
00283         m_next = rhs.m_next;
00284         m_prev->m_next = m_next->m_prev = this;
00285         rhs.m_next = rhs.m_prev = &rhs;
00286         return;
00287     }
00288     if (rhs.m_next == &rhs)
00289     {
00290 #ifdef DO_EXTRA_LOKI_TESTS
00291         // rhs is in a cycle by itself.
00292         assert( rhs.m_prev == &rhs );
00293 #endif
00294         rhs.m_prev = m_prev;
00295         rhs.m_next = m_next;
00296         m_prev->m_next = m_next->m_prev = &rhs;
00297         m_next = m_prev = this;
00298         return;
00299     }
00300     if (m_next == &rhs ) // rhs is next neighbour
00301     {
00302         if ( m_prev == &rhs )
00303             return;  // cycle of 2 pointers - no need to swap.
00304         std::swap(m_prev, m_next);
00305         std::swap(rhs.m_prev, rhs.m_next);
00306         std::swap(rhs.m_prev, m_next);
00307         std::swap(rhs.m_prev->m_next,m_next->m_prev);
00308     }
00309     else if ( m_prev == &rhs ) // rhs is prev neighbor
00310     {
00311         if ( m_next == &rhs )
00312             return;  // cycle of 2 pointers - no need to swap.
00313         std::swap( m_prev, m_next );
00314         std::swap( rhs.m_next, rhs.m_prev );
00315         std::swap( rhs.m_next, m_prev );
00316         std::swap( rhs.m_next->m_prev, m_prev->m_next );
00317     }
00318     else // not neighhbors
00319     {
00320         std::swap(m_prev, rhs.m_prev);
00321         std::swap(m_next, rhs.m_next);
00322         std::swap(m_prev->m_next, rhs.m_prev->m_next);
00323         std::swap(m_next->m_prev, rhs.m_next->m_prev);
00324     }
00325 
00326 #ifdef DO_EXTRA_LOKI_TESTS
00327     assert( m_next == this ? m_prev == this : m_prev != this);
00328     assert( m_prev == this ? m_next == this : m_next != this);
00329     assert( m_prev->HasPrevNode( this ) );
00330     assert( m_next->HasNextNode( this ) );
00331     assert( CountPrevCycle( this ) == CountNextCycle( this ) );
00332     assert( rhs.m_prev->HasPrevNode( &rhs ) );
00333     assert( rhs.m_next->HasNextNode( &rhs ) );
00334     assert( CountPrevCycle( &rhs ) == CountNextCycle( &rhs ) );
00335     assert( AllNodesHaveSamePointer() );
00336     assert( rhs.AllNodesHaveSamePointer() );
00337 #endif
00338 
00339 }
00340 
00341 // ----------------------------------------------------------------------------
00342 
00343 bool TwoRefLinks::AllNodesHaveSamePointer( void ) const
00344 {
00345     const TwoRefLinks * next = m_next;
00346     if ( NULL == next )
00347         return true;
00348     do
00349     {
00350         if ( next->m_pointer != m_pointer )
00351             return false;
00352         next = next->m_next;
00353     } while ( next != this );
00354     return true;
00355 }
00356 
00357 // ----------------------------------------------------------------------------
00358 
00359 unsigned int TwoRefLinks::CountPrevCycle( const TwoRefLinks * pThis )
00360 {
00361     if ( NULL == pThis )
00362         return 0;
00363     const TwoRefLinks * p = pThis->m_prev;
00364     if ( NULL == p )
00365         return 0;
00366     if ( pThis == p )
00367         return 1;
00368 
00369     unsigned int count = 1;
00370     do
00371     {
00372         p = p->m_prev;
00373         ++count;
00374     } while ( p != pThis );
00375 
00376     return count;
00377 }
00378 
00379 // ----------------------------------------------------------------------------
00380 
00381 unsigned int TwoRefLinks::CountNextCycle( const TwoRefLinks * pThis )
00382 {
00383     if ( NULL == pThis )
00384         return 0;
00385     const TwoRefLinks * p = pThis->m_next;
00386     if ( NULL == p )
00387         return 0;
00388     if ( pThis == p )
00389         return 1;
00390 
00391     unsigned int count = 1;
00392     while ( p != pThis )
00393     {
00394         p = p->m_next;
00395         ++count;
00396     }
00397 
00398     return count;
00399 }
00400 
00401 // ----------------------------------------------------------------------------
00402 
00403 bool TwoRefLinks::HasPrevNode( const TwoRefLinks * p ) const
00404 {
00405     if ( this == p )
00406         return true;
00407     const TwoRefLinks * prev = m_prev;
00408     if ( NULL == prev )
00409         return false;
00410     while ( prev != this )
00411     {
00412         if ( p == prev )
00413             return true;
00414         prev = prev->m_prev;
00415     }
00416     return false;
00417 }
00418 
00419 // ----------------------------------------------------------------------------
00420 
00421 bool TwoRefLinks::HasNextNode( const TwoRefLinks * p ) const
00422 {
00423     if ( this == p )
00424         return true;
00425     const TwoRefLinks * next = m_next;
00426     if ( NULL == next )
00427         return false;
00428     while ( next != this )
00429     {
00430         if ( p == next )
00431             return true;
00432         next = next->m_next;
00433     }
00434     return false;
00435 }
00436 
00437 // ----------------------------------------------------------------------------
00438 
00439 bool TwoRefLinks::HasStrongPointer( void ) const
00440 {
00441     const TwoRefLinks * next = m_next;
00442     if ( NULL == next )
00443         return false;
00444     while ( next != this )
00445     {
00446         if ( next->m_strong )
00447             return true;
00448         next = next->m_next;
00449     }
00450     return false;
00451 }
00452 
00453 // ----------------------------------------------------------------------------
00454 
00455 bool TwoRefLinks::Merge( TwoRefLinks & rhs )
00456 {
00457 
00458     if ( NULL == m_next )
00459     {
00460 #ifdef DO_EXTRA_LOKI_TESTS
00461         assert( NULL == m_prev );
00462 #endif
00463         return false;
00464     }
00465     TwoRefLinks * prhs = &rhs;
00466     if ( prhs == this )
00467         return true;
00468     if ( NULL == prhs->m_next )
00469     {
00470 #ifdef DO_EXTRA_LOKI_TESTS
00471         assert( NULL == prhs->m_prev );
00472 #endif
00473         return true;
00474     }
00475 
00476 #ifdef DO_EXTRA_LOKI_TESTS
00477     assert( CountPrevCycle( this ) == CountNextCycle( this ) );
00478     assert( CountPrevCycle( prhs ) == CountNextCycle( prhs ) );
00479 #endif
00480     // If rhs node is already in this cycle, then no need to merge.
00481     if ( HasPrevNode( &rhs ) )
00482     {
00483 #ifdef DO_EXTRA_LOKI_TESTS
00484         assert( HasNextNode( &rhs ) );
00485 #endif
00486         return true;
00487     }
00488 
00489     if ( prhs == prhs->m_next )
00490     {
00492 #ifdef DO_EXTRA_LOKI_TESTS
00493         assert( prhs->m_prev == prhs );
00494 #endif
00495         prhs->m_prev = m_prev;
00496         prhs->m_next = this;
00497         m_prev->m_next = prhs;
00498         m_prev = prhs;
00499     }
00500     else if ( this == m_next )
00501     {
00503 #ifdef DO_EXTRA_LOKI_TESTS
00504         assert( m_prev == this );
00505 #endif
00506         m_prev = prhs->m_prev;
00507         m_next = prhs;
00508         prhs->m_prev->m_next = this;
00509         prhs->m_prev = this;
00510     }
00511     else
00512     {
00513         m_next->m_prev = prhs->m_prev;
00514         prhs->m_prev->m_next = m_prev;
00515         m_next = prhs;
00516         prhs->m_prev = this;
00517     }
00518 
00519 
00520 #ifdef DO_EXTRA_LOKI_TESTS
00521     assert( CountPrevCycle( this ) == CountNextCycle( this ) );
00522 #endif
00523 
00524     return true;
00525 }
00526 
00527 // ----------------------------------------------------------------------------
00528 
00529 } // end namespace Loki
00530 

Generated on Sun Feb 25 16:52:28 2007 for Loki by  doxygen 1.5.1-p1