Main Page   Modules   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

RCObject.h

Go to the documentation of this file.
00001 // Copyright NVIDIA Corporation 2002-2004
00002 // TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED
00003 // *AS IS* AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS
00004 // OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
00005 // AND FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL NVIDIA OR ITS SUPPLIERS
00006 // BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES
00007 // WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
00008 // BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR ANY OTHER PECUNIARY LOSS)
00009 // ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF NVIDIA HAS
00010 // BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES 
00011 
00012 // rcobject.h
00013 //
00014 // Support for reference counted object
00015 //
00016 #pragma once
00017 
00019 #include "nvsgcommon.h"
00020 
00021 #include "nvutil/Allocator.h" // for IAllocator interface
00022 
00023 // memory leak detection
00024 #ifdef _DEBUG
00025 # ifndef new
00026 #  define new new(__FILE__, __LINE__)
00027 #  define _DEFINED_DBGNEW // restrict the 'new' macro to this header file only
00028 # endif
00029 #endif
00030 
00031 namespace nvutil
00032 {
00034 
00055   class RCObject : public IAllocator
00056   {
00057     public:
00059 
00060       RCObject() : m_refcnt(0), m_shareable(true) {};
00061 
00063 
00069       NVSG_API void addRef()            const; 
00071 
00074       NVSG_API void removeRef()         const;  
00076 
00079       NVSG_API void markUnshareable();
00081 
00084       NVSG_API bool isShareable()       const; 
00086 
00090       NVSG_API bool isShared()          const; 
00091 
00092     protected:
00093 
00095 
00097       RCObject(const RCObject& rhs) : m_refcnt(0), m_shareable(true) {}
00098 
00100 
00102       RCObject& operator=(const RCObject& rhs) { return *this; }
00103 
00105 
00107       virtual ~RCObject() {}
00108 
00109     private:
00111       mutable int m_refcnt;
00112       bool m_shareable;
00113   };
00114 
00116 
00119   template<typename T>
00120   class RCVector : public std::vector<T>, public RCObject
00121   {
00122     public:
00124       RCVector()
00125       {
00126       }
00127 
00129 
00130       RCVector( size_t n      
00131               )
00132         : std::vector<T>(n)
00133       {
00134       }
00135   };
00136 
00138 
00145   template <typename T>
00146   class RCPtr
00147   {
00149 
00165     template <typename U>
00166     friend void writeAccess( RCPtr<U> &rcPtr 
00167                           );
00168    
00169     public: 
00170       explicit RCPtr(T* pRCObj=0);              
00171       RCPtr(const RCPtr& rhs);                  
00172       ~RCPtr();                                 
00173       RCPtr<T>& operator=(const RCPtr<T>& rhs); 
00174       
00175       T* operator->();                
00176       const T* operator->() const;    
00177       T& operator*();                 
00178       const T& operator*() const;     
00179 
00180     private:
00181       void init();                              
00182       void clone();                             
00183 
00184       // the dump pointer
00185       T * m_ptr;
00186   };
00187 
00189 
00193   template <typename T>
00194   class RCIPtr
00195   {
00197 
00213     template <typename U>
00214     friend void writeAccess( RCIPtr<U> &rcPtr 
00215                           );
00216 
00217     public:
00218       explicit RCIPtr(T* pObj=0);                 
00219       RCIPtr(const RCIPtr& rhs);                  
00220       ~RCIPtr();                                  
00221       RCIPtr<T>& operator=(const RCIPtr<T>& rhs); 
00222       
00223       T* operator->();                
00224       const T* operator->() const;    
00225       T& operator*();                 
00226       const T& operator*() const;     
00227 
00228     private:
00229       // CountHolder acts as an additional indirection and holds
00230       // a dump pointer to the opject beeing reference counted
00231       struct CountHolder : public RCObject
00232       {
00233         // destructor only gets called when the objects 
00234         // reference count reaches zero
00235         ~CountHolder() { delete m_ptr; }
00236         T * m_ptr;
00237       };
00238 
00239       CountHolder * m_cntHolder;
00240 
00241       void init();
00242       void clone(); // copy on write
00243   };
00244 
00246 
00248   template <typename T>
00249   class RCObject_AutoPtr
00250   {
00251     template<typename U> 
00252     friend class RCObject_AutoPtr;  
00253 
00254     public:
00255       explicit RCObject_AutoPtr(T * ptr=0);               
00256       template <typename U>
00257       RCObject_AutoPtr(const RCObject_AutoPtr<U>& rhs);   
00258       ~RCObject_AutoPtr();                                
00259       template <typename U>
00260       RCObject_AutoPtr<T>& operator=(const RCObject_AutoPtr<U>& rhs); 
00261 
00262       T * get() const;            
00263       T * operator->() const;     
00264       T&  operator*() const;      
00265       T * release();              
00266       void reset(T * ptr);        
00267 
00268     private:
00269       void deletePointer();
00270       T * m_ptr;
00271   };
00272 
00273   //----------------------------------------------------------------------------
00274   // inline implementations following
00275   //----------------------------------------------------------------------------
00276 
00277   inline void RCObject::addRef() const 
00278   { 
00279     ++m_refcnt; 
00280   } 
00281 
00282   inline void RCObject::removeRef() const
00283   { 
00284     __ASSERT(m_refcnt>0); 
00285     if (!--m_refcnt) 
00286     { 
00287       delete this; 
00288     } 
00289   }
00290 
00291   inline void RCObject::markUnshareable() 
00292   { 
00293     m_shareable=false; 
00294   }
00295 
00296   inline bool RCObject::isShareable() const 
00297   { 
00298     return m_shareable==true; 
00299   }
00300 
00301   inline bool RCObject::isShared() const 
00302   { 
00303     return m_refcnt>1; 
00304   }
00305   //>>
00306   template <typename T>
00307   inline RCPtr<T>::RCPtr(T* pRCObj) 
00308   : m_ptr(pRCObj) 
00309   { 
00310     init(); 
00311   }
00312 
00313   template <typename T>
00314   inline RCPtr<T>::RCPtr(const RCPtr& rhs) 
00315   : m_ptr(rhs.m_ptr) 
00316   { 
00317     init(); 
00318   }
00319 
00320   template <typename T>
00321   inline RCPtr<T>::~RCPtr() 
00322   { 
00323     if ( m_ptr ) 
00324     { 
00325       m_ptr->removeRef(); 
00326     } 
00327   }
00328 
00329   template <typename T>
00330   inline RCPtr<T>& RCPtr<T>::operator=(const RCPtr<T>& rhs) 
00331   {
00332     if ( m_ptr != rhs.m_ptr )
00333     {
00334       // remove reference to former value first
00335       m_ptr->removeRef();
00336       m_ptr = rhs.m_ptr;
00337       init();
00338     }
00339     return *this;
00340   }
00341     
00342   template <typename T>
00343   inline T* RCPtr<T>::operator->() 
00344   { 
00345     return m_ptr; 
00346   }
00347 
00348   template <typename T>
00349   inline const T* RCPtr<T>::operator->() const 
00350   { 
00351     return m_ptr; 
00352   }
00353 
00354   template <typename T>
00355   inline T& RCPtr<T>::operator*() 
00356   { 
00357     return *m_ptr; 
00358   }
00359 
00360   template <typename T>
00361   inline const T& RCPtr<T>::operator*() const 
00362   { 
00363     return *m_ptr; 
00364   }
00365 
00366   template <typename T>
00367   inline void RCPtr<T>::init()
00368   {
00369     if ( !m_ptr ) return;
00370     
00371     if ( !m_ptr->isShareable() )
00372     {
00373       // deep copy required!
00374       m_ptr = new T(*m_ptr);
00375     }
00376     m_ptr->addRef();
00377   }
00378 
00379   template <typename T>
00380   inline void RCPtr<T>::clone()
00381   {
00382     if ( m_ptr->isShared() )
00383     { 
00384       // need to wedge off an own copy if original data is shared 
00385       T * pOldVal = m_ptr; // remember the old object pointer for deep copying below
00386       m_ptr->removeRef(); // unreference the object before beeing new assigned
00387       m_ptr = new T(*pOldVal); // deep copy -> T(const T&) required!
00388       m_ptr->addRef();
00389     }
00390   }
00391   //>>
00392   template <typename T>
00393   inline RCIPtr<T>::RCIPtr(T * pObj)
00394   : m_cntHolder(new CountHolder)
00395   {
00396     m_cntHolder->m_ptr = pObj;
00397     init();
00398   }
00399 
00400   template <typename T>
00401   inline RCIPtr<T>::RCIPtr(const RCIPtr<T>& rhs)
00402   : m_cntHolder(rhs.m_cntHolder)
00403   {
00404     init();
00405   }
00406 
00407   template <typename T>
00408   inline RCIPtr<T>::~RCIPtr()
00409   {
00410     m_cntHolder->removeRef();
00411   }
00412 
00413   template <typename T>
00414   inline RCIPtr<T>& RCIPtr<T>::operator=(const RCIPtr<T>& rhs)
00415   {
00416     if ( m_cntHolder != rhs.m_cntHolder )
00417     {
00418       m_cntHolder->removeRef(); // unreference the object before beeing new assigned
00419       m_cntHolder = rhs.m_cntHolder;
00420       init();
00421     }
00422     return *this;
00423   }
00424 
00425   template <typename T>
00426   inline const T* RCIPtr<T>::operator->() const
00427   {
00428     // const access, no need for copy on write here
00429     return m_cntHolder->m_ptr;
00430   }
00431 
00432   template <typename T>
00433   inline T* RCIPtr<T>::operator->() 
00434   {
00435     // perform copy on write with every non-const access to the pointed-to object
00436     // clone();
00437     return m_cntHolder->m_ptr;
00438   }
00439 
00440   template <typename T>
00441   inline const T& RCIPtr<T>::operator*() const
00442   {
00443     // const access, no need for copy on write here
00444     return *(m_cntHolder->m_ptr);
00445   }
00446 
00447   template <typename T>
00448   inline T& RCIPtr<T>::operator*() 
00449   {
00450     // perform copy on write with every non-const access to the pointed-to object
00451     // clone();
00452     return *(m_cntHolder->m_ptr);
00453   }
00454 
00455   template <typename T>
00456   inline void RCIPtr<T>::init()
00457   {
00458     if ( !m_cntHolder->isShareable() )
00459     {
00460       // non-shareables must not be shared (refcnt==1)
00461       _ASSERTE(!m_cntHolder->isShared());
00462       // must not unreference unshared objects because this 
00463       // would delete the pointed-to object immediately! 
00464       T * pOldVal = m_cntHolder->m_ptr;
00465       m_cntHolder = new CountHolder;
00466       m_cntHolder->m_ptr = new T(*pOldVal);
00467     }
00468     m_cntHolder->addRef();
00469   }
00470 
00471   template <typename T>
00472   inline void RCIPtr<T>::clone()
00473   {
00474     if ( m_cntHolder->isShared() )
00475     {
00476       T * pOldVal = m_cntHolder->m_ptr; // remember the old object pointer for deep copying below
00477       m_cntHolder->removeRef(); // unreference the object before beeing new assigned
00478       m_cntHolder = new CountHolder;
00479       m_cntHolder->m_ptr = new T(*pOldVal); // deep copy
00480       m_cntHolder->addRef();
00481     }
00482   }
00483   //>>
00484 
00485   template <typename T>
00486   inline RCObject_AutoPtr<T>::RCObject_AutoPtr(T * ptr)
00487   : m_ptr(ptr)
00488   {
00489   }
00490 
00491   template <typename T>
00492   template <typename U>
00493   inline RCObject_AutoPtr<T>::RCObject_AutoPtr(const RCObject_AutoPtr<U>& rhs)
00494   : m_ptr(rhs.release())
00495   {
00496     // !! don't add reference here !!
00497   }
00498 
00499   template <typename T>
00500   inline RCObject_AutoPtr<T>::~RCObject_AutoPtr()
00501   {
00502     deletePointer();
00503   }
00504     
00505   template <typename T>
00506   template <typename U>
00507   inline RCObject_AutoPtr<T>& RCObject_AutoPtr<T>::operator=(const RCObject_AutoPtr<U>& rhs)
00508   {
00509     if ( this != &rhs )
00510     {
00511       reset(rhs.release());
00512     }
00513     return *this;
00514   }
00515 
00516   template <typename T>
00517   inline T * RCObject_AutoPtr<T>::get() const
00518   {
00519     return m_ptr;
00520   }
00521 
00522   template <typename T>
00523   inline T * RCObject_AutoPtr<T>::operator->() const
00524   {
00525     return m_ptr;
00526   }
00527 
00528   template <typename T>
00529   inline T&  RCObject_AutoPtr<T>::operator*() const
00530   {
00531     return *m_ptr;
00532   }
00533     
00534   template <typename T>
00535   inline T * RCObject_AutoPtr<T>::release()
00536   {
00537     T * ptr = m_ptr;
00538     m_ptr = 0;
00539     return ptr;
00540   }
00541 
00542   template <typename T>
00543   void RCObject_AutoPtr<T>::reset(T * ptr)
00544   {
00545     if ( m_ptr != ptr )
00546     {
00547       deletePointer();
00548       m_ptr = ptr;
00549       // !! don't ad reference here !!
00550     }
00551   }
00552 
00553   template <typename T>
00554   void RCObject_AutoPtr<T>::deletePointer()
00555   {
00556     if ( m_ptr )
00557     {
00558       m_ptr->addRef();
00559       m_ptr->removeRef();
00560     }
00561   }
00562 
00563   //>>
00564   template <typename T>
00565   inline void writeAccess( RCPtr<T> &rcPtr )
00566   {
00567     // perform a deep copy of the embedded object if shared
00568     rcPtr.clone();
00569   }
00570 
00571   //>>
00572   template <typename T>
00573   inline void writeAccess( RCIPtr<T> &rcPtr )
00574   {
00575     // perform a deep copy of the embedded object if shared
00576     rcPtr.clone();
00577   }
00578 
00579 //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
00581   /** With this helper functor it's easy and efficient to add a reference to each object contained in a STL container.
00582     * To copy a container of reference counted objects and increase their reference count you could do something like
00583     * that:
00584     *   \code
00585     *   for ( iter=src.begin() ; iter!=src.end() ; ++iter )
00586     *   {
00587     *     dst.push_back( *iter );
00588     *     (*iter)->addRef();
00589     *   }
00590     *   \endcode
00591     * or, equivalently but more efficiently, using this functor:
00592     *   \code
00593     *   transform( src.begin(), src.end(), inserter( dst, dst.begin()), addReference() );
00594     *   \endcode
00595     */
00596   struct addReference
00597   {
00599 
00601     template <typename RCOBJPTR>
00602     RCOBJPTR operator()( RCOBJPTR pRCObject   
00603                       );
00604 
00606 
00608     template <typename AnyType, typename RCOBJPTR>
00609       const std::pair<AnyType, RCOBJPTR>& operator()( std::pair<AnyType,RCOBJPTR>& p  
00610                                             );
00611   };
00612 
00613   template <typename RCOBJPTR>
00614   RCOBJPTR addReference::operator()( RCOBJPTR pRCObject )
00615   {
00616     pRCObject->addRef();
00617     return pRCObject;
00618   }
00619 
00620   template <typename AnyType, typename RCOBJPTR>
00621   const std::pair<AnyType, RCOBJPTR>& addReference::operator()( std::pair<AnyType,RCOBJPTR>& p )
00622   {
00623     p.second->addRef();
00624     return p;
00625   }
00626 //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
00627 
00629   struct removeReference
00630   {
00632     template <typename RCOBJPTR>
00633     RCOBJPTR operator()(RCOBJPTR pRCObject) 
00634       { pRCObject->removeRef(); return pRCObject; }
00635 
00637     template <typename AnyType, typename RCOBJPTR>
00638     const std::pair<AnyType, RCOBJPTR>& operator() (std::pair<AnyType,RCOBJPTR>& p) 
00639       { p.second->removeRef(); return p; }
00640   };
00641 
00642 } // namespace nvutil
00643 
00644 #ifdef _DEFINED_DBGNEW
00645 # undef new
00646 #endif

Generated on Tue Mar 1 13:19:18 2005 for NVSGSDK by NVIDIA