HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups 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_Assert.h"
20 #include "UT_SharedPtr.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>
43 class UT_COWHandle
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.relaxedLoad());
67  }
68 
70  {
71  UT_ASSERT(!myWriteCount.relaxedLoad());
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.relaxedLoad());
85  myData = UTmakeShared<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.relaxedLoad());
94  myData = UTmakeShared<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.relaxedLoad());
103  myData.reset(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.relaxedLoad());
111  myData.reset();
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  myData = UTmakeShared<Data>(*myData);
128  }
129  // We are now unique!
130  }
131 
132  UT_SharedPtr<Data> myData;
133 
134  /// Tracks the number of outstanding writecounts referring to this
135  /// data.
136  /// This is only required for sanity-checking.
137  mutable SYS_AtomicInt32 myWriteCount;
138 
139  /// Grant our friends direct access.
140  template<typename OtherData> friend class UT_COWReadHandle;
141  template<typename OtherData> friend class UT_COWTransientReadHandle;
142  template<typename OtherData> friend class UT_COWWriteHandle;
143 };
144 
145 ///
146 /// Read Handles are copies of the original handle that have
147 /// their internal data exposed. You are not allowed to edit them,
148 /// so many read handles may be sharing the same underlying data.
149 ///
150 template <typename Data>
151 class UT_COWReadHandle
152 {
153 public:
155  {
156  // Handle's default to null so this is fine.
157  }
158 
160  {
161  // Natural destructor suffices.
162  }
163 
165  {
166  myHandle = src.myHandle;
167  }
168 
170  {
171  *this = src;
172  }
173 
175  {
176  myHandle = src.myHandle;
177  return *this;
178  }
179 
181  {
182  myHandle = src;
183  // It's fine to make a read lock of something with an existing
184  // write lock, as long as we release the read lock before we
185  // next try to access the write lock. This condition is checked
186  // in the UT_COWWriteHandle cast functions.
187  return *this;
188  }
189 
190  /// Removes references, making this a null pointer
191  void resetHandle()
192  {
193  myHandle.resetHandle();
194  }
195 
196  /// Test if this is a NULL pointer
197  bool isNull() const
198  {
199  return !myHandle.myData;
200  }
201 
202  const Data &operator*() const
203  {
204  return *myHandle.myData;
205  }
206 
207  const Data *operator->() const
208  {
209  return myHandle.myData.get();
210  }
211  const Data *get() const
212  {
213  return myHandle.myData.get();
214  }
215 
216  int getRefCount() const
217  { return myHandle.getRefCount(); }
218 
219 private:
220  UT_COWHandle<Data> myHandle;
221 };
222 
223 ///
224 /// Transient Read Handles are simply accessors to the internal data of
225 /// the original handle. Unlike normal read handles, transient read
226 /// handles don't result in a tracked reference to the underlying data,
227 /// and so have lower overhead, but are unsafe to use outside the scope
228 /// of, or after any changes to, the original handle. Write handles will
229 /// not be aware of any active transient read handles, so errors in this
230 /// usage will not trigger assertions. In fact, no write handles to the
231 /// underlying data should exist during the entire scope of a transient
232 /// read handle.
233 ///
234 /// You are not allowed to edit the underlying data, so many read handles
235 /// may be sharing the same underlying data.
236 ///
237 template <typename Data>
239 {
240 public:
242  : myData(NULL)
243  {
244  }
245 
247  {
248  // Natural destructor suffices.
249  }
250 
252  : myData(src.myData)
253  {
254  }
255 
257  : myData (src.myData.get())
258  {
259  }
260 
263  {
264  myData = src.myData;
265  return *this;
266  }
267 
269  const UT_COWHandle<Data> &src)
270  {
271  // We can't verify in the UT_COWWriteHandle cast functions that
272  // transient read handles are released before we next try to
273  // access the write lock, so we verify that they're not being
274  // created while any write lock is active.
275  UT_ASSERT(!src.myWriteCount.relaxedLoad());
276  myData = src.myData.get();
277  return *this;
278  }
279 
280  /// Removes references, making this a null pointer
281  void resetHandle()
282  {
283  myData = 0;
284  }
285 
286  /// Test if this is a NULL pointer
287  bool isNull() const
288  {
289  return !myData;
290  }
291 
292  const Data &operator*() const
293  {
294  return *myData;
295  }
296 
297  const Data *operator->() const
298  {
299  return myData;
300  }
301  const Data *get() const
302  {
303  return myData;
304  }
305 
306 private:
307  const Data *myData;
308 };
309 
310 ///
311 /// A write handle can be thought of as a pointer to the actual
312 /// data. It allows you to modify the underlying data. To do this,
313 /// it will unique the plain-handle's data so no outstanding
314 /// readlocks will be affected by the writes.
315 ///
316 /// Building read handles while a write handle is active is valid
317 /// so long as no dereference occurs during the lifetime of the read
318 /// handle.
319 ///
320 template <typename Data>
321 class UT_COWWriteHandle
322 {
323 public:
325  {
326  myHandle = 0;
327  }
328 
330  {
331  unlock();
332  }
333 
335  {
336  myHandle = 0;
337  *this = src;
338  }
339 
341  {
342  myHandle = 0;
343  *this = src;
344  }
345 
346  /// Passing write handles by value is fine as the users understand
347  /// they all share the same underlying data, so is responsible
348  /// for thread safety, etc.
350  {
351  // Track our lock counts appropriately.
352  src.lock();
353  unlock();
354  myHandle = src.myHandle;
355 
356  return *this;
357  }
358 
359  /// Converting from a handle into a write handle can only be
360  /// done once. This prevents other threads or methods from
361  /// invalidating our uniqueness property.
362  /// Note we up case from a *pointer* to a UT_COWHandle, not from
363  /// a UT_COWHandle. This avoids people accidentally using an
364  /// temporary as the source and underlines that write handles
365  /// are like pointers while read handles are like values.
367  {
368  myHandle = src;
369 
370  if (src)
371  {
372  // Ensure we are the only copy.
373  src->makeUnique();
374  }
375 
376  lock();
377  return *this;
378  }
379 
380  /// Turns this into a null handle to drop references.
381  void resetHandle()
382  {
383  unlock();
384  myHandle = 0;
385  }
386 
387  /// Test if this is a NULL pointer
388  bool isNull() const
389  {
390  return !myHandle || !myHandle->myData;
391  }
392 
393  Data &operator*() const
394  {
395  if (myHandle)
396  {
397  // It is possible UT_COWReadHandles were created on
398  // our handle. This is fine as long as they are
399  // destroyed before we do our next write access.
400  UT_ASSERT(myHandle->myData.unique());
401  return *(myHandle->myData);
402  }
403  else
404  {
405  // As much of a crash as returning zero,
406  // but the compiler is happier.
407  // return *(0);
408  return *(myHandle->myData);
409  }
410  }
411 
412  Data *operator->() const
413  {
414  if (myHandle)
415  {
416  // It is possible UT_COWReadHandles were created on
417  // our handle. This is fine as long as they are
418  // destroyed before we do our next write access.
419  UT_ASSERT(myHandle->myData.unique());
420  return &*(myHandle->myData);
421  }
422  else
423  return (Data *)0;
424  }
425  Data *get() const
426  {
427  if (myHandle)
428  {
429  UT_ASSERT(myHandle->myData.unique());
430  return &*(myHandle->myData);
431  }
432  return nullptr;
433  }
434 
435  int getRefCount() const
436  { return myHandle->getRefCount(); }
437 
438 private:
439  void unlock() const
440  {
441  if (myHandle)
442  {
443  // Don't track reference counts on null arrays since
444  // they are safe to share.
445  if (!myHandle->myData)
446  return;
447  UT_ASSERT(myHandle->myWriteCount.relaxedLoad());
448  if (myHandle->myWriteCount.relaxedLoad())
449  myHandle->myWriteCount.add(-1);
450  }
451  }
452 
453  void lock() const
454  {
455  if (myHandle)
456  {
457  // Don't track reference counts on null arrays since
458  // they are safe to share.
459  if (!myHandle->myData)
460  return;
461  myHandle->myWriteCount.add(1);
462  }
463  }
464 
465  UT_COWHandle<Data> *myHandle;
466 };
467 
468 #include "UT_COW.C"
469 
470 #endif
471 
UT_COWWriteHandle(const UT_COWWriteHandle< Data > &src)
Definition: UT_COW.h:334
UT_COWTransientReadHandle(const UT_COWTransientReadHandle< Data > &src)
Definition: UT_COW.h:251
void steal(Data *src)
Definition: UT_COW.h:100
const UT_COWReadHandle< Data > & operator=(const UT_COWReadHandle< Data > &src)
Definition: UT_COW.h:174
const Data * get() const
Definition: UT_COW.h:301
Data & operator*() const
Definition: UT_COW.h:393
const UT_COWHandle< Data > & operator=(const UT_COWHandle< Data > &src)
Definition: UT_COW.h:69
void resetHandle()
Turns this into a null handle to drop references.
Definition: UT_COW.h:381
const Data & operator*() const
Definition: UT_COW.h:202
Data * operator->() const
Definition: UT_COW.h:412
UT_COWWriteHandle(UT_COWHandle< Data > *src)
Definition: UT_COW.h:340
int getRefCount() const
Returns the number of shared pointer references to the same Data.
Definition: UT_COW.h:115
UT_COWHandle()
Definition: UT_COW.h:51
void copy(const Data *src)
Definition: UT_COW.h:91
const UT_COWTransientReadHandle< Data > & operator=(const UT_COWHandle< Data > &src)
Definition: UT_COW.h:268
const UT_COWReadHandle< Data > & operator=(const UT_COWHandle< Data > &src)
Definition: UT_COW.h:180
UT_COWReadHandle(const UT_COWReadHandle< Data > &src)
Definition: UT_COW.h:164
std::shared_ptr< T > UT_SharedPtr
Wrapper around std::shared_ptr.
Definition: UT_SharedPtr.h:36
const Data * operator->() const
Definition: UT_COW.h:207
virtual ~UT_COWHandle()
Definition: UT_COW.h:63
const UT_COWWriteHandle< Data > & operator=(UT_COWHandle< Data > *src)
Definition: UT_COW.h:366
int getRefCount() const
Definition: UT_COW.h:435
void allocate()
Calls the default constructor on the object.
Definition: UT_COW.h:82
UT_COWReadHandle(const UT_COWHandle< Data > &src)
Definition: UT_COW.h:169
const Data & operator*() const
Definition: UT_COW.h:292
SYS_FORCE_INLINE T relaxedLoad() const
const Data * operator->() const
Definition: UT_COW.h:297
const UT_COWTransientReadHandle< Data > & operator=(const UT_COWTransientReadHandle< Data > &src)
Definition: UT_COW.h:261
UT_COWHandle(const UT_COWHandle< Data > &src)
Definition: UT_COW.h:56
const UT_COWWriteHandle< Data > & operator=(const UT_COWWriteHandle< Data > &src)
Definition: UT_COW.h:349
bool isNull() const
Test if this is a NULL pointer.
Definition: UT_COW.h:197
T add(T val)
Atomically adds val to myValue, returning the new value of myValue.
int getRefCount() const
Definition: UT_COW.h:216
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:156
void resetHandle()
Definition: UT_COW.h:108
UT_COWTransientReadHandle(const UT_COWHandle< Data > &src)
Definition: UT_COW.h:256
bool isNull() const
Test if this is a NULL pointer.
Definition: UT_COW.h:388
void resetHandle()
Removes references, making this a null pointer.
Definition: UT_COW.h:281
void resetHandle()
Removes references, making this a null pointer.
Definition: UT_COW.h:191
bool isNull() const
Test if this is a NULL pointer.
Definition: UT_COW.h:287
GLenum src
Definition: glcorearb.h:1793