]> git.cworth.org Git - vogl/blob - src/extlib/loki/src/SmartPtr.cpp
Initial vogl checkin
[vogl] / src / extlib / loki / src / SmartPtr.cpp
1 ////////////////////////////////////////////////////////////////////////////////
2 // The Loki Library
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 ////////////////////////////////////////////////////////////////////////////////
16
17 // $Id: SmartPtr.cpp 756 2006-10-17 20:05:42Z syntheticpp $
18
19
20 #include <loki/SmartPtr.h>
21
22 #include <cassert>
23
24 //#define DO_EXTRA_LOKI_TESTS
25 #ifdef DO_EXTRA_LOKI_TESTS
26 #include <iostream>
27 #endif
28
29
30 // ----------------------------------------------------------------------------
31
32 namespace Loki
33 {
34
35 namespace Private
36 {
37
38 // ----------------------------------------------------------------------------
39
40 RefLinkedBase::RefLinkedBase(const RefLinkedBase &rhs)
41 {
42         prev_ = &rhs;
43         next_ = rhs.next_;
44         prev_->next_ = this;
45         next_->prev_ = this;
46
47 #ifdef DO_EXTRA_LOKI_TESTS
48         assert( prev_->HasPrevNode( this ) );
49         assert( next_->HasNextNode( this ) );
50         assert( CountPrevCycle( this ) == CountNextCycle( this ) );
51 #endif
52 }
53
54 // ----------------------------------------------------------------------------
55
56 bool RefLinkedBase::Release()
57 {
58
59 #ifdef DO_EXTRA_LOKI_TESTS
60         assert( prev_->HasPrevNode( this ) );
61         assert( next_->HasNextNode( this ) );
62         assert( CountPrevCycle( this ) == CountNextCycle( this ) );
63 #endif
64
65         if ( NULL == next_ )
66         {
67                 assert( NULL == prev_ );
68                 // Return false so it does not try to destroy shared object
69                 // more than once.
70                 return false;
71         }
72         else if (next_ == this)
73         {
74                 assert(prev_ == this);
75                 // Set these to NULL to prevent re-entrancy.
76                 prev_ = NULL;
77                 next_ = NULL;
78                 return true;
79         }
80
81 #ifdef DO_EXTRA_LOKI_TESTS
82         assert( this != prev_ );
83         assert( NULL != prev_ );
84         assert( prev_->HasPrevNode( this ) );
85         assert( next_->HasNextNode( this ) );
86 #endif
87
88         prev_->next_ = next_;
89         next_->prev_ = prev_;
90
91 #ifdef DO_EXTRA_LOKI_TESTS
92         next_ = this;
93         prev_ = this;
94         assert( 1 == CountNextCycle( this ) );
95         assert( 1 == CountPrevCycle( this ) );
96 #endif
97
98         return false;
99 }
100
101 // ----------------------------------------------------------------------------
102
103 void RefLinkedBase::Swap(RefLinkedBase &rhs)
104 {
105
106 #ifdef DO_EXTRA_LOKI_TESTS
107         assert( prev_->HasPrevNode( this ) );
108         assert( next_->HasNextNode( this ) );
109         assert( CountPrevCycle( this ) == CountNextCycle( this ) );
110 #endif
111
112         if (next_ == this)
113         {
114                 assert(prev_ == this);
115                 if (rhs.next_ == &rhs)
116                 {
117                         assert(rhs.prev_ == &rhs);
118                         // both lists are empty, nothing 2 do
119                         return;
120                 }
121                 prev_ = rhs.prev_;
122                 next_ = rhs.next_;
123                 prev_->next_ = next_->prev_ = this;
124                 rhs.next_ = rhs.prev_ = &rhs;
125                 return;
126         }
127         if (rhs.next_ == &rhs)
128         {
129                 rhs.Swap(*this);
130                 return;
131         }
132         if (next_ == &rhs ) // rhs is next neighbour
133         {
134                 if ( prev_ == &rhs )
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_);
140         }
141         else if ( prev_ == &rhs ) // rhs is prev neighbor
142         {
143                 if ( next_ == &rhs )
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_ );
149         }
150         else // not neighhbors
151         {
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_);
156         }
157
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 ) );
167 #endif
168
169 }
170
171 // ----------------------------------------------------------------------------
172
173 unsigned int RefLinkedBase::CountPrevCycle( const RefLinkedBase *pThis )
174 {
175         if ( NULL == pThis )
176                 return 0;
177         const RefLinkedBase *p = pThis->prev_;
178         if ( NULL == p )
179                 return 0;
180         if ( pThis == p )
181                 return 1;
182
183         unsigned int count = 1;
184         do
185         {
186                 p = p->prev_;
187                 ++count;
188         }
189         while ( p != pThis );
190
191         return count;
192 }
193
194 // ----------------------------------------------------------------------------
195
196 unsigned int RefLinkedBase::CountNextCycle( const RefLinkedBase *pThis )
197 {
198         if ( NULL == pThis )
199                 return 0;
200         const RefLinkedBase *p = pThis->next_;
201         if ( NULL == p )
202                 return 0;
203         if ( pThis == p )
204                 return 1;
205
206         unsigned int count = 1;
207         while ( p != pThis )
208         {
209                 p = p->next_;
210                 ++count;
211         }
212
213         return count;
214 }
215
216 // ----------------------------------------------------------------------------
217
218 bool RefLinkedBase::HasPrevNode( const RefLinkedBase *p ) const
219 {
220         if ( this == p )
221                 return true;
222         const RefLinkedBase *prev = prev_;
223         if ( NULL == prev )
224                 return false;
225         while ( prev != this )
226         {
227                 if ( p == prev )
228                         return true;
229                 prev = prev->prev_;
230         }
231         return false;
232 }
233
234 // ----------------------------------------------------------------------------
235
236 bool RefLinkedBase::HasNextNode( const RefLinkedBase *p ) const
237 {
238         if ( this == p )
239                 return true;
240         const RefLinkedBase *next = next_;
241         if ( NULL == next )
242                 return false;
243         while ( next != this )
244         {
245                 if ( p == next )
246                         return true;
247                 next = next->next_;
248         }
249         return false;
250 }
251
252 // ----------------------------------------------------------------------------
253
254 bool RefLinkedBase::Merge( RefLinkedBase &rhs )
255 {
256
257         if ( NULL == next_ )
258         {
259                 assert( NULL == prev_ );
260                 return false;
261         }
262         RefLinkedBase *prhs = &rhs;
263         if ( prhs == this )
264                 return true;
265         if ( NULL == prhs->next_ )
266         {
267                 assert( NULL == prhs->prev_ );
268                 return true;
269         }
270
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 ) )
275         {
276                 assert( HasNextNode( &rhs ) );
277                 return true;
278         }
279
280         if ( prhs == prhs->next_ )
281         {
282                 /// rhs is in a cycle with 1 node.
283                 assert( prhs->prev_ == prhs );
284                 prhs->prev_ = prev_;
285                 prhs->next_ = this;
286                 prev_->next_ = prhs;
287                 prev_ = prhs;
288         }
289         else if ( this == next_ )
290         {
291                 /// this is in a cycle with 1 node.
292                 assert( prev_ == this );
293                 prev_ = prhs->prev_;
294                 next_ = prhs;
295                 prhs->prev_->next_ = this;
296                 prhs->prev_ = this;
297         }
298         else
299         {
300                 next_->prev_ = prhs->prev_;
301                 prhs->prev_->next_ = prev_;
302                 next_ = prhs;
303                 prhs->prev_ = this;
304         }
305
306         assert( CountPrevCycle( this ) == CountNextCycle( this ) );
307         return true;
308 }
309
310 // ----------------------------------------------------------------------------
311
312 } // end namespace Private
313
314 } // end namespace Loki
315