base_unique_ptr.hh

Go to the documentation of this file.
00001 /*
00008  * LEGAL:   COPYRIGHT (C) JIM E. BROOKS 2007
00009  *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
00010  *          OF THE GNU GENERAL PUBLIC LICENSE VERSION 2 (GPL 2).
00011  *****************************************************************************/
00012 
00115 
00116 #ifndef BASE_UNIQUE_PTR_HH
00117 #define BASE_UNIQUE_PTR_HH 1
00118 
00119 
00120 
00121 #include "base_common.hh"
00122 #include "base_defs.hh"
00123 #include "base_funcs.hh"
00124 
00125 namespace base {
00126 
00128 // Applying a global lock to every type of UniqueFactory isn't optimal,
00129 // but a single lock allows the UniqueFactory class to contain and hide it.
00130 #if COMPILE_THREADS
00131 namespace restrict { BASE_GLOBAL FastLock gLockUniqueFactory; }
00132 #endif
00133 
00138 #define uniptr UniquePtr
00139 
00147 class Unique
00148 {
00149     // Empty base class.
00150     //
00151     // Don't try to optimize UniqueFactory by letting it store a flag in this class
00152     // in order to reduce searching STL set.  The problem is that clients would be ignorant
00153     // of such a flag and may change the same object and encapsulate it in multiple UniquePtrs
00154     // (an example is Import) but flag would incorrectly be true after every modification.
00155 public:
00156     ;
00157 };
00158 
00167 template<typename T>
00168 class UniqueFactory : private Threadable
00169 {
00170 public:
00171     UniqueFactory( void ) { SET_TYPESIG(this,TYPESIG_UNIQUE_FACTORY); }
00172     ~UniqueFactory()      { INVALIDATE_TYPESIG(this,TYPESIG_UNIQUE_FACTORY); }
00173 
00174     // Substitute a new object with an equal object from the unique set.
00175     SafePtr<const T> Substitute( const T* obj )
00176     {
00177     THREAD_CODE( FastLock::Auto autolock( &restrict::gLockUniqueFactory ); )
00178     CHECK_TYPESIG(this,TYPESIG_UNIQUE_FACTORY);  // catch if factory was destroyed
00179 
00180         if ( EX( obj != NULL ) )
00181         {
00182             // Compiler's type-checking prevents a caller passing back
00183             // what this returns (SafePtr<T> can't be passed as T*).
00184             // If not for SafePtr, "delete obj" could corrupt the set.
00185             SafePtr<const T> obj2 = Substitute( *obj );
00186             delete obj;  // client is supposed to let UniqueFactory own it
00187             return obj2;
00188         }
00189         else
00190         {
00191             return NULL;  // toss grenade back
00192         }
00193     }
00194 
00195     // Substitute a reference with an equal object in the unique set.
00196     SafePtr<const T> Substitute( const T& obj )
00197     {
00198     THREAD_CODE( FastLock::Auto autolock( &restrict::gLockUniqueFactory ); )
00199     CHECK_TYPESIG(this,TYPESIG_UNIQUE_FACTORY);
00200 
00201         // insert() either inserts a new item or returns an existing one.
00202         // Pointers to STL set elements are ok.
00203         pair<typename set<T>::iterator,bool> iter_flag = mSet.insert( obj );
00204         const T* unique = &*iter_flag.first;  // &* is an STL idiom
00205         CHECK_TYPESIG( unique, TYPESIG_UNIQUE );  // catch if client misuses PTR() and deletes it
00206         return unique;
00207     }
00208 
00209 #if DEBUG || STATS
00210     uint GetCnt( void ) const { return mSet.size(); }  // number of items in factory
00211 #endif
00212 
00213 private:
00214     set<T>  mSet;  // STL set provides uniqueification.  BTW, "set<const T>" doesn't compile.
00215 public:
00216     
00217 };
00218 
00220 // Smart pointer that shares a unique object.
00221 //
00222 template<typename T>
00223 class UniquePtr : private Threadable
00224 {
00225 
00226 public:
00227     // For pointer variants, UniquePtr takes ownership of given object (like SharedPtr).
00228     UniquePtr( const T* obj ) : mObj(T::GetUniqueFactory().Substitute(obj)) { }
00229     UniquePtr( const T& obj ) : mObj(T::GetUniqueFactory().Substitute(obj)) { }
00230   //UniquePtr( UniquePtr& ); // default suffices
00231     ~UniquePtr() { }  // mObj owned by factory
00232     const UniquePtr& operator=( const T* obj ) { mObj = T::GetUniqueFactory().Substitute( obj ); }
00233     const UniquePtr& operator=( const T& obj ) { mObj = T::GetUniqueFactory().Substitute( obj ); }
00234   //operator=(UniquePtr&) // default suffices
00235     const T* operator->( void ) const { return mObj.CONST_PTR(); }  // returns const to prevent client turning it into a duplicate
00236     const T& operator*( void ) const { return mObj.CONST_REF(); }  // limited use (extracted reference could dangle)
00237     bool operator==( const UniquePtr& other ) const { return mObj == other.mObj; }
00238     bool operator!=( const UniquePtr& other ) const { return mObj != other.mObj; }
00239     bool operator==( const T* obj ) const { return mObj == obj; }
00240     bool operator!=( const T* obj ) const { return mObj != obj; }
00241     bool operator==( const T& obj ) const { return *mObj == obj; }
00242     bool operator!=( const T& obj ) const { return *mObj != obj; }
00243     // Very limited use.  Avoiding the risk of deleting object owned by UniqueFactory!
00244     const T* CONST_PTR( void ) const { return mObj; }
00245     const T& CONST_REF( void ) const { return *mObj; }
00246 
00247 private:
00248     SafePtr<const T>  mObj;  // factory owns it
00249 };
00250 
00251 template<typename T> bool operator==( const UniquePtr<T>& a, const UniquePtr<T>& b ) { return a.PTR() == b.PTR(); }
00252 template<typename T> bool operator!=( const UniquePtr<T>& a, const UniquePtr<T>& b ) { return a.PTR() != b.PTR(); }
00253 template<typename T> bool operator<( const UniquePtr<T>& a, const UniquePtr<T>& b ) { return a.PTR() < b.PTR(); }
00254 
00255 } // namespace base
00256 
00257 #endif // BASE_UNIQUE_PTR_HH
Palomino 3D Engine documents generated by doxygen 1.5.3 on Fri Nov 23 11:26:07 2007