1 ////////////////////////////////////////////////////////////////////////////////
3 // Copyright (c) 2001 by Andrei Alexandrescu
4 // Copyright (c) 2006 Richard Sposato
5 // This code accompanies the book:
6 // Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design
7 // Patterns Applied". Copyright (c) 2001. Addison-Wesley.
8 // Permission to use, copy, modify, distribute and sell this software for any
9 // purpose is hereby granted without fee, provided that the above copyright
10 // notice appear in all copies and that both that copyright notice and this
11 // permission notice appear in supporting documentation.
12 // The author or Addison-Wesley Longman make no representations about the
13 // suitability of this software for any purpose. It is provided "as is"
14 // without express or implied warranty.
15 ////////////////////////////////////////////////////////////////////////////////
17 // $Id: SmartPtr.cpp 756 2006-10-17 20:05:42Z syntheticpp $
20 #include <loki/SmartPtr.h>
24 //#define DO_EXTRA_LOKI_TESTS
25 #ifdef DO_EXTRA_LOKI_TESTS
30 // ----------------------------------------------------------------------------
38 // ----------------------------------------------------------------------------
40 RefLinkedBase::RefLinkedBase(const RefLinkedBase &rhs)
47 #ifdef DO_EXTRA_LOKI_TESTS
48 assert( prev_->HasPrevNode( this ) );
49 assert( next_->HasNextNode( this ) );
50 assert( CountPrevCycle( this ) == CountNextCycle( this ) );
54 // ----------------------------------------------------------------------------
56 bool RefLinkedBase::Release()
59 #ifdef DO_EXTRA_LOKI_TESTS
60 assert( prev_->HasPrevNode( this ) );
61 assert( next_->HasNextNode( this ) );
62 assert( CountPrevCycle( this ) == CountNextCycle( this ) );
67 assert( NULL == prev_ );
68 // Return false so it does not try to destroy shared object
72 else if (next_ == this)
74 assert(prev_ == this);
75 // Set these to NULL to prevent re-entrancy.
81 #ifdef DO_EXTRA_LOKI_TESTS
82 assert( this != prev_ );
83 assert( NULL != prev_ );
84 assert( prev_->HasPrevNode( this ) );
85 assert( next_->HasNextNode( this ) );
91 #ifdef DO_EXTRA_LOKI_TESTS
94 assert( 1 == CountNextCycle( this ) );
95 assert( 1 == CountPrevCycle( this ) );
101 // ----------------------------------------------------------------------------
103 void RefLinkedBase::Swap(RefLinkedBase &rhs)
106 #ifdef DO_EXTRA_LOKI_TESTS
107 assert( prev_->HasPrevNode( this ) );
108 assert( next_->HasNextNode( this ) );
109 assert( CountPrevCycle( this ) == CountNextCycle( this ) );
114 assert(prev_ == this);
115 if (rhs.next_ == &rhs)
117 assert(rhs.prev_ == &rhs);
118 // both lists are empty, nothing 2 do
123 prev_->next_ = next_->prev_ = this;
124 rhs.next_ = rhs.prev_ = &rhs;
127 if (rhs.next_ == &rhs)
132 if (next_ == &rhs ) // rhs is next neighbour
135 return; // cycle of 2 pointers - no need to swap.
136 std::swap(prev_, next_);
137 std::swap(rhs.prev_, rhs.next_);
138 std::swap(rhs.prev_, next_);
139 std::swap(rhs.prev_->next_,next_->prev_);
141 else if ( prev_ == &rhs ) // rhs is prev neighbor
144 return; // cycle of 2 pointers - no need to swap.
145 std::swap( prev_, next_ );
146 std::swap( rhs.next_, rhs.prev_ );
147 std::swap( rhs.next_, prev_ );
148 std::swap( rhs.next_->prev_, prev_->next_ );
150 else // not neighhbors
152 std::swap(prev_, rhs.prev_);
153 std::swap(next_, rhs.next_);
154 std::swap(prev_->next_, rhs.prev_->next_);
155 std::swap(next_->prev_, rhs.next_->prev_);
158 #ifdef DO_EXTRA_LOKI_TESTS
159 assert( next_ == this ? prev_ == this : prev_ != this);
160 assert( prev_ == this ? next_ == this : next_ != this);
161 assert( prev_->HasPrevNode( this ) );
162 assert( next_->HasNextNode( this ) );
163 assert( CountPrevCycle( this ) == CountNextCycle( this ) );
164 assert( rhs.prev_->HasPrevNode( &rhs ) );
165 assert( rhs.next_->HasNextNode( &rhs ) );
166 assert( CountPrevCycle( &rhs ) == CountNextCycle( &rhs ) );
171 // ----------------------------------------------------------------------------
173 unsigned int RefLinkedBase::CountPrevCycle( const RefLinkedBase *pThis )
177 const RefLinkedBase *p = pThis->prev_;
183 unsigned int count = 1;
189 while ( p != pThis );
194 // ----------------------------------------------------------------------------
196 unsigned int RefLinkedBase::CountNextCycle( const RefLinkedBase *pThis )
200 const RefLinkedBase *p = pThis->next_;
206 unsigned int count = 1;
216 // ----------------------------------------------------------------------------
218 bool RefLinkedBase::HasPrevNode( const RefLinkedBase *p ) const
222 const RefLinkedBase *prev = prev_;
225 while ( prev != this )
234 // ----------------------------------------------------------------------------
236 bool RefLinkedBase::HasNextNode( const RefLinkedBase *p ) const
240 const RefLinkedBase *next = next_;
243 while ( next != this )
252 // ----------------------------------------------------------------------------
254 bool RefLinkedBase::Merge( RefLinkedBase &rhs )
259 assert( NULL == prev_ );
262 RefLinkedBase *prhs = &rhs;
265 if ( NULL == prhs->next_ )
267 assert( NULL == prhs->prev_ );
271 assert( CountPrevCycle( this ) == CountNextCycle( this ) );
272 assert( CountPrevCycle( prhs ) == CountNextCycle( prhs ) );
273 // If rhs node is already in this cycle, then no need to merge.
274 if ( HasPrevNode( &rhs ) )
276 assert( HasNextNode( &rhs ) );
280 if ( prhs == prhs->next_ )
282 /// rhs is in a cycle with 1 node.
283 assert( prhs->prev_ == prhs );
289 else if ( this == next_ )
291 /// this is in a cycle with 1 node.
292 assert( prev_ == this );
295 prhs->prev_->next_ = this;
300 next_->prev_ = prhs->prev_;
301 prhs->prev_->next_ = prev_;
306 assert( CountPrevCycle( this ) == CountNextCycle( this ) );
310 // ----------------------------------------------------------------------------
312 } // end namespace Private
314 } // end namespace Loki