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