openModeller  Version 1.4.0
refcount.hh
Go to the documentation of this file.
00001 #ifndef _REFCOUNT_HH
00002 #define _REFCOUNT_HH
00003 
00004 #include <openmodeller/Log.hh>
00005 
00006 #undef DEBUG_MEMORY
00007 
00008 //
00009 // This is a very small templated TypeTraits class which really only
00010 // provides a convient way to strip const qualifiers.  It is needed
00011 // by the ReferenceCountedPointer<> template below to create
00012 // ReferenceCountedPointer< const T * >.  Without the PlainPointerType,
00013 // the underlying type would be const T* instead of the correct
00014 // T*.
00015 //
00016 template< typename T >
00017 class TypeTraits {
00018 private:
00019   template< class U > struct UnConst
00020   {
00021     typedef U* PointerType;
00022     typedef U* PlainPointerType;
00023     typedef U& ReferenceType;
00024     typedef U& PlainReferenceType;
00025   };
00026   template< class U > struct UnConst<const U> {
00027     typedef U const * PointerType;
00028     typedef U* PlainPointerType;
00029     typedef const U & ReferenceType;
00030     typedef U& PlainReferenceType;
00031   };
00032 public:
00033   typedef typename UnConst<T>::PointerType PointerType;
00034   typedef typename UnConst<T>::ReferenceType ReferenceType;
00035   typedef typename UnConst<T>::PlainPointerType PlainPointerType;
00036 };
00037 
00038 //
00039 // Declaration of ReferenceCountedObject.
00040 //
00041 // This class contains the _ref_count and is used to decorate
00042 // objects which ReferenceCountedPointer points to.
00043 // This is an intrusive reference count (you need to derive from
00044 // this class).  This mechanism has been chosen because
00045 // we have the source of the library and can change the code
00046 // to derive from this class, and it's space and runtime overhead
00047 // is minimal.
00048 //
00049 class dllexp ReferenceCountedObject
00050 {
00051 
00052   /* I'd like to get friendship to work here */
00053   /* Instead each derived class from this base needs
00054      To have it's container's class declared a friend */
00055   template< typename T >
00056   friend class ReferenceCountedPointer;
00057 
00058 protected:
00059   ReferenceCountedObject() :
00060     _ref_count(0)
00061   {}
00062 
00063   virtual inline ~ReferenceCountedObject() = 0;
00064 
00065 private:
00066 
00067   int _ref_count;
00068 
00069 };
00070 
00071 template< class T >
00072 class ReferenceCountedPointer {
00073 public:
00074 
00075   typedef typename TypeTraits<T>::PointerType PointerType;
00076   typedef typename TypeTraits<T>::ReferenceType ReferenceType;
00077   typedef typename TypeTraits<T>::PlainPointerType PlainPointerType;
00078 
00079   template< typename S >
00080   friend class ReferenceCountedPointer;
00081 
00082   //
00083   // Default constructor creates pointer to null.
00084   inline ReferenceCountedPointer( );
00085 
00086   //
00087   // implict conversion constructor from T*.
00088   // Provides for the following syntax
00089   // ReferenceCountedPointer<T> ptr = new T();
00090   // ... ReferenceCountedPoitner<T> ( new T() );
00091   //
00092   inline ReferenceCountedPointer( PointerType );
00093   //
00094   // Conversion from class S derived from T
00095   template< class S >
00096   inline ReferenceCountedPointer( S* );
00097 
00098   //
00099   // copy constructor.
00100   inline ReferenceCountedPointer( const ReferenceCountedPointer & );
00101   //
00102   // copy constructor from derived classes
00103   template< class S >
00104   inline ReferenceCountedPointer( const ReferenceCountedPointer<S> & );
00105 
00106   //
00107   // destructor
00108   inline virtual ~ReferenceCountedPointer();
00109 
00110   inline ReferenceType operator*() const;
00111   inline PointerType operator->() const;
00112 
00113   //
00114   // Assignment operator.
00115   inline ReferenceCountedPointer<T>& operator=( const ReferenceCountedPointer& );
00116   template< class S >
00117   inline ReferenceCountedPointer<T>& operator=( const ReferenceCountedPointer<S>& );
00118 
00119   //
00120   // Assignment from plain pointer classes.
00121   inline ReferenceCountedPointer<T>& operator=( PointerType& );
00122   template< class S >
00123   inline ReferenceCountedPointer<T>& operator=( S*& );
00124 
00125   // Two ways to test for NULL-ness.
00126   inline bool operator!() const;
00127   inline operator bool() const;
00128 
00129   // Need a member for swap since VC doesn't allow friend templates
00130   inline void swap( ReferenceCountedPointer<T>& rhs) {
00131     PlainPointerType tmp = this->_p;
00132     this->_p = rhs._p;
00133     rhs._p = tmp;
00134   }
00135 
00136 private:
00137   inline void releasePointer();
00138   inline void takePointer( PlainPointerType ptr );
00139 
00140   PlainPointerType _p;
00141 
00142 };
00143 
00144 template< class T >
00145 void
00146 swap( ReferenceCountedPointer<T>& lhs, ReferenceCountedPointer<T>& rhs ) {
00147   lhs.swap(rhs);
00148 }
00149 
00150 /*
00151  *
00152  * Implementation for ReferenceCountedPointer inlines
00153  *
00154  */
00155 template< class T >
00156 ReferenceCountedPointer<T>::ReferenceCountedPointer() :
00157   _p( 0 )
00158 {
00159 # if defined(DEBUG_MEMORY)
00160   Log::instance()->debug( "ReferenceCountedPointer<T>::ReferenceCountedPointer()\n");
00161 # endif
00162 }
00163 
00164 template< class T >
00165 ReferenceCountedPointer<T>::ReferenceCountedPointer( const ReferenceCountedPointer & rhs )
00166 {
00167 # if defined(DEBUG_MEMORY)
00168   Log::instance()->debug( "ReferenceCountedPointer<T>::ReferenceCountedPointer( const ReferenceCountedPointer & rhs )\n" );
00169 # endif
00170   takePointer( rhs._p );
00171 }
00172 
00173 template< class T >
00174 template< class S >
00175 ReferenceCountedPointer<T>::ReferenceCountedPointer( const ReferenceCountedPointer<S> & rhs )
00176 {
00177 # if defined(DEBUG_MEMORY)
00178   Log::instance()->debug( "ReferenceCountedPointer<T>::ReferenceCountedPointer( const ReferenceCountedPointer<S> & rhs )\n" );
00179 # endif
00180   takePointer( rhs._p );
00181 }
00182 
00183 template< class T >
00184 ReferenceCountedPointer<T>::ReferenceCountedPointer( PointerType rhs )
00185 {
00186 # if defined(DEBUG_MEMORY)
00187   Log::instance()->debug( "ReferenceCountedPointer<T>::ReferenceCountedPointer( T* rhs )\n" );
00188 # endif
00189   takePointer( rhs );
00190 }
00191 
00192 template< class T >
00193 template< class S >
00194 ReferenceCountedPointer<T>::ReferenceCountedPointer( S* rhs )
00195 {
00196 # if defined(DEBUG_MEMORY)
00197   Log::instance()->debug( "ReferenceCountedPointer<T>::ReferenceCountedPointer( S* rhs )\n" );
00198 # endif
00199   takePointer( rhs );
00200 }
00201 
00202 template< class T >
00203 ReferenceCountedPointer<T>::~ReferenceCountedPointer()
00204 {
00205 # if defined(DEBUG_MEMORY)
00206   Log::instance()->debug( "ReferenceCountedPointer<T>::~ReferenceCountedPointer()\n" );
00207 # endif
00208   releasePointer();
00209 }
00210 
00211 template< class T >
00212 ReferenceCountedPointer<T>& 
00213 ReferenceCountedPointer<T>::operator=( const ReferenceCountedPointer& rhs )
00214 {
00215 # if defined(DEBUG_MEMORY)
00216   Log::instance()->debug( "ReferenceCountedPointer<T>::operator=( const ReferenceCountedPointer<T>& rhs )\n" );
00217 # endif
00218   if ( this == &rhs )
00219     return *this;
00220 
00221   if ( this->_p == rhs._p )
00222     return *this;
00223 
00224   releasePointer();
00225   takePointer( rhs._p );
00226   return *this;
00227 }
00228 
00229 template< class T >
00230 template< class S >
00231 ReferenceCountedPointer<T>& 
00232 ReferenceCountedPointer<T>::operator=( const ReferenceCountedPointer<S>& rhs )
00233 {
00234 # if defined(DEBUG_MEMORY)
00235   Log::instance()->debug( "ReferenceCountedPointer<T>::operator=( const ReferenceCountedPointer<S>& rhs )\n" );
00236 # endif
00237   if ( this == &rhs )
00238     return *this;
00239 
00240   if ( this->_p == rhs._p )
00241     return *this;
00242 
00243   releasePointer();
00244   takePointer( rhs._p );
00245   return *this;
00246 }
00247 
00248 template< class T >
00249 ReferenceCountedPointer<T>& 
00250 ReferenceCountedPointer<T>::operator=( PointerType& rhs )
00251 {
00252 # if defined(DEBUG_MEMORY)
00253   Log::instance()->debug( "ReferenceCountedPointer<T>::operator=( T*& rhs )\n" );
00254 # endif
00255   if ( this->_p == rhs )
00256     return *this;
00257 
00258   releasePointer();
00259   takePointer( rhs );
00260   return *this;
00261 }
00262 
00263 template< class T >
00264 template< class S >
00265 ReferenceCountedPointer<T>& 
00266 ReferenceCountedPointer<T>::operator=( S*& rhs )
00267 {
00268 # if defined(DEBUG_MEMORY)
00269   Log::instance()->debug( "ReferenceCountedPointer<T>::operator=( S*& rhs )\n" );
00270 # endif
00271   if ( this->_p == rhs )
00272     return *this;
00273 
00274   releasePointer();
00275   takePointer( rhs );
00276   return *this;
00277 }
00278 
00279 template< class T >
00280 typename TypeTraits<T>::ReferenceType
00281 ReferenceCountedPointer<T>::operator*() const
00282 {
00283   return *_p;
00284 }
00285 
00286 template< class T >
00287 typename TypeTraits<T>::PointerType
00288 ReferenceCountedPointer<T>::operator->() const
00289 {
00290   return _p;
00291 }
00292 
00293 template< class T >
00294 bool ReferenceCountedPointer<T>::operator!() const
00295 {
00296   return (_p == 0);
00297 }
00298 
00299 template< class T >
00300 ReferenceCountedPointer<T>::operator bool() const
00301 {
00302   return (_p != 0);
00303 }
00304 
00305 template< class T >
00306 void
00307 ReferenceCountedPointer<T>::releasePointer()
00308 {
00309   if ( _p ) {
00310 
00311     --_p->_ref_count;
00312 
00313     if ( _p->_ref_count <= 0 ) {
00314       delete _p;
00315       _p = 0;
00316     }
00317   }
00318 }
00319 
00320 template< class T >
00321 void
00322 ReferenceCountedPointer<T>::takePointer( PlainPointerType ptr )
00323 {
00324 # if defined(DEBUG_MEMORY)
00325   Log::instance()->debug( "Taking Pointer: %x\n", ptr );
00326 # endif
00327   _p = ptr;
00328   if ( _p != 0 ) {
00329 
00330     ++_p->_ref_count;
00331 
00332 #   if defined(DEBUG_MEMORY)
00333     Log::instance()->debug( "Recount is: %d\n",_p->_ref_count);
00334 #   endif
00335 
00336   }
00337 }
00338 
00339 ReferenceCountedObject::~ReferenceCountedObject()
00340 {}
00341 
00342 #endif