HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GU_DetailHandle.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: GU_DetailHandle.h ( GU Library, C++)
7  *
8  * COMMENTS: A detail handle is used to maintain a reference to a
9  * GU_Detail. In most cases Copy-on-Write semantics are
10  * expected - you are only write to a detail if you are
11  * the sole owner.
12  * SOPs, for historical reasons, re-uses handles in place
13  * ignoring the uniqueness. To force SOPs to respect
14  * the COW properties the PreserveReferenceCount must be
15  * non-zero.
16  *
17  */
18 
19 #ifndef __GU_DetailHandle__
20 #define __GU_DetailHandle__
21 
22 #include "GU_API.h"
23 #include <GA/GA_Types.h>
24 #include <UT/UT_NonCopyable.h>
25 #include <UT/UT_VectorTypes.h>
26 #include <SYS/SYS_Math.h>
27 #include <SYS/SYS_PointerHash.h>
28 
29 #include <new>
30 
31 class GU_Detail;
32 class GU_DetailHandleRef;
33 
34 /// A GU_DetailHandle is designed to allow arms length references to
35 /// GU_Details. It acts as a shared pointer that ensures life time
36 /// of GU_Details will be properly preserved.
37 /// Further, it provides access control to the GU_Detail, ensuring multiple
38 /// entities do not write to it at once.
39 ///
40 /// NOTE: The locking methods are historical accidents and are not enforced
41 /// nor encouraged.
43 {
44 public:
46  GU_DetailHandle(const GU_DetailHandle &handle);
48 
49  ~GU_DetailHandle();
50 
51  void clear();
52 
53  /// This method will duplicate the geometry associated with the handle,
54  /// returning a new handle.
55  GU_DetailHandle duplicateGeometry(GA_DataIdStrategy data_id_strategy = GA_DATA_ID_BUMP) const;
56 
59 
60  bool operator==(const GU_DetailHandle &handle) const;
61  bool operator!=(const GU_DetailHandle &handle) const;
62 
63  /// Compute a hash based on myHandle. This is not on the contents
64  /// of the gdp!
65  uint hash() const { return SYSpointerHash(myHandle); }
66 
67 
68  /// Ensures this is the only handle referring to the underlying
69  /// geometry, ie, getRefCount() == 1. A no-op if the geometry
70  /// is already unique, otherwise invokes duplicateGeometry().
71  /// For most applications, you should only modify handles that
72  /// you know are unique to avoid editing geometry stored in caches.
73  void makeUnique(GA_DataIdStrategy data_id_strategy = GA_DATA_ID_BUMP);
74  bool isUnique() const { return getRefCount() <= 1; }
75 
76  /// Readable & writeable pointers.
77  /// If acquiring a write pointer, it is expected one will ensure uniqueness
78  /// prior to acquiring it.
79  GU_Detail *gdpNC();
80  const GU_Detail *gdp() const;
81 
82  /// Equivalent to gdp(), peekDetail is left over from when
83  /// locking was considered important.
84  const GU_Detail *peekDetail() const;
85 
86  /// Create a new underlying reference & set it to point to the
87  /// given gdp.
88  /// The own flag determines if the GU_Detail will be deleted by
89  /// the handle system when the underlying reference is deleted.
90  void allocateAndSet(GU_Detail *gdp, bool own=true);
91 
92  /// Deletes the underlying gdp and sets the gdp pointer to be null.
93  /// It returns true if the gdp was successfully deleted, false if not.
94  /// Failure likely results from a lock being present.
95  bool deleteGdp();
96 
97  /// Determine if this is a null handle. This means it
98  /// points to a null handle, or the handle's gdp is null.
99  bool isNull() const;
100 
101  /// Determine if this is a valid handle (!isNull())
102  bool isValid() const { return !isNull(); }
103 
104  /// Safe-bool operator to return whether the handle is valid
105  SYS_SAFE_BOOL operator bool() const { return isValid(); }
106 
107  /// Returns the number of references made to the base handle.
108  int getRefCount() const;
109 
110  /// Preserve Requests:
111  /// A preserve request is a request that people create a new
112  /// GU_DetailHandle rather than editting the current one. It
113  /// is used by SOPs to determine if it is safe to do an in place
114  /// cook.
115  /// Anything outside of SOPs should always respect uniqueness instead.
116  /// If storing a handle that comes from SOPs, adding a preserve
117  /// request will stop SOPs from re-using it.
118  void addPreserveRequest();
119  void removePreserveRequest();
120  int getPreserveRequest() const;
121 
122  /// External references should not block unload requests at the SOP
123  /// level. Normally if any external GU_DetailHandles still refer
124  /// to the handle, unloading is prevented.
125  void addExternalReference();
126  void removeExternalReference();
127  int getExternalReference() const;
128 
129  /// Return the amount of memory owned by the GU_DetailHandle itself,
130  /// *NOT* the detail. This will count the memory of the GU_DetailHandleRef,
131  /// which could be shared, so only the definitive "original" handle
132  /// should be counted, e.g. the one on SOP_Node.
133  int64 getMemoryUsage(bool inclusive) const;
134 
135  /// NOTE: Locking is not enforced, and no longer encouraged.
136  /// This will acquire a read lock on the GU_Detail. The result is 0
137  /// if no lock can be acquired, or no underlying detail exists.
138  /// The returned detail should be passed to unlock(). (Technically,
139  /// no locking occurs on error, but unlock is a no-op with a 0 gdp)
140  const GU_Detail *readLock();
141 
142  /// NOTE: Locking is not enforced, and no longer encouraged.
143  /// This will acquire a write lock on the GU_Detail. The result is 0
144  /// if no lock can be acquired, or no underlying detail is present.
145  /// The returned detail should be passed to unlock() when finished.
146  /// There can only be one active write lock at a time. Do not destroy
147  /// or modify the pointer itself and expect the unlock to update
148  /// the GU_Detail *. Instead, use one of the delete or change functions.
149  /// No readlocks or write locks can be active for this to work.
150  GU_Detail *writeLock();
151 
152  /// NOTE: Locking is not enforced, and no longer encouraged.
153  /// This will unlock one layer of locking.
154  /// If the passed in gdp is null, no unlocking occurs.
155  /// Otherwise, the passed in gdp is asserted to match the one
156  /// which myHandle points to.
157  void unlock(const GU_Detail *gdp);
158 
159  /// NOTE: Locking is not enforced, and no longer encouraged.
160  /// Determines if anyone has a lock on this handle.
161  bool hasActiveLock() const;
162 
163  /// NOTE: Locking is not enforced, and no longer encouraged.
164  /// Returns the number of locks made to the base handle for debugging.
165  int getLockCount() const;
166 
167 private:
168  /// This changes the underlying gdp of the handle. The old
169  /// gdp is returned. This fails if there are any locks on the gdp, and so
170  /// it should never be called.
171  GU_Detail *setGdp(GU_Detail *gdp);
172 
173  GU_DetailHandleRef *myHandle;
174 };
175 
176 /// A GU_ConstDetailHandle uses a GU_DetailHandle to provide const-only
177 /// access to a GU_Detail. It uses a GU_DetailHandle member variable to
178 /// do all the actual work, and simply hides any functionality that is
179 /// unsafe or inappropriate for a const GU_Detail.
181 {
182 public:
184  { }
186  { myDetailHandle = handle; }
187 
189  {
190  myDetailHandle = handle;
191  return *this;
192  }
193 
194  bool operator==(const GU_ConstDetailHandle &handle) const
195  { return myDetailHandle == handle.myDetailHandle; }
196  bool operator!=(const GU_ConstDetailHandle &handle) const
197  { return myDetailHandle != handle.myDetailHandle; }
198 
199  uint hash() const { return myDetailHandle.hash(); }
200 
201  void clear()
202  { myDetailHandle.clear(); }
203 
204  /// This method casts from a GU_ConstDetailHandle to a GU_DetailHandle.
205  /// Use it carefully. Calling getWriteableCopy() is preferred.
206  /// Duplicating geometry is not as expensive as it might seem.
208  { return myDetailHandle; }
209 
210  /// Create a writeable copy of the detail
212  { return myDetailHandle.duplicateGeometry(data_id_strategy); }
213 
214  /// Unlocked readable pointers.
215  const GU_Detail *gdp() const { return myDetailHandle.gdp(); }
216 
217  /// Determine if this is a null handle. This means it
218  /// points to a null handle, or the handle's gdp is null.
219  bool isNull() const
220  { return myDetailHandle.isNull(); }
221  /// Check if this is a valid handle.
222  bool isValid() const
223  { return myDetailHandle.isValid(); }
224 
225  /// Safe-bool operator to return whether the handle is valid
226  SYS_SAFE_BOOL operator bool() const { return isValid(); }
227 
228  /// Returns the number of references made to the base handle.
229  int getRefCount() const
230  { return myDetailHandle.getRefCount(); }
231 
232  /// Preserve Requests:
233  /// A preserve request is a request that people create a new
234  /// GU_DetailHandle rather than editting the current one. It
235  /// is used by SOPs to determine if it is safe to do an in place
236  /// cook.
238  { myDetailHandle.addPreserveRequest(); }
240  { myDetailHandle.removePreserveRequest(); }
241  int getPreserveRequest() const
242  { return myDetailHandle.getPreserveRequest(); }
243 
244  /// Return the amount of memory owned by the GU_DetailHandle itself,
245  /// *NOT* the detail. This will count the memory of the GU_DetailHandleRef,
246  /// which could be shared, so only the definitive "original" handle
247  /// should be counted, e.g. the one on SOP_Node.
248  int64 getMemoryUsage(bool inclusive) const
249  { return myDetailHandle.getMemoryUsage(inclusive); }
250 
251  /// NOTE: Locking is not enforced, and no longer encouraged.
252  /// This will acquire a read lock on the GU_Detail. The result is 0
253  /// if no lock can be acquired, or no underlying detail exists.
254  /// The returned detail should be passed to unlock(). (Technically,
255  /// no locking occurs on error, but unlock is a no-op with a 0 gdp)
257  { return myDetailHandle.readLock(); }
258 
259  /// NOTE: Locking is not enforced, and no longer encouraged.
260  /// This will unlock one layer of locking.
261  /// If the passed in gdp is null, no unlocking occurs.
262  /// Otherwise, the passed in gdp is asserted to match the one
263  /// which myHandle points to.
264  void unlock(const GU_Detail *gdp)
265  { myDetailHandle.unlock(gdp); }
266 
267  /// NOTE: Locking is not enforced, and no longer encouraged.
268  /// Returns the number of locks made to the base handle for debugging.
269  int getLockCount() const
270  { return myDetailHandle.getLockCount(); }
271 
272  /// Ramp registration to allow geometry to be converted
273  /// to integers across HOM boundaries.
274 
275  /// Registers & returns the handle, adding the handle to the registered
276  /// list
277  static int registerGeometry(GU_ConstDetailHandle gdh, UT_IntArray &registered);
278  /// Unregister all layers corresponding to the provided list,
279  /// erase the list afterwards. Assertion if handle wasn't regsitered
280  static void unregisterGeometries(UT_IntArray &registered);
281  /// Look up a registered layer by handle.
282  static GU_ConstDetailHandle lookupGeometry(int handle);
283 
284 private:
285  GU_DetailHandle myDetailHandle;
286 };
287 
288 /// NOTE: Locking is no longer encouraged, and never was enforced.
289 /// Use .gdp() instead.
290 ///
291 /// GU_DetalHandleAutoFOOLock is a utility class to allow the easy extraction
292 /// of const GU_Detail * from GU_DetailHandles. It uses the C++ scoping
293 /// mechanism to make the locking & unlocking transparent to the caller.
294 /// One can thus do:
295 /// GU_DetailHandleAutoFOOLock gdl(sop->getCookedGeo())
296 /// const GU_Detail *gdp = gdl.getGdp();
297 /// The FOO = Read returns const GU_Details and does a read lock.
298 /// The FOO = Write returns non-const GU_Details and does a write lock.
299 ///
300 class
302 {
303 public:
305  {
306  myHandle = handle;
307  myGdp = myHandle.readLock();
308  }
310  {
311  myHandle = handle;
312  myGdp = myHandle.readLock();
313  }
315  {
316  myHandle.unlock(myGdp);
317  }
318 
319  bool isValid() const { return myGdp != 0; }
320  const GU_Detail *getGdp() const { return myGdp; }
321  const GU_ConstDetailHandle &handle() const { return myHandle; }
322  const GU_Detail *operator->() const { return myGdp; }
323  const GU_Detail &operator*() const { UT_ASSERT_P(myGdp); return *myGdp; }
324 
325  /// Safe-bool operator to return whether the handle is valid
326  SYS_SAFE_BOOL operator bool() const { return isValid(); }
327 
328 private:
329  GU_ConstDetailHandle myHandle;
330  const GU_Detail *myGdp;
331 };
332 
333 /// NOTE: Locking is no longer encouraged, and never was enforced.
334 /// Use .gdpNC() instead (after ensuring uniqueness)
335 class
337 {
338 public:
340  {
341  myHandle = handle;
342  myGdp = myHandle.writeLock();
343  }
345  {
346  myHandle.unlock(myGdp);
347  }
348 
349  bool isValid() const { return myGdp != 0; }
350  GU_Detail *getGdp() const { return myGdp; }
351  GU_Detail *operator->() const { return myGdp; }
352  GU_Detail &operator*() const { UT_ASSERT_P(myGdp); return *myGdp; }
353  const GU_DetailHandle &handle() const { return myHandle; }
354 
355  /// Safe-bool operator to return whether the handle is valid
356  SYS_SAFE_BOOL operator bool() const { return isValid(); }
357 
358 private:
359  GU_DetailHandle myHandle;
360  GU_Detail *myGdp;
361 };
362 
363 namespace UT
364 {
365 template <typename T> struct DefaultClearer;
366 
367 template <>
369 {
370  static void clear(GU_DetailHandle &v)
371  {
372  v.clear();
373  }
374 
375  static bool isClear(const GU_DetailHandle &v)
376  {
377  return !v.isValid();
378  }
379 
381  {
382  new ((void *)p) GU_DetailHandle();
383  }
384 
385  static const bool clearNeedsDestruction = false;
386 };
387 
388 template <>
390 {
392  {
393  v.clear();
394  }
395 
396  static bool isClear(const GU_ConstDetailHandle &v)
397  {
398  return !v.isValid();
399  }
400 
402  {
403  new ((void *)p) GU_ConstDetailHandle();
404  }
405 
406  static const bool clearNeedsDestruction = false;
407 };
408 
409 } // namespace UT
410 
411 #endif
GU_Detail * getGdp() const
GU_Detail * writeLock()
int getLockCount() const
const GU_DetailHandle & handle() const
bool isValid() const
Determine if this is a valid handle (!isNull())
GA_DataIdStrategy
Definition: GA_Types.h:211
const GLdouble * v
Definition: glcorearb.h:837
GU_DetailHandle castAwayConst() const
const GU_Detail * readLock()
const GU_Detail * readLock()
int64 getMemoryUsage(bool inclusive) const
GU_ConstDetailHandle(const GU_DetailHandle &handle)
GU_DetailHandleAutoWriteLock(const GU_DetailHandle &handle)
GU_DetailHandleAutoReadLock(const GU_ConstDetailHandle &handle)
static void clearConstruct(GU_DetailHandle *p)
GU_Detail & operator*() const
OutGridT const XformOp bool bool
GU_DetailHandle duplicateGeometry(GA_DataIdStrategy data_id_strategy=GA_DATA_ID_BUMP) const
const GU_Detail * gdp() const
Unlocked readable pointers.
bool operator==(const BaseDimensions< T > &a, const BaseDimensions< Y > &b)
Definition: Dimensions.h:137
int getRefCount() const
Returns the number of references made to the base handle.
const GU_ConstDetailHandle & handle() const
GU_Detail * operator->() const
static void clearConstruct(GU_ConstDetailHandle *p)
#define SYS_SAFE_BOOL
Definition: SYS_Compiler.h:55
#define UT_ASSERT_P(ZZ)
Definition: UT_Assert.h:155
bool operator!=(const GU_ConstDetailHandle &handle) const
long long int64
Definition: SYS_Types.h:116
void unlock(const GU_Detail *gdp)
static bool isClear(const GU_DetailHandle &v)
static bool isClear(const GU_ConstDetailHandle &v)
#define GU_API
Definition: GU_API.h:14
static void clear(GU_ConstDetailHandle &v)
int getPreserveRequest() const
uint hash() const
static void clear(GU_DetailHandle &v)
const GU_Detail * operator->() const
LeafData & operator=(const LeafData &)=delete
bool operator==(const GU_ConstDetailHandle &handle) const
GU_DetailHandle getWriteableCopy(GA_DataIdStrategy data_id_strategy=GA_DATA_ID_BUMP) const
Create a writeable copy of the detail.
const GU_Detail & operator*() const
GU_DetailHandleAutoReadLock(const GU_DetailHandle &handle)
bool operator!=(const BaseDimensions< T > &a, const BaseDimensions< Y > &b)
Definition: Dimensions.h:165
bool isUnique() const
unsigned int uint
Definition: SYS_Types.h:45
const GU_Detail * getGdp() const
const GU_ConstDetailHandle & operator=(const GU_DetailHandle &handle)
bool isValid() const
Check if this is a valid handle.