1 ////////////////////////////////////////////////////////////////////////////////
2 // The Loki Library
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 ////////////////////////////////////////////////////////////////////////////////
12 
13 // $Id: StrongPtr.cpp 819 2007-03-07 00:30:12Z rich_sposato $
14 
15 
16 #include <loki/StrongPtr.h>
17 
18 #include <memory.h>
19 #ifdef DO_EXTRA_LOKI_TESTS
20     #include <cassert>
21 #endif
22 
23 #include <loki/SmallObj.h>
24 
25 
26 // ----------------------------------------------------------------------------
27 
28 namespace Loki
29 {
30 
31 // ----------------------------------------------------------------------------
32 
TwoRefCounts(bool strong)33 TwoRefCounts::TwoRefCounts( bool strong )
34     : m_counts( NULL )
35 {
36     void * temp = SmallObject<>::operator new(
37         sizeof(Loki::Private::TwoRefCountInfo) );
38 #ifdef DO_EXTRA_LOKI_TESTS
39     assert( temp != 0 );
40 #endif
41     m_counts = new ( temp ) Loki::Private::TwoRefCountInfo( strong );
42 }
43 
44 // ----------------------------------------------------------------------------
45 
TwoRefCounts(const void * p,bool strong)46 TwoRefCounts::TwoRefCounts( const void * p, bool strong )
47     : m_counts( NULL )
48 {
49     void * temp = SmallObject<>::operator new(
50         sizeof(Loki::Private::TwoRefCountInfo) );
51 #ifdef DO_EXTRA_LOKI_TESTS
52     assert( temp != 0 );
53 #endif
54     void * p2 = const_cast< void * >( p );
55     m_counts = new ( temp ) Loki::Private::TwoRefCountInfo( p2, strong );
56 }
57 
58 // ----------------------------------------------------------------------------
59 
Increment(bool strong)60 void TwoRefCounts::Increment( bool strong )
61 {
62     if ( strong )
63     {
64         m_counts->IncStrongCount();
65     }
66     else
67     {
68         m_counts->IncWeakCount();
69     }
70 }
71 
72 // ----------------------------------------------------------------------------
73 
Decrement(bool strong)74 bool TwoRefCounts::Decrement( bool strong )
75 {
76     if ( strong )
77     {
78         m_counts->DecStrongCount();
79     }
80     else
81     {
82         m_counts->DecWeakCount();
83     }
84     return !m_counts->HasStrongPointer();
85 }
86 
87 // ----------------------------------------------------------------------------
88 
Swap(TwoRefCounts & rhs)89 void TwoRefCounts::Swap( TwoRefCounts & rhs )
90 {
91     std::swap( m_counts, rhs.m_counts );
92 }
93 
94 // ----------------------------------------------------------------------------
95 
ZapPointer(void)96 void TwoRefCounts::ZapPointer( void )
97 {
98 #ifdef DO_EXTRA_LOKI_TESTS
99     assert( !m_counts->HasStrongPointer() );
100 #endif
101     if ( m_counts->HasWeakPointer() )
102     {
103         m_counts->ZapPointer();
104     }
105     else
106     {
107         SmallObject<>::operator delete ( m_counts,
108             sizeof(Loki::Private::TwoRefCountInfo) );
109         m_counts = NULL;
110     }
111 }
112 
113 
114 // ----------------------------------------------------------------------------
115 
TwoRefLinks(const void * p,bool strong)116 TwoRefLinks::TwoRefLinks( const void * p, bool strong )
117     : m_pointer( const_cast< void * >( p ) )
118     , m_strong( strong )
119 {
120     m_prev = m_next = this;
121 #ifdef DO_EXTRA_LOKI_TESTS
122     assert( CountPrevCycle( this ) == CountNextCycle( this ) );
123 #endif
124 }
125 
126 // ----------------------------------------------------------------------------
127 
TwoRefLinks(const TwoRefLinks & rhs,bool strong)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 )
132     , m_strong( strong )
133 {
134     m_prev->m_next = this;
135     m_next->m_prev = this;
136 
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() );
145 #endif
146 }
147 
148 // ----------------------------------------------------------------------------
149 
SetPointer(void * p)150 void TwoRefLinks::SetPointer( void * p )
151 {
152     TwoRefLinks * node = m_prev;
153     if ( ( this == node ) || ( 0 == node ) )
154         return;
155 
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() );
161 #endif
162 
163     while ( node != this )
164     {
165         node->m_pointer = p;
166         node = node->m_next;
167     }
168     m_pointer = node;
169 
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() );
175 #endif
176 }
177 
178 // ----------------------------------------------------------------------------
179 
Release(bool strong)180 bool TwoRefLinks::Release( bool strong )
181 {
182 
183     (void)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() );
190 #endif
191 
192     if ( NULL == m_next )
193     {
194 #ifdef DO_EXTRA_LOKI_TESTS
195         assert( NULL == m_prev );
196 #endif
197         // Return false so it does not try to destroy shared object
198         // more than once.
199         return false;
200     }
201     else if (m_next == this)
202     {
203 #ifdef DO_EXTRA_LOKI_TESTS
204         assert(m_prev == this);
205 #endif
206         // Set these to NULL to prevent re-entrancy.
207         m_prev = NULL;
208         m_next = NULL;
209         // Last one in the cycle has to release the pointer.
210         return true;
211     }
212 
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 ) );
218 #endif
219 
220     // If a single node is strong, then return false so it won't release.
221     if ( HasStrongPointer() )
222     {
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;
226         return false;
227     }
228 
229     return true;
230 }
231 
232 // ----------------------------------------------------------------------------
233 
ZapAllNodes(void)234 void TwoRefLinks::ZapAllNodes( void )
235 {
236     TwoRefLinks * p = m_prev;
237     if ( ( this == p ) || ( 0 == p ) )
238         return;
239 #ifdef DO_EXTRA_LOKI_TESTS
240     assert( AllNodesHaveSamePointer() );
241 #endif
242 
243     while ( p != this )
244     {
245         TwoRefLinks * p1 = p->m_prev;
246         p->m_pointer = 0;
247         p->m_next = p;
248         p->m_prev = p;
249         p = p1;
250     }
251     m_pointer = 0;
252 }
253 
254 // ----------------------------------------------------------------------------
255 
Swap(TwoRefLinks & rhs)256 void TwoRefLinks::Swap( TwoRefLinks & rhs )
257 {
258 
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() );
265 #endif
266 
267     std::swap( rhs.m_pointer, m_pointer );
268     if (m_next == this)
269     {
270 #ifdef DO_EXTRA_LOKI_TESTS
271         // This is in a cycle by itself.
272         assert(m_prev == this);
273 #endif
274         if (rhs.m_next == &rhs)
275         {
276 #ifdef DO_EXTRA_LOKI_TESTS
277             assert(rhs.m_prev == &rhs);
278 #endif
279             // both are in 1-node cycles - thus there is nothing to do.
280             return;
281         }
282         m_prev = rhs.m_prev;
283         m_next = rhs.m_next;
284         m_prev->m_next = m_next->m_prev = this;
285         rhs.m_next = rhs.m_prev = &rhs;
286         return;
287     }
288     if (rhs.m_next == &rhs)
289     {
290 #ifdef DO_EXTRA_LOKI_TESTS
291         // rhs is in a cycle by itself.
292         assert( rhs.m_prev == &rhs );
293 #endif
294         rhs.m_prev = m_prev;
295         rhs.m_next = m_next;
296         m_prev->m_next = m_next->m_prev = &rhs;
297         m_next = m_prev = this;
298         return;
299     }
300     if (m_next == &rhs ) // rhs is next neighbour
301     {
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);
308     }
309     else if ( m_prev == &rhs ) // rhs is prev neighbor
310     {
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 );
317     }
318     else // not neighhbors
319     {
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);
324     }
325 
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() );
337 #endif
338 
339 }
340 
341 // ----------------------------------------------------------------------------
342 
AllNodesHaveSamePointer(void) const343 bool TwoRefLinks::AllNodesHaveSamePointer( void ) const
344 {
345     const TwoRefLinks * next = m_next;
346     if ( NULL == next )
347         return true;
348     do
349     {
350         if ( next->m_pointer != m_pointer )
351             return false;
352         next = next->m_next;
353     } while ( next != this );
354     return true;
355 }
356 
357 // ----------------------------------------------------------------------------
358 
CountPrevCycle(const TwoRefLinks * pThis)359 unsigned int TwoRefLinks::CountPrevCycle( const TwoRefLinks * pThis )
360 {
361     if ( NULL == pThis )
362         return 0;
363     const TwoRefLinks * p = pThis->m_prev;
364     if ( NULL == p )
365         return 0;
366     if ( pThis == p )
367         return 1;
368 
369     unsigned int count = 1;
370     do
371     {
372         p = p->m_prev;
373         ++count;
374     } while ( p != pThis );
375 
376     return count;
377 }
378 
379 // ----------------------------------------------------------------------------
380 
CountNextCycle(const TwoRefLinks * pThis)381 unsigned int TwoRefLinks::CountNextCycle( const TwoRefLinks * pThis )
382 {
383     if ( NULL == pThis )
384         return 0;
385     const TwoRefLinks * p = pThis->m_next;
386     if ( NULL == p )
387         return 0;
388     if ( pThis == p )
389         return 1;
390 
391     unsigned int count = 1;
392     while ( p != pThis )
393     {
394         p = p->m_next;
395         ++count;
396     }
397 
398     return count;
399 }
400 
401 // ----------------------------------------------------------------------------
402 
HasPrevNode(const TwoRefLinks * p) const403 bool TwoRefLinks::HasPrevNode( const TwoRefLinks * p ) const
404 {
405     if ( this == p )
406         return true;
407     const TwoRefLinks * prev = m_prev;
408     if ( NULL == prev )
409         return false;
410     while ( prev != this )
411     {
412         if ( p == prev )
413             return true;
414         prev = prev->m_prev;
415     }
416     return false;
417 }
418 
419 // ----------------------------------------------------------------------------
420 
HasNextNode(const TwoRefLinks * p) const421 bool TwoRefLinks::HasNextNode( const TwoRefLinks * p ) const
422 {
423     if ( this == p )
424         return true;
425     const TwoRefLinks * next = m_next;
426     if ( NULL == next )
427         return false;
428     while ( next != this )
429     {
430         if ( p == next )
431             return true;
432         next = next->m_next;
433     }
434     return false;
435 }
436 
437 // ----------------------------------------------------------------------------
438 
HasStrongPointer(void) const439 bool TwoRefLinks::HasStrongPointer( void ) const
440 {
441     const TwoRefLinks * next = m_next;
442     if ( NULL == next )
443         return false;
444     while ( next != this )
445     {
446         if ( next->m_strong )
447             return true;
448         next = next->m_next;
449     }
450     return false;
451 }
452 
453 // ----------------------------------------------------------------------------
454 
Merge(TwoRefLinks & rhs)455 bool TwoRefLinks::Merge( TwoRefLinks & rhs )
456 {
457 
458     if ( NULL == m_next )
459     {
460 #ifdef DO_EXTRA_LOKI_TESTS
461         assert( NULL == m_prev );
462 #endif
463         return false;
464     }
465     TwoRefLinks * prhs = &rhs;
466     if ( prhs == this )
467         return true;
468     if ( NULL == prhs->m_next )
469     {
470 #ifdef DO_EXTRA_LOKI_TESTS
471         assert( NULL == prhs->m_prev );
472 #endif
473         return true;
474     }
475 
476 #ifdef DO_EXTRA_LOKI_TESTS
477     assert( CountPrevCycle( this ) == CountNextCycle( this ) );
478     assert( CountPrevCycle( prhs ) == CountNextCycle( prhs ) );
479 #endif
480     // If rhs node is already in this cycle, then no need to merge.
481     if ( HasPrevNode( &rhs ) )
482     {
483 #ifdef DO_EXTRA_LOKI_TESTS
484         assert( HasNextNode( &rhs ) );
485 #endif
486         return true;
487     }
488 
489     if ( prhs == prhs->m_next )
490     {
491         /// rhs is in a cycle with 1 node.
492 #ifdef DO_EXTRA_LOKI_TESTS
493         assert( prhs->m_prev == prhs );
494 #endif
495         prhs->m_prev = m_prev;
496         prhs->m_next = this;
497         m_prev->m_next = prhs;
498         m_prev = prhs;
499     }
500     else if ( this == m_next )
501     {
502         /// this is in a cycle with 1 node.
503 #ifdef DO_EXTRA_LOKI_TESTS
504         assert( m_prev == this );
505 #endif
506         m_prev = prhs->m_prev;
507         m_next = prhs;
508         prhs->m_prev->m_next = this;
509         prhs->m_prev = this;
510     }
511     else
512     {
513         m_next->m_prev = prhs->m_prev;
514         prhs->m_prev->m_next = m_prev;
515         m_next = prhs;
516         prhs->m_prev = this;
517     }
518 
519 
520 #ifdef DO_EXTRA_LOKI_TESTS
521     assert( CountPrevCycle( this ) == CountNextCycle( this ) );
522 #endif
523 
524     return true;
525 }
526 
527 // ----------------------------------------------------------------------------
528 
529 } // end namespace Loki
530 
531