HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
UT_COW.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: UT_COW.h ( UT Library, C++)
7  *
8  * COMMENTS:
9  * Defines our templated copy-on-write methods.
10  */
11 
12 #ifndef __UT_COW__
13 #define __UT_COW__
14 
15 #include "UT_API.h"
16 
17 #include <SYS/SYS_AtomicInt.h>
18 
19 #include "UT_SharedPtr.h"
20 #include "UT_Assert.h"
21 
22 ///
23 /// This is a copy-on-write shared pointer to data.
24 /// If you create a writehandle, it will uniquify the
25 /// underlying data.
26 /// Do not pass references to handles or pointers to them around.
27 /// This can cause you to invalidate the tracking of copies.
28 /// In any case, passing by value is fast.
29 ///
30 
31 // Forward declarations for our friendship.
32 template <typename Data> class UT_COWReadHandle;
33 template <typename Data> class UT_COWTransientReadHandle;
34 template <typename Data> class UT_COWWriteHandle;
35 
36 ///
37 /// A plain handle is an opaque refernce to the data. You can't
38 /// read or write to it with this sort of handle, but you can
39 /// copy and store it. Assign a plain handle into a ReadHandle
40 /// or a WriteHandle to gain more privelages.
41 ///
42 template <typename Data>
44 {
45 public:
46  /// Default constructor creates a null pointer. To assign the pointer:
47  /// @code
48  /// UT_COWHandle<Type> handle;
49  /// handle.steal( new Type(...) );
50  /// @endcode
52  : myData(),
53  myWriteCount(0)
54  {
55  }
57  : myData(),
58  myWriteCount(0)
59  {
60  *this = src;
61  }
62 
63  virtual ~UT_COWHandle()
64  {
65  // Locks must have expired.
66  UT_ASSERT(!myWriteCount);
67  }
68 
70  {
71  UT_ASSERT(!myWriteCount);
72  // It's fine to make a new handle of something with an existing
73  // write lock, as long as we release the handle before we
74  // next try to access the write lock. This condition is checked
75  // in the UT_COWWriteHandle cast functions.
76  myData = src.myData;
77 
78  return *this;
79  }
80 
81  /// Calls the default constructor on the object.
82  void allocate()
83  {
84  UT_ASSERT(!myWriteCount);
85  myData.steal(new Data);
86  }
87 
88  /// Makes a copy of the source data. This is the safest
89  /// approach as the caller will retain ownership.
90  /// @note This uses the Data copy constructor.
91  void copy(const Data *src)
92  {
93  UT_ASSERT(!myWriteCount);
94  myData.steal(new Data(*src));
95  }
96 
97  /// Be careful when initializing using this function. The
98  /// handle will gain ownership of the provided pointer, so
99  /// the caller should cease referring to it.
100  void steal(Data *src)
101  {
102  UT_ASSERT(!myWriteCount);
103  myData.steal(src);
104  }
105 
106  /// Turns us into a null pointer, a useful way to end our use
107  /// of a handle without having to play weird scope games.
108  void resetHandle()
109  {
110  UT_ASSERT(!myWriteCount);
111  myData.clear();
112  }
113 
114  /// Returns the number of shared pointer references to the same Data
115  int getRefCount() const
116  { return myData.use_count(); }
117 
118 private:
119  void makeUnique()
120  {
121  // Zero pointers are already unique
122  if (!myData)
123  return;
124 
125  if (!myData.unique())
126  {
127  UT_SharedPtr<Data > tmp(new Data(*myData));
128  myData = tmp;
129  }
130  // We are now unique!
131  }
132 
133  UT_SharedPtr<Data> myData;
134 
135  /// Tracks the number of outstanding writecounts referring to this
136  /// data.
137  /// This is only required for sanity-checking.
138  mutable SYS_AtomicInt32 myWriteCount;
139 
140  /// Grant our friends direct access.
141  template<typename OtherData> friend class UT_COWReadHandle;
142  template<typename OtherData> friend class UT_COWTransientReadHandle;
143  template<typename OtherData> friend class UT_COWWriteHandle;
144 };
145 
146 ///
147 /// Read Handles are copies of the original handle that have
148 /// their internal data exposed. You are not allowed to edit them,
149 /// so many read handles may be sharing the same underlying data.
150 ///
151 template <typename Data>
152 class UT_COWReadHandle
153 {
154 public:
156  {
157  // Handle's default to null so this is fine.
158  }
159 
161  {
162  // Natural destructor suffices.
163  }
164 
166  {
167  myHandle = src.myHandle;
168  }
169 
171  {
172  *this = src;
173  }
174 
176  {
177  myHandle = src.myHandle;
178  return *this;
179  }
180 
182  {
183  myHandle = src;
184  // It's fine to make a read lock of something with an existing
185  // write lock, as long as we release the read lock before we
186  // next try to access the write lock. This condition is checked
187  // in the UT_COWWriteHandle cast functions.
188  return *this;
189  }
190 
191  /// Removes references, making this a null pointer
192  void resetHandle()
193  {
194  myHandle.resetHandle();
195  }
196 
197  /// Test if this is a NULL pointer
198  bool isNull() const
199  {
200  return !myHandle.myData;
201  }
202 
203  const Data &operator*() const
204  {
205  return *myHandle.myData;
206  }
207 
208  const Data *operator->() const
209  {
210  return myHandle.myData.get();
211  }
212  const Data *get() const
213  {
214  return myHandle.myData.get();
215  }
216 
217  int getRefCount() const
218  { return myHandle.getRefCount(); }
219 
220 private:
221  UT_COWHandle<Data> myHandle;
222 };
223 
224 ///
225 /// Transient Read Handles are simply accessors to the internal data of
226 /// the original handle. Unlike normal read handles, transient read
227 /// handles don't result in a tracked reference to the underlying data,
228 /// and so have lower overhead, but are unsafe to use outside the scope
229 /// of, or after any changes to, the original handle. Write handles will
230 /// not be aware of any active transient read handles, so errors in this
231 /// usage will not trigger assertions. In fact, no write handles to the
232 /// underlying data should exist during the entire scope of a transient
233 /// read handle.
234 ///
235 /// You are not allowed to edit the underlying data, so many read handles
236 /// may be sharing the same underlying data.
237 ///
238 template <typename Data>
240 {
241 public:
243  : myData(NULL)
244  {
245  }
246 
248  {
249  // Natural destructor suffices.
250  }
251 
253  : myData(src.myData)
254  {
255  }
256 
258  : myData (src.myData.get())
259  {
260  }
261 
264  {
265  myData = src.myData;
266  return *this;
267  }
268 
270  const UT_COWHandle<Data> &src)
271  {
272  // We can't verify in the UT_COWWriteHandle cast functions that
273  // transient read handles are released before we next try to
274  // access the write lock, so we verify that they're not being
275  // created while any write lock is active.
276  UT_ASSERT(!src.myWriteCount);
277  myData = src.myData.get();
278  return *this;
279  }
280 
281  /// Removes references, making this a null pointer
282  void resetHandle()
283  {
284  myData = 0;
285  }
286 
287  /// Test if this is a NULL pointer
288  bool isNull() const
289  {
290  return !myData;
291  }
292 
293  const Data &operator*() const
294  {
295  return *myData;
296  }
297 
298  const Data *operator->() const
299  {
300  return myData;
301  }
302  const Data *get() const
303  {
304  return myData;
305  }
306 
307 private:
308  const Data *myData;
309 };
310 
311 ///
312 /// A write handle can be thought of as a pointer to the actual
313 /// data. It allows you to modify the underlying data. To do this,
314 /// it will unique the plain-handle's data so no outstanding
315 /// readlocks will be affected by the writes.
316 ///
317 /// Building read handles while a write handle is active is valid
318 /// so long as no dereference occurs during the lifetime of the read
319 /// handle.
320 ///
321 template <typename Data>
322 class UT_COWWriteHandle
323 {
324 public:
326  {
327  myHandle = 0;
328  }
329 
331  {
332  unlock();
333  }
334 
336  {
337  myHandle = 0;
338  *this = src;
339  }
340 
342  {
343  myHandle = 0;
344  *this = src;
345  }
346 
347  /// Passing write handles by value is fine as the users understand
348  /// they all share the same underlying data, so is responsible
349  /// for thread safety, etc.
351  {
352  // Track our lock counts appropriately.
353  src.lock();
354  unlock();
355  myHandle = src.myHandle;
356 
357  return *this;
358  }
359 
360  /// Converting from a handle into a write handle can only be
361  /// done once. This prevents other threads or methods from
362  /// invalidating our uniqueness property.
363  /// Note we up case from a *pointer* to a UT_COWHandle, not from
364  /// a UT_COWHandle. This avoids people accidentally using an
365  /// temporary as the source and underlines that write handles
366  /// are like pointers while read handles are like values.
368  {
369  myHandle = src;
370 
371  if (src)
372  {
373  // Ensure we are the only copy.
374  src->makeUnique();
375  }
376 
377  lock();
378  return *this;
379  }
380 
381  /// Turns this into a null handle to drop references.
382  void resetHandle()
383  {
384  unlock();
385  myHandle = 0;
386  }
387 
388  /// Test if this is a NULL pointer
389  bool isNull() const
390  {
391  return !myHandle || !myHandle->myData;
392  }
393 
394  Data &operator*() const
395  {
396  if (myHandle)
397  {
398  // It is possible UT_COWReadHandles were created on
399  // our handle. This is fine as long as they are
400  // destroyed before we do our next write access.
401  UT_ASSERT(myHandle->myData.unique());
402  return *(myHandle->myData);
403  }
404  else
405  {
406  // As much of a crash as returning zero,
407  // but the compiler is happier.
408  // return *(0);
409  return *(myHandle->myData);
410  }
411  }
412 
413  Data *operator->() const
414  {
415  if (myHandle)
416  {
417  // It is possible UT_COWReadHandles were created on
418  // our handle. This is fine as long as they are
419  // destroyed before we do our next write access.
420  UT_ASSERT(myHandle->myData.unique());
421  return &*(myHandle->myData);
422  }
423  else
424  return (Data *)0;
425  }
426 
427  int getRefCount() const
428  { return myHandle->getRefCount(); }
429 
430 private:
431  void unlock() const
432  {
433  if (myHandle)
434  {
435  // Don't track reference counts on null arrays since
436  // they are safe to share.
437  if (!myHandle->myData)
438  return;
439  UT_ASSERT(myHandle->myWriteCount);
440  if (myHandle->myWriteCount)
441  myHandle->myWriteCount.add(-1);
442  }
443  }
444 
445  void lock() const
446  {
447  if (myHandle)
448  {
449  // Don't track reference counts on null arrays since
450  // they are safe to share.
451  if (!myHandle->myData)
452  return;
453  myHandle->myWriteCount.add(1);
454  }
455  }
456 
457  UT_COWHandle<Data> *myHandle;
458 };
459 
460 #if defined( WIN32 ) || defined( LINUX ) || defined( MBSD ) || defined(GAMEOS)
461  #include "UT_COW.C"
462 #endif
463 
464 
465 #endif
466 
int getRefCount() const
Returns the number of shared pointer references to the same Data.
Definition: UT_COW.h:115
const UT_COWWriteHandle< Data > & operator=(UT_COWHandle< Data > *src)
Definition: UT_COW.h:367
UT_COWWriteHandle(const UT_COWWriteHandle< Data > &src)
Definition: UT_COW.h:335
UT_COWHandle(const UT_COWHandle< Data > &src)
Definition: UT_COW.h:56
UT_COWReadHandle(const UT_COWReadHandle< Data > &src)
Definition: UT_COW.h:165
virtual ~UT_COWHandle()
Definition: UT_COW.h:63
bool isNull() const
Test if this is a NULL pointer.
Definition: UT_COW.h:389
void steal(Data *src)
Definition: UT_COW.h:100
int getRefCount() const
Definition: UT_COW.h:217
bool isNull() const
Test if this is a NULL pointer.
Definition: UT_COW.h:288
Data & operator*() const
Definition: UT_COW.h:394
const UT_COWTransientReadHandle< Data > & operator=(const UT_COWTransientReadHandle< Data > &src)
Definition: UT_COW.h:262
UT_COWWriteHandle(UT_COWHandle< Data > *src)
Definition: UT_COW.h:341
const UT_COWTransientReadHandle< Data > & operator=(const UT_COWHandle< Data > &src)
Definition: UT_COW.h:269
void allocate()
Calls the default constructor on the object.
Definition: UT_COW.h:82
void resetHandle()
Definition: UT_COW.h:108
UT_COWTransientReadHandle(const UT_COWTransientReadHandle< Data > &src)
Definition: UT_COW.h:252
bool isNull() const
Test if this is a NULL pointer.
Definition: UT_COW.h:198
UT_COWReadHandle(const UT_COWHandle< Data > &src)
Definition: UT_COW.h:170
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:102
const UT_COWReadHandle< Data > & operator=(const UT_COWHandle< Data > &src)
Definition: UT_COW.h:181
const Data & operator*() const
Definition: UT_COW.h:293
const Data * operator->() const
Definition: UT_COW.h:298
const UT_COWWriteHandle< Data > & operator=(const UT_COWWriteHandle< Data > &src)
Definition: UT_COW.h:350
void copy(const Data *src)
Definition: UT_COW.h:91
void clear()
Convenience method to clear the pointer.
Definition: UT_SharedPtr.h:48
UT_COWTransientReadHandle(const UT_COWHandle< Data > &src)
Definition: UT_COW.h:257
void resetHandle()
Removes references, making this a null pointer.
Definition: UT_COW.h:282
Data * operator->() const
Definition: UT_COW.h:413
void steal(T *src)
Steal and take ownership of the data passed in.
Definition: UT_SharedPtr.h:51
int getRefCount() const
Definition: UT_COW.h:427
const Data & operator*() const
Definition: UT_COW.h:203
UT_COWHandle()
Definition: UT_COW.h:51
const Data * operator->() const
Definition: UT_COW.h:208
const UT_COWHandle< Data > & operator=(const UT_COWHandle< Data > &src)
Definition: UT_COW.h:69
void resetHandle()
Removes references, making this a null pointer.
Definition: UT_COW.h:192
const Data * get() const
Definition: UT_COW.h:302
const UT_COWReadHandle< Data > & operator=(const UT_COWReadHandle< Data > &src)
Definition: UT_COW.h:175
GLenum src
Definition: glcorearb.h:1792
void resetHandle()
Turns this into a null handle to drop references.
Definition: UT_COW.h:382