1 ////////////////////////////////////////////////////////////////////////////////
3 // Copyright (c) 2006 Rich Sposato
4 // Permission to use, copy, modify, distribute and sell this software for any
5 // purpose is hereby granted without fee, provided that the above copyright
6 // notice appear in all copies and that both that copyright notice and this
7 // permission notice appear in supporting documentation.
8 // The author makes no representations about the
9 // suitability of this software for any purpose. It is provided "as is"
10 // without express or implied warranty.
11 ////////////////////////////////////////////////////////////////////////////////
13 // $Id: StrongPtr.cpp 819 2007-03-07 00:30:12Z rich_sposato $
16 #include <loki/StrongPtr.h>
19 #ifdef DO_EXTRA_LOKI_TESTS
23 #include <loki/SmallObj.h>
26 // ----------------------------------------------------------------------------
31 // ----------------------------------------------------------------------------
33 TwoRefCounts::TwoRefCounts( bool strong )
36 void *temp = SmallObject<>::operator new(
37 sizeof(Loki::Private::TwoRefCountInfo) );
38 #ifdef DO_EXTRA_LOKI_TESTS
41 m_counts = new ( temp ) Loki::Private::TwoRefCountInfo( strong );
44 // ----------------------------------------------------------------------------
46 TwoRefCounts::TwoRefCounts( const void *p, bool strong )
49 void *temp = SmallObject<>::operator new(
50 sizeof(Loki::Private::TwoRefCountInfo) );
51 #ifdef DO_EXTRA_LOKI_TESTS
54 void *p2 = const_cast< void * >( p );
55 m_counts = new ( temp ) Loki::Private::TwoRefCountInfo( p2, strong );
58 // ----------------------------------------------------------------------------
60 void TwoRefCounts::Increment( bool strong )
64 m_counts->IncStrongCount();
68 m_counts->IncWeakCount();
72 // ----------------------------------------------------------------------------
74 bool TwoRefCounts::Decrement( bool strong )
78 m_counts->DecStrongCount();
82 m_counts->DecWeakCount();
84 return !m_counts->HasStrongPointer();
87 // ----------------------------------------------------------------------------
89 void TwoRefCounts::Swap( TwoRefCounts &rhs )
91 std::swap( m_counts, rhs.m_counts );
94 // ----------------------------------------------------------------------------
96 void TwoRefCounts::ZapPointer( void )
98 #ifdef DO_EXTRA_LOKI_TESTS
99 assert( !m_counts->HasStrongPointer() );
101 if ( m_counts->HasWeakPointer() )
103 m_counts->ZapPointer();
107 SmallObject<>::operator delete ( m_counts,
108 sizeof(Loki::Private::TwoRefCountInfo) );
114 // ----------------------------------------------------------------------------
116 TwoRefLinks::TwoRefLinks( const void *p, bool strong )
117 : m_pointer( const_cast< void * >( p ) )
120 m_prev = m_next = this;
121 #ifdef DO_EXTRA_LOKI_TESTS
122 assert( CountPrevCycle( this ) == CountNextCycle( this ) );
126 // ----------------------------------------------------------------------------
128 TwoRefLinks::TwoRefLinks( const TwoRefLinks &rhs, bool strong )
129 : m_pointer( rhs.m_pointer )
130 , m_prev( const_cast< TwoRefLinks * >( &rhs ) )
131 , m_next( rhs.m_next )
134 m_prev->m_next = this;
135 m_next->m_prev = this;
137 #ifdef DO_EXTRA_LOKI_TESTS
138 assert( m_prev->HasPrevNode( this ) );
139 assert( m_next->HasNextNode( this ) );
140 assert( rhs.m_next->HasNextNode( this ) );
141 assert( rhs.m_prev->HasPrevNode( this ) );
142 assert( CountPrevCycle( this ) == CountNextCycle( this ) );
143 assert( CountPrevCycle( this ) == CountNextCycle( &rhs ) );
144 assert( AllNodesHaveSamePointer() );
148 // ----------------------------------------------------------------------------
150 void TwoRefLinks::SetPointer( void *p )
152 TwoRefLinks *node = m_prev;
153 if ( ( this == node ) || ( 0 == node ) )
156 #ifdef DO_EXTRA_LOKI_TESTS
157 assert( m_prev->HasPrevNode( this ) );
158 assert( m_next->HasNextNode( this ) );
159 assert( CountPrevCycle( this ) == CountNextCycle( this ) );
160 assert( AllNodesHaveSamePointer() );
163 while ( node != this )
170 #ifdef DO_EXTRA_LOKI_TESTS
171 assert( m_prev->HasPrevNode( this ) );
172 assert( m_next->HasNextNode( this ) );
173 assert( CountPrevCycle( this ) == CountNextCycle( this ) );
174 assert( AllNodesHaveSamePointer() );
178 // ----------------------------------------------------------------------------
180 bool TwoRefLinks::Release( bool strong )
184 #ifdef DO_EXTRA_LOKI_TESTS
185 assert( strong == m_strong );
186 assert( m_prev->HasPrevNode( this ) );
187 assert( m_next->HasNextNode( this ) );
188 assert( CountPrevCycle( this ) == CountNextCycle( this ) );
189 assert( AllNodesHaveSamePointer() );
192 if ( NULL == m_next )
194 #ifdef DO_EXTRA_LOKI_TESTS
195 assert( NULL == m_prev );
197 // Return false so it does not try to destroy shared object
201 else if (m_next == this)
203 #ifdef DO_EXTRA_LOKI_TESTS
204 assert(m_prev == this);
206 // Set these to NULL to prevent re-entrancy.
209 // Last one in the cycle has to release the pointer.
213 #ifdef DO_EXTRA_LOKI_TESTS
214 assert( this != m_prev );
215 assert( NULL != m_prev );
216 assert( m_prev->HasPrevNode( this ) );
217 assert( m_next->HasNextNode( this ) );
220 // If a single node is strong, then return false so it won't release.
221 if ( HasStrongPointer() )
223 // A cyclic chain of pointers is only as strong as the strongest link.
224 m_prev->m_next = m_next;
225 m_next->m_prev = m_prev;
232 // ----------------------------------------------------------------------------
234 void TwoRefLinks::ZapAllNodes( void )
236 TwoRefLinks *p = m_prev;
237 if ( ( this == p ) || ( 0 == p ) )
239 #ifdef DO_EXTRA_LOKI_TESTS
240 assert( AllNodesHaveSamePointer() );
245 TwoRefLinks *p1 = p->m_prev;
254 // ----------------------------------------------------------------------------
256 void TwoRefLinks::Swap( TwoRefLinks &rhs )
259 #ifdef DO_EXTRA_LOKI_TESTS
260 assert( m_prev->HasPrevNode( this ) );
261 assert( m_next->HasNextNode( this ) );
262 assert( CountPrevCycle( this ) == CountNextCycle( this ) );
263 assert( AllNodesHaveSamePointer() );
264 assert( rhs.AllNodesHaveSamePointer() );
267 std::swap( rhs.m_pointer, m_pointer );
270 #ifdef DO_EXTRA_LOKI_TESTS
271 // This is in a cycle by itself.
272 assert(m_prev == this);
274 if (rhs.m_next == &rhs)
276 #ifdef DO_EXTRA_LOKI_TESTS
277 assert(rhs.m_prev == &rhs);
279 // both are in 1-node cycles - thus there is nothing to do.
284 m_prev->m_next = m_next->m_prev = this;
285 rhs.m_next = rhs.m_prev = &rhs;
288 if (rhs.m_next == &rhs)
290 #ifdef DO_EXTRA_LOKI_TESTS
291 // rhs is in a cycle by itself.
292 assert( rhs.m_prev == &rhs );
296 m_prev->m_next = m_next->m_prev = &rhs;
297 m_next = m_prev = this;
300 if (m_next == &rhs ) // rhs is next neighbour
302 if ( m_prev == &rhs )
303 return; // cycle of 2 pointers - no need to swap.
304 std::swap(m_prev, m_next);
305 std::swap(rhs.m_prev, rhs.m_next);
306 std::swap(rhs.m_prev, m_next);
307 std::swap(rhs.m_prev->m_next,m_next->m_prev);
309 else if ( m_prev == &rhs ) // rhs is prev neighbor
311 if ( m_next == &rhs )
312 return; // cycle of 2 pointers - no need to swap.
313 std::swap( m_prev, m_next );
314 std::swap( rhs.m_next, rhs.m_prev );
315 std::swap( rhs.m_next, m_prev );
316 std::swap( rhs.m_next->m_prev, m_prev->m_next );
318 else // not neighhbors
320 std::swap(m_prev, rhs.m_prev);
321 std::swap(m_next, rhs.m_next);
322 std::swap(m_prev->m_next, rhs.m_prev->m_next);
323 std::swap(m_next->m_prev, rhs.m_next->m_prev);
326 #ifdef DO_EXTRA_LOKI_TESTS
327 assert( m_next == this ? m_prev == this : m_prev != this);
328 assert( m_prev == this ? m_next == this : m_next != this);
329 assert( m_prev->HasPrevNode( this ) );
330 assert( m_next->HasNextNode( this ) );
331 assert( CountPrevCycle( this ) == CountNextCycle( this ) );
332 assert( rhs.m_prev->HasPrevNode( &rhs ) );
333 assert( rhs.m_next->HasNextNode( &rhs ) );
334 assert( CountPrevCycle( &rhs ) == CountNextCycle( &rhs ) );
335 assert( AllNodesHaveSamePointer() );
336 assert( rhs.AllNodesHaveSamePointer() );
341 // ----------------------------------------------------------------------------
343 bool TwoRefLinks::AllNodesHaveSamePointer( void ) const
345 const TwoRefLinks *next = m_next;
350 if ( next->m_pointer != m_pointer )
354 while ( next != this );
358 // ----------------------------------------------------------------------------
360 unsigned int TwoRefLinks::CountPrevCycle( const TwoRefLinks *pThis )
364 const TwoRefLinks *p = pThis->m_prev;
370 unsigned int count = 1;
376 while ( p != pThis );
381 // ----------------------------------------------------------------------------
383 unsigned int TwoRefLinks::CountNextCycle( const TwoRefLinks *pThis )
387 const TwoRefLinks *p = pThis->m_next;
393 unsigned int count = 1;
403 // ----------------------------------------------------------------------------
405 bool TwoRefLinks::HasPrevNode( const TwoRefLinks *p ) const
409 const TwoRefLinks *prev = m_prev;
412 while ( prev != this )
421 // ----------------------------------------------------------------------------
423 bool TwoRefLinks::HasNextNode( const TwoRefLinks *p ) const
427 const TwoRefLinks *next = m_next;
430 while ( next != this )
439 // ----------------------------------------------------------------------------
441 bool TwoRefLinks::HasStrongPointer( void ) const
443 const TwoRefLinks *next = m_next;
446 while ( next != this )
448 if ( next->m_strong )
455 // ----------------------------------------------------------------------------
457 bool TwoRefLinks::Merge( TwoRefLinks &rhs )
460 if ( NULL == m_next )
462 #ifdef DO_EXTRA_LOKI_TESTS
463 assert( NULL == m_prev );
467 TwoRefLinks *prhs = &rhs;
470 if ( NULL == prhs->m_next )
472 #ifdef DO_EXTRA_LOKI_TESTS
473 assert( NULL == prhs->m_prev );
478 #ifdef DO_EXTRA_LOKI_TESTS
479 assert( CountPrevCycle( this ) == CountNextCycle( this ) );
480 assert( CountPrevCycle( prhs ) == CountNextCycle( prhs ) );
482 // If rhs node is already in this cycle, then no need to merge.
483 if ( HasPrevNode( &rhs ) )
485 #ifdef DO_EXTRA_LOKI_TESTS
486 assert( HasNextNode( &rhs ) );
491 if ( prhs == prhs->m_next )
493 /// rhs is in a cycle with 1 node.
494 #ifdef DO_EXTRA_LOKI_TESTS
495 assert( prhs->m_prev == prhs );
497 prhs->m_prev = m_prev;
499 m_prev->m_next = prhs;
502 else if ( this == m_next )
504 /// this is in a cycle with 1 node.
505 #ifdef DO_EXTRA_LOKI_TESTS
506 assert( m_prev == this );
508 m_prev = prhs->m_prev;
510 prhs->m_prev->m_next = this;
515 m_next->m_prev = prhs->m_prev;
516 prhs->m_prev->m_next = m_prev;
522 #ifdef DO_EXTRA_LOKI_TESTS
523 assert( CountPrevCycle( this ) == CountNextCycle( this ) );
529 // ----------------------------------------------------------------------------
531 } // end namespace Loki