SmartPtr.cpp

00001 
00002 // The Loki Library
00003 // Copyright (c) 2001 by Andrei Alexandrescu
00004 // Copyright (c) 2006 Richard Sposato
00005 // This code accompanies the book:
00006 // Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design 
00007 //     Patterns Applied". Copyright (c) 2001. Addison-Wesley.
00008 // Permission to use, copy, modify, distribute and sell this software for any 
00009 //     purpose is hereby granted without fee, provided that the above  copyright 
00010 //     notice appear in all copies and that both that copyright notice and this 
00011 //     permission notice appear in supporting documentation.
00012 // The author or Addison-Wesley Longman make no representations about the 
00013 //     suitability of this software for any purpose. It is provided "as is" 
00014 //     without express or implied warranty.
00016 
00017 // $Id: SmartPtr.cpp 756 2006-10-17 20:05:42Z syntheticpp $
00018 
00019 
00020 #include <loki/SmartPtr.h>
00021 
00022 #include <cassert>
00023 
00024 //#define DO_EXTRA_LOKI_TESTS
00025 #ifdef DO_EXTRA_LOKI_TESTS
00026     #include <iostream>
00027 #endif
00028 
00029 
00030 // ----------------------------------------------------------------------------
00031 
00032 namespace Loki
00033 {
00034 
00035 namespace Private
00036 {
00037 
00038 // ----------------------------------------------------------------------------
00039 
00040 RefLinkedBase::RefLinkedBase(const RefLinkedBase& rhs) 
00041 {
00042     prev_ = &rhs;
00043     next_ = rhs.next_;
00044     prev_->next_ = this;
00045     next_->prev_ = this;
00046 
00047 #ifdef DO_EXTRA_LOKI_TESTS
00048     assert( prev_->HasPrevNode( this ) );
00049     assert( next_->HasNextNode( this ) );
00050     assert( CountPrevCycle( this ) == CountNextCycle( this ) );
00051 #endif
00052 }
00053 
00054 // ----------------------------------------------------------------------------
00055 
00056 bool RefLinkedBase::Release()
00057 {
00058 
00059 #ifdef DO_EXTRA_LOKI_TESTS
00060     assert( prev_->HasPrevNode( this ) );
00061     assert( next_->HasNextNode( this ) );
00062     assert( CountPrevCycle( this ) == CountNextCycle( this ) );
00063 #endif
00064 
00065     if ( NULL == next_ )
00066     {
00067         assert( NULL == prev_ );
00068         // Return false so it does not try to destroy shared object
00069         // more than once.
00070         return false;
00071     }
00072     else if (next_ == this)
00073     {   
00074         assert(prev_ == this);
00075         // Set these to NULL to prevent re-entrancy.
00076         prev_ = NULL;
00077         next_ = NULL;
00078         return true;
00079     }
00080 
00081 #ifdef DO_EXTRA_LOKI_TESTS
00082     assert( this != prev_ );
00083     assert( NULL != prev_ );
00084     assert( prev_->HasPrevNode( this ) );
00085     assert( next_->HasNextNode( this ) );
00086 #endif
00087 
00088     prev_->next_ = next_;
00089     next_->prev_ = prev_;
00090 
00091 #ifdef DO_EXTRA_LOKI_TESTS
00092     next_ = this;
00093     prev_ = this;
00094     assert( 1 == CountNextCycle( this ) );
00095     assert( 1 == CountPrevCycle( this ) );
00096 #endif
00097 
00098     return false;
00099 }
00100 
00101 // ----------------------------------------------------------------------------
00102 
00103 void RefLinkedBase::Swap(RefLinkedBase& rhs)
00104 {
00105 
00106 #ifdef DO_EXTRA_LOKI_TESTS
00107     assert( prev_->HasPrevNode( this ) );
00108     assert( next_->HasNextNode( this ) );
00109     assert( CountPrevCycle( this ) == CountNextCycle( this ) );
00110 #endif
00111 
00112     if (next_ == this)
00113     {
00114         assert(prev_ == this);
00115         if (rhs.next_ == &rhs)
00116         {
00117             assert(rhs.prev_ == &rhs);
00118             // both lists are empty, nothing 2 do
00119             return;
00120         }
00121         prev_ = rhs.prev_;
00122         next_ = rhs.next_;
00123         prev_->next_ = next_->prev_ = this;
00124         rhs.next_ = rhs.prev_ = &rhs;
00125         return;
00126     }
00127     if (rhs.next_ == &rhs)
00128     {
00129         rhs.Swap(*this);
00130         return;
00131     }
00132     if (next_ == &rhs ) // rhs is next neighbour
00133     {
00134         if ( prev_ == &rhs )
00135             return;  // cycle of 2 pointers - no need to swap.
00136         std::swap(prev_, next_);
00137         std::swap(rhs.prev_, rhs.next_);
00138         std::swap(rhs.prev_, next_);
00139         std::swap(rhs.prev_->next_,next_->prev_);
00140     }
00141     else if ( prev_ == &rhs ) // rhs is prev neighbor
00142     {
00143         if ( next_ == &rhs )
00144             return;  // cycle of 2 pointers - no need to swap.
00145         std::swap( prev_, next_ );
00146         std::swap( rhs.next_, rhs.prev_ );
00147         std::swap( rhs.next_, prev_ );
00148         std::swap( rhs.next_->prev_, prev_->next_ );
00149     }
00150     else // not neighhbors
00151     {
00152         std::swap(prev_, rhs.prev_);
00153         std::swap(next_, rhs.next_);
00154         std::swap(prev_->next_, rhs.prev_->next_);
00155         std::swap(next_->prev_, rhs.next_->prev_);
00156     }
00157 
00158 #ifdef DO_EXTRA_LOKI_TESTS
00159     assert( next_ == this ? prev_ == this : prev_ != this);
00160     assert( prev_ == this ? next_ == this : next_ != this);
00161     assert( prev_->HasPrevNode( this ) );
00162     assert( next_->HasNextNode( this ) );
00163     assert( CountPrevCycle( this ) == CountNextCycle( this ) );
00164     assert( rhs.prev_->HasPrevNode( &rhs ) );
00165     assert( rhs.next_->HasNextNode( &rhs ) );
00166     assert( CountPrevCycle( &rhs ) == CountNextCycle( &rhs ) );
00167 #endif
00168 
00169 }
00170 
00171 // ----------------------------------------------------------------------------
00172 
00173 unsigned int RefLinkedBase::CountPrevCycle( const RefLinkedBase * pThis )
00174 {
00175     if ( NULL == pThis )
00176         return 0;
00177     const RefLinkedBase * p = pThis->prev_;
00178     if ( NULL == p )
00179         return 0;
00180     if ( pThis == p )
00181         return 1;
00182 
00183     unsigned int count = 1;
00184     do
00185     {
00186         p = p->prev_;
00187         ++count;
00188     } while ( p != pThis );
00189 
00190     return count;
00191 }
00192 
00193 // ----------------------------------------------------------------------------
00194 
00195 unsigned int RefLinkedBase::CountNextCycle( const RefLinkedBase * pThis )
00196 {
00197     if ( NULL == pThis )
00198         return 0;
00199     const RefLinkedBase * p = pThis->next_;
00200     if ( NULL == p )
00201         return 0;
00202     if ( pThis == p )
00203         return 1;
00204 
00205     unsigned int count = 1;
00206     while ( p != pThis )
00207     {
00208         p = p->next_;
00209         ++count;
00210     }
00211 
00212     return count;
00213 }
00214 
00215 // ----------------------------------------------------------------------------
00216 
00217 bool RefLinkedBase::HasPrevNode( const RefLinkedBase * p ) const
00218 {
00219     if ( this == p )
00220         return true;
00221     const RefLinkedBase * prev = prev_;
00222     if ( NULL == prev )
00223         return false;
00224     while ( prev != this )
00225     {
00226         if ( p == prev )
00227             return true;
00228         prev = prev->prev_;
00229     }
00230     return false;
00231 }
00232 
00233 // ----------------------------------------------------------------------------
00234 
00235 bool RefLinkedBase::HasNextNode( const RefLinkedBase * p ) const
00236 {
00237     if ( this == p )
00238         return true;
00239     const RefLinkedBase * next = next_;
00240     if ( NULL == next )
00241         return false;
00242     while ( next != this )
00243     {
00244         if ( p == next )
00245             return true;
00246         next = next->next_;
00247     }
00248     return false;
00249 }
00250 
00251 // ----------------------------------------------------------------------------
00252 
00253 bool RefLinkedBase::Merge( RefLinkedBase & rhs )
00254 {
00255 
00256     if ( NULL == next_ )
00257     {
00258         assert( NULL == prev_ );
00259         return false;
00260     }
00261     RefLinkedBase * prhs = &rhs;
00262     if ( prhs == this )
00263         return true;
00264     if ( NULL == prhs->next_ )
00265     {
00266         assert( NULL == prhs->prev_ );
00267         return true;
00268     }
00269 
00270     assert( CountPrevCycle( this ) == CountNextCycle( this ) );
00271     assert( CountPrevCycle( prhs ) == CountNextCycle( prhs ) );
00272     // If rhs node is already in this cycle, then no need to merge.
00273     if ( HasPrevNode( &rhs ) )
00274     {
00275         assert( HasNextNode( &rhs ) );
00276         return true;
00277     }
00278 
00279     if ( prhs == prhs->next_ )
00280     {
00282         assert( prhs->prev_ == prhs );
00283         prhs->prev_ = prev_;
00284         prhs->next_ = this;
00285         prev_->next_ = prhs;
00286         prev_ = prhs;
00287     }
00288     else if ( this == next_ )
00289     {
00291         assert( prev_ == this );
00292         prev_ = prhs->prev_;
00293         next_ = prhs;
00294         prhs->prev_->next_ = this;
00295         prhs->prev_ = this;
00296     }
00297     else
00298     {
00299         next_->prev_ = prhs->prev_;
00300         prhs->prev_->next_ = prev_;
00301         next_ = prhs;
00302         prhs->prev_ = this;
00303     }
00304 
00305     assert( CountPrevCycle( this ) == CountNextCycle( this ) );
00306     return true;
00307 }
00308 
00309 // ----------------------------------------------------------------------------
00310 
00311 } // end namespace Private
00312 
00313 } // end namespace Loki
00314 

Generated on Sun Feb 25 16:52:27 2007 for Loki by  doxygen 1.5.1-p1