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