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