00001 /* 00002 * PROPRIETARY INFORMATION. This software is proprietary to 00003 * Side Effects Software Inc., and is not to be reproduced, 00004 * transmitted, or disclosed in any way without written permission. 00005 * 00006 * Produced by: 00007 * Jeff Lait 00008 * Side Effects Software Inc 00009 * 123 Front Street West, Suite 1401 00010 * Toronto, Ontario 00011 * Canada M5J 2M2 00012 * 416-504-9876 00013 * 00014 * NAME: UT_COW.h ( UT Library, C++) 00015 * 00016 * COMMENTS: 00017 * Defines our templated copy-on-write methods. 00018 */ 00019 00020 #ifndef __UT_COW__ 00021 #define __UT_COW__ 00022 00023 #include "UT_API.h" 00024 00025 #include <SYS/SYS_AtomicInt.h> 00026 00027 // Sadly, we cannot include this in the .C file since we are 00028 // a template 00029 #include <SYS/SYS_AtomicIntImpl.h> 00030 #include "UT_SharedPtr.h" 00031 #include "UT_Assert.h" 00032 00033 /// 00034 /// This is a copy-on-write shared pointer to data. 00035 /// If you create a writehandle, it will uniquify the 00036 /// underlying data. 00037 /// Do not pass references to handles or pointers to them around. 00038 /// This can cause you to invalidate the tracking of copies. 00039 /// In any case, passing by value is fast. 00040 /// 00041 00042 // Forward declarations for our friendship. 00043 template <typename Data> class UT_COWReadHandle; 00044 template <typename Data> class UT_COWWriteHandle; 00045 00046 /// 00047 /// A plain handle is an opaque refernce to the data. You can't 00048 /// read or write to it with this sort of handle, but you can 00049 /// copy and store it. Assign a plain handle into a ReadHandle 00050 /// or a WriteHandle to gain more privelages. 00051 /// 00052 template <typename Data> 00053 class UT_COWHandle 00054 { 00055 public: 00056 /// Default constructor creates a null pointer. To assign the pointer: 00057 /// @code 00058 /// UT_COWHandle<Type> handle; 00059 /// handle.steal( new Type(...) ); 00060 /// @endcode 00061 UT_COWHandle() 00062 : myData(), 00063 myWriteCount(0) 00064 { 00065 } 00066 UT_COWHandle(const UT_COWHandle<Data> &src) 00067 : myData(), 00068 myWriteCount(0) 00069 { 00070 *this = src; 00071 } 00072 00073 virtual ~UT_COWHandle() 00074 { 00075 // Locks must have expired. 00076 UT_ASSERT(!myWriteCount); 00077 } 00078 00079 const UT_COWHandle<Data> &operator=(const UT_COWHandle<Data> &src) 00080 { 00081 UT_ASSERT(!myWriteCount); 00082 // It's fine to make a new handle of something with an existing 00083 // write lock, as long as we release the handle before we 00084 // next try to access the write lock. This condition is checked 00085 // in the UT_COWWriteHandle cast functions. 00086 myData = src.myData; 00087 00088 return *this; 00089 } 00090 00091 /// Calls the default constructor on the object. 00092 void allocate() 00093 { 00094 UT_ASSERT(!myWriteCount); 00095 myData.steal(new Data); 00096 } 00097 00098 /// Makes a copy of the source data. This is the safest 00099 /// approach as the caller will retain ownership. 00100 /// @note This uses the Data copy constructor. 00101 void copy(Data *src) 00102 { 00103 UT_ASSERT(!myWriteCount); 00104 myData.steal(new Data(*src)); 00105 } 00106 00107 /// Be careful when initializing using this function. The 00108 /// handle will gain ownership of the provided pointer, so 00109 /// the caller should cease referring to it. 00110 void steal(Data *src) 00111 { 00112 UT_ASSERT(!myWriteCount); 00113 myData.steal(src); 00114 } 00115 00116 /// Turns us into a null pointer, a useful way to end our use 00117 /// of a handle without having to play weird scope games. 00118 void resetHandle() 00119 { 00120 UT_ASSERT(!myWriteCount); 00121 myData.clear(); 00122 } 00123 00124 private: 00125 void makeUnique() 00126 { 00127 // Zero pointers are already unique 00128 if (!myData) 00129 return; 00130 00131 if (!myData.unique()) 00132 { 00133 UT_SharedPtr<Data > tmp(new Data(*myData)); 00134 myData = tmp; 00135 } 00136 // We are now unique! 00137 } 00138 00139 UT_SharedPtr<Data> myData; 00140 00141 /// Tracks the number of outstanding writecounts referring to this 00142 /// data. 00143 /// This is only required for sanity-checking. 00144 mutable SYS_AtomicInt32 myWriteCount; 00145 00146 /// Grant our friends direct access. 00147 template<typename OtherData> friend class UT_COWReadHandle; 00148 template<typename OtherData> friend class UT_COWWriteHandle; 00149 }; 00150 00151 /// 00152 /// Read Handles are copies of the original handle that have 00153 /// their internal data exposed. You are not allowed to edit them, 00154 /// so many read handles may be sharing the same underlying data. 00155 /// 00156 template <typename Data> 00157 class UT_COWReadHandle 00158 { 00159 public: 00160 UT_COWReadHandle() 00161 { 00162 // Handle's default to null so this is fine. 00163 } 00164 00165 ~UT_COWReadHandle() 00166 { 00167 // Natural destructor suffices. 00168 } 00169 00170 UT_COWReadHandle(const UT_COWReadHandle<Data> &src) 00171 { 00172 myHandle = src.myHandle; 00173 } 00174 00175 UT_COWReadHandle(const UT_COWHandle<Data> &src) 00176 { 00177 *this = src; 00178 } 00179 00180 const UT_COWReadHandle<Data> &operator=(const UT_COWReadHandle<Data> &src) 00181 { 00182 myHandle = src.myHandle; 00183 return *this; 00184 } 00185 00186 const UT_COWReadHandle<Data> &operator=(const UT_COWHandle<Data> &src) 00187 { 00188 myHandle = src; 00189 // It's fine to make a read lock of something with an existing 00190 // write lock, as long as we release the read lock before we 00191 // next try to access the write lock. This condition is checked 00192 // in the UT_COWWriteHandle cast functions. 00193 return *this; 00194 } 00195 00196 /// Removes references, making this a null pointer 00197 void resetHandle() 00198 { 00199 myHandle.resetHandle(); 00200 } 00201 00202 /// Test if this is a NULL pointer 00203 bool isNull() const 00204 { 00205 return myHandle.myData.isNull(); 00206 } 00207 00208 const Data &operator*() const 00209 { 00210 return *myHandle.myData; 00211 } 00212 00213 const Data *operator->() const 00214 { 00215 return myHandle.myData.get(); 00216 } 00217 00218 private: 00219 UT_COWHandle<Data> myHandle; 00220 }; 00221 00222 /// 00223 /// A write handle can be thought of as a pointer to the actual 00224 /// data. It allows you to modify the underlying data. To do this, 00225 /// it will unique the plain-handle's data so no outstanding 00226 /// readlocks will be affected by the writes. 00227 /// 00228 /// Building read handles while a write handle is active is valid 00229 /// so long as no dereference occurs during the lifetime of the read 00230 /// handle. 00231 /// 00232 template <typename Data> 00233 class UT_COWWriteHandle 00234 { 00235 public: 00236 UT_COWWriteHandle() 00237 { 00238 myHandle = 0; 00239 } 00240 00241 ~UT_COWWriteHandle() 00242 { 00243 unlock(); 00244 } 00245 00246 UT_COWWriteHandle(const UT_COWWriteHandle<Data> &src) 00247 { 00248 myHandle = 0; 00249 *this = src; 00250 } 00251 00252 UT_COWWriteHandle(UT_COWHandle<Data> *src) 00253 { 00254 myHandle = 0; 00255 *this = src; 00256 } 00257 00258 /// Passing write handles by value is fine as the users understand 00259 /// they all share the same underlying data, so is responsible 00260 /// for thread safety, etc. 00261 const UT_COWWriteHandle<Data> &operator=(const UT_COWWriteHandle<Data> &src) 00262 { 00263 // Track our lock counts appropriately. 00264 src.lock(); 00265 unlock(); 00266 myHandle = src.myHandle; 00267 00268 return *this; 00269 } 00270 00271 /// Converting from a handle into a write handle can only be 00272 /// done once. This prevents other threads or methods from 00273 /// invalidating our uniqueness property. 00274 /// Note we up case from a *pointer* to a UT_COWHandle, not from 00275 /// a UT_COWHandle. This avoids people accidentally using an 00276 /// temporary as the source and underlines that write handles 00277 /// are like pointers while read handles are like values. 00278 const UT_COWWriteHandle<Data> &operator=(UT_COWHandle<Data> *src) 00279 { 00280 myHandle = src; 00281 00282 if (src) 00283 { 00284 // Ensure we are the only copy. 00285 src->makeUnique(); 00286 } 00287 00288 lock(); 00289 return *this; 00290 } 00291 00292 /// Turns this into a null handle to drop references. 00293 void resetHandle() 00294 { 00295 unlock(); 00296 myHandle = 0; 00297 } 00298 00299 /// Test if this is a NULL pointer 00300 bool isNull() const 00301 { 00302 return !myHandle || !myHandle->myData; 00303 } 00304 00305 Data &operator*() const 00306 { 00307 if (myHandle) 00308 { 00309 // It is possible UT_COWReadHandles were created on 00310 // our handle. This is fine as long as they are 00311 // destroyed before we do our next write access. 00312 UT_ASSERT(myHandle->myData.unique()); 00313 return *(myHandle->myData); 00314 } 00315 else 00316 { 00317 // As much of a crash as returning zero, 00318 // but the compiler is happier. 00319 // return *(0); 00320 return *(myHandle->myData); 00321 } 00322 } 00323 00324 Data *operator->() const 00325 { 00326 if (myHandle) 00327 { 00328 // It is possible UT_COWReadHandles were created on 00329 // our handle. This is fine as long as they are 00330 // destroyed before we do our next write access. 00331 UT_ASSERT(myHandle->myData.unique()); 00332 return &*(myHandle->myData); 00333 } 00334 else 00335 return (Data *)0; 00336 } 00337 00338 private: 00339 void unlock() const 00340 { 00341 if (myHandle) 00342 { 00343 // Don't track reference counts on null arrays since 00344 // they are safe to share. 00345 if (!myHandle->myData) 00346 return; 00347 UT_ASSERT(myHandle->myWriteCount); 00348 if (myHandle->myWriteCount) 00349 myHandle->myWriteCount.add(-1); 00350 } 00351 } 00352 00353 void lock() const 00354 { 00355 if (myHandle) 00356 { 00357 // Don't track reference counts on null arrays since 00358 // they are safe to share. 00359 if (!myHandle->myData) 00360 return; 00361 myHandle->myWriteCount.add(1); 00362 } 00363 } 00364 00365 UT_COWHandle<Data> *myHandle; 00366 }; 00367 00368 #if defined( WIN32 ) || defined( LINUX ) || defined( MBSD ) || defined(GAMEOS) 00369 #include "UT_COW.C" 00370 #endif 00371 00372 00373 #endif 00374
1.5.9