]> git.cworth.org Git - vogl/blob - src/extlib/loki/src/StrongPtr.cpp
Initial vogl checkin
[vogl] / src / extlib / loki / src / StrongPtr.cpp
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
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
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
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
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
89 void TwoRefCounts::Swap( TwoRefCounts &rhs )
90 {
91         std::swap( m_counts, rhs.m_counts );
92 }
93
94 // ----------------------------------------------------------------------------
95
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
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
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
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
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
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
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
343 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         }
354         while ( next != this );
355         return true;
356 }
357
358 // ----------------------------------------------------------------------------
359
360 unsigned int TwoRefLinks::CountPrevCycle( const TwoRefLinks *pThis )
361 {
362         if ( NULL == pThis )
363                 return 0;
364         const TwoRefLinks *p = pThis->m_prev;
365         if ( NULL == p )
366                 return 0;
367         if ( pThis == p )
368                 return 1;
369
370         unsigned int count = 1;
371         do
372         {
373                 p = p->m_prev;
374                 ++count;
375         }
376         while ( p != pThis );
377
378         return count;
379 }
380
381 // ----------------------------------------------------------------------------
382
383 unsigned int TwoRefLinks::CountNextCycle( const TwoRefLinks *pThis )
384 {
385         if ( NULL == pThis )
386                 return 0;
387         const TwoRefLinks *p = pThis->m_next;
388         if ( NULL == p )
389                 return 0;
390         if ( pThis == p )
391                 return 1;
392
393         unsigned int count = 1;
394         while ( p != pThis )
395         {
396                 p = p->m_next;
397                 ++count;
398         }
399
400         return count;
401 }
402
403 // ----------------------------------------------------------------------------
404
405 bool TwoRefLinks::HasPrevNode( const TwoRefLinks *p ) const
406 {
407         if ( this == p )
408                 return true;
409         const TwoRefLinks *prev = m_prev;
410         if ( NULL == prev )
411                 return false;
412         while ( prev != this )
413         {
414                 if ( p == prev )
415                         return true;
416                 prev = prev->m_prev;
417         }
418         return false;
419 }
420
421 // ----------------------------------------------------------------------------
422
423 bool TwoRefLinks::HasNextNode( const TwoRefLinks *p ) const
424 {
425         if ( this == p )
426                 return true;
427         const TwoRefLinks *next = m_next;
428         if ( NULL == next )
429                 return false;
430         while ( next != this )
431         {
432                 if ( p == next )
433                         return true;
434                 next = next->m_next;
435         }
436         return false;
437 }
438
439 // ----------------------------------------------------------------------------
440
441 bool TwoRefLinks::HasStrongPointer( void ) const
442 {
443         const TwoRefLinks *next = m_next;
444         if ( NULL == next )
445                 return false;
446         while ( next != this )
447         {
448                 if ( next->m_strong )
449                         return true;
450                 next = next->m_next;
451         }
452         return false;
453 }
454
455 // ----------------------------------------------------------------------------
456
457 bool TwoRefLinks::Merge( TwoRefLinks &rhs )
458 {
459
460         if ( NULL == m_next )
461         {
462 #ifdef DO_EXTRA_LOKI_TESTS
463                 assert( NULL == m_prev );
464 #endif
465                 return false;
466         }
467         TwoRefLinks *prhs = &rhs;
468         if ( prhs == this )
469                 return true;
470         if ( NULL == prhs->m_next )
471         {
472 #ifdef DO_EXTRA_LOKI_TESTS
473                 assert( NULL == prhs->m_prev );
474 #endif
475                 return true;
476         }
477
478 #ifdef DO_EXTRA_LOKI_TESTS
479         assert( CountPrevCycle( this ) == CountNextCycle( this ) );
480         assert( CountPrevCycle( prhs ) == CountNextCycle( prhs ) );
481 #endif
482         // If rhs node is already in this cycle, then no need to merge.
483         if ( HasPrevNode( &rhs ) )
484         {
485 #ifdef DO_EXTRA_LOKI_TESTS
486                 assert( HasNextNode( &rhs ) );
487 #endif
488                 return true;
489         }
490
491         if ( prhs == prhs->m_next )
492         {
493                 /// rhs is in a cycle with 1 node.
494 #ifdef DO_EXTRA_LOKI_TESTS
495                 assert( prhs->m_prev == prhs );
496 #endif
497                 prhs->m_prev = m_prev;
498                 prhs->m_next = this;
499                 m_prev->m_next = prhs;
500                 m_prev = prhs;
501         }
502         else if ( this == m_next )
503         {
504                 /// this is in a cycle with 1 node.
505 #ifdef DO_EXTRA_LOKI_TESTS
506                 assert( m_prev == this );
507 #endif
508                 m_prev = prhs->m_prev;
509                 m_next = prhs;
510                 prhs->m_prev->m_next = this;
511                 prhs->m_prev = this;
512         }
513         else
514         {
515                 m_next->m_prev = prhs->m_prev;
516                 prhs->m_prev->m_next = m_prev;
517                 m_next = prhs;
518                 prhs->m_prev = this;
519         }
520
521
522 #ifdef DO_EXTRA_LOKI_TESTS
523         assert( CountPrevCycle( this ) == CountNextCycle( this ) );
524 #endif
525
526         return true;
527 }
528
529 // ----------------------------------------------------------------------------
530
531 } // end namespace Loki
532