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