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 <SYS/SYS_Math.h>
24 #include <UT/UT_NonCopyable.h>
25 #include <GA/GA_Types.h>
26 
27 class GU_Detail;
28 class GU_DetailHandleRef;
29 
30 /// A GU_DetailHandle is designed to allow arms length references to
31 /// GU_Details. It acts as a shared pointer that ensures life time
32 /// of GU_Details will be properly preserved.
33 /// Further, it provides access control to the GU_Detail, ensuring multiple
34 /// entities do not write to it at once.
35 ///
36 /// NOTE: The locking methods are historical accidents and are not enforced
37 /// nor encouraged.
39 {
40 public:
44 
45  ~GU_DetailHandle();
46 
47  void clear();
48 
49  /// This method will duplicate the geometry associated with the handle,
50  /// returning a new handle.
51  GU_DetailHandle duplicateGeometry(GA_DataIdStrategy data_id_strategy = GA_DATA_ID_BUMP) const;
52 
53  GU_DetailHandle &operator=(const GU_DetailHandle &handle);
54  GU_DetailHandle &operator=(GU_DetailHandle &&handle);
55 
56  bool operator==(const GU_DetailHandle &handle) const;
57  bool operator!=(const GU_DetailHandle &handle) const;
58 
59  /// Compute a hash based on myHandle. This is not on the contents
60  /// of the gdp!
61  uint hash() const { return SYSpointerHash(myHandle); }
62 
63 
64  /// Ensures this is the only handle referring to the underlying
65  /// geometry, ie, getRefCount() == 1. A no-op if the geometry
66  /// is already unique, otherwise invokes duplicateGeometry().
67  /// For most applications, you should only modify handles that
68  /// you know are unique to avoid editing geometry stored in caches.
69  void makeUnique(GA_DataIdStrategy data_id_strategy = GA_DATA_ID_BUMP);
70  bool isUnique() const { return getRefCount() <= 1; }
71 
72  /// Readable & writeable pointers.
73  /// If acquiring a write pointer, it is expected one will ensure uniqueness
74  /// prior to acquiring it.
75  GU_Detail *gdpNC();
76  const GU_Detail *gdp() const;
77 
78  /// Equivalent to gdp(), peekDetail is left over from when
79  /// locking was considered important.
80  const GU_Detail *peekDetail() const;
81 
82  /// Create a new underlying reference & set it to point to the
83  /// given gdp.
84  /// The own flag determines if the GU_Detail will be deleted by
85  /// the handle system when the underlying reference is deleted.
86  void allocateAndSet(GU_Detail *gdp, bool own=true);
87 
88  /// Deletes the underlying gdp and sets the gdp pointer to be null.
89  /// It returns true if the gdp was successfully deleted, false if not.
90  /// Failure likely results from a lock being present.
91  bool deleteGdp();
92 
93  /// Determine if this is a null handle. This means it
94  /// points to a null handle, or the handle's gdp is null.
95  bool isNull() const;
96 
97  /// Determine if this is a valid handle (!isNull())
98  bool isValid() const { return !isNull(); }
99 
100  /// Safe-bool operator to return whether the handle is valid
101  SYS_SAFE_BOOL operator bool() const { return isValid(); }
102 
103  /// Returns the number of references made to the base handle.
104  int getRefCount() const;
105 
106  /// Preserve Requests:
107  /// A preserve request is a request that people create a new
108  /// GU_DetailHandle rather than editting the current one. It
109  /// is used by SOPs to determine if it is safe to do an in place
110  /// cook.
111  /// Anything outside of SOPs should always respect uniqueness instead.
112  /// If storing a handle that comes from SOPs, adding a preserve
113  /// request will stop SOPs from re-using it.
114  void addPreserveRequest();
115  void removePreserveRequest();
116  int getPreserveRequest() const;
117 
118  /// External references should not block unload requests at the SOP
119  /// level. Normally if any external GU_DetailHandles still refer
120  /// to the handle, unloading is prevented.
121  void addExternalReference();
122  void removeExternalReference();
123  int getExternalReference() const;
124 
125  /// Return the amount of memory owned by the GU_DetailHandle itself,
126  /// *NOT* the detail. This will count the memory of the GU_DetailHandleRef,
127  /// which could be shared, so only the definitive "original" handle
128  /// should be counted, e.g. the one on SOP_Node.
129  int64 getMemoryUsage(bool inclusive) const;
130 
131  /// NOTE: Locking is not enforced, and no longer encouraged.
132  /// This will acquire a read lock on the GU_Detail. The result is 0
133  /// if no lock can be acquired, or no underlying detail exists.
134  /// The returned detail should be passed to unlock(). (Technically,
135  /// no locking occurs on error, but unlock is a no-op with a 0 gdp)
136  const GU_Detail *readLock();
137 
138  /// NOTE: Locking is not enforced, and no longer encouraged.
139  /// This will acquire a write lock on the GU_Detail. The result is 0
140  /// if no lock can be acquired, or no underlying detail is present.
141  /// The returned detail should be passed to unlock() when finished.
142  /// There can only be one active write lock at a time. Do not destroy
143  /// or modify the pointer itself and expect the unlock to update
144  /// the GU_Detail *. Instead, use one of the delete or change functions.
145  /// No readlocks or write locks can be active for this to work.
146  GU_Detail *writeLock();
147 
148  /// NOTE: Locking is not enforced, and no longer encouraged.
149  /// This will unlock one layer of locking.
150  /// If the passed in gdp is null, no unlocking occurs.
151  /// Otherwise, the passed in gdp is asserted to match the one
152  /// which myHandle points to.
153  void unlock(const GU_Detail *gdp);
154 
155  /// NOTE: Locking is not enforced, and no longer encouraged.
156  /// Determines if anyone has a lock on this handle.
157  bool hasActiveLock() const;
158 
159  /// NOTE: Locking is not enforced, and no longer encouraged.
160  /// Returns the number of locks made to the base handle for debugging.
161  int getLockCount() const;
162 
163 private:
164  /// This changes the underlying gdp of the handle. The old
165  /// gdp is returned. This fails if there are any locks on the gdp, and so
166  /// it should never be called.
167  GU_Detail *setGdp(GU_Detail *gdp);
168 
169  GU_DetailHandleRef *myHandle;
170 };
171 
172 /// A GU_ConstDetailHandle uses a GU_DetailHandle to provide const-only
173 /// access to a GU_Detail. It uses a GU_DetailHandle member variable to
174 /// do all the actual work, and simply hides any functionality that is
175 /// unsafe or inappropriate for a const GU_Detail.
177 {
178 public:
180  { }
182  { myDetailHandle = handle; }
183 
185  {
186  myDetailHandle = handle;
187  return *this;
188  }
189 
191  { return myDetailHandle == handle.myDetailHandle; }
193  { return myDetailHandle != handle.myDetailHandle; }
194 
195  uint hash() const { return myDetailHandle.hash(); }
196 
197  void clear()
198  { myDetailHandle.clear(); }
199 
200  /// This method casts from a GU_ConstDetailHandle to a GU_DetailHandle.
201  /// Use it carefully. Calling getWriteableCopy() is preferred.
202  /// Duplicating geometry is not as expensive as it might seem.
204  { return myDetailHandle; }
205 
206  /// Create a writeable copy of the detail
208  { return myDetailHandle.duplicateGeometry(data_id_strategy); }
209 
210  /// Unlocked readable pointers.
211  const GU_Detail *gdp() const { return myDetailHandle.gdp(); }
212 
213  /// Determine if this is a null handle. This means it
214  /// points to a null handle, or the handle's gdp is null.
215  bool isNull() const
216  { return myDetailHandle.isNull(); }
217  /// Check if this is a valid handle.
218  bool isValid() const
219  { return myDetailHandle.isValid(); }
220 
221  /// Safe-bool operator to return whether the handle is valid
222  SYS_SAFE_BOOL operator bool() const { return isValid(); }
223 
224  /// Returns the number of references made to the base handle.
225  int getRefCount() const
226  { return myDetailHandle.getRefCount(); }
227 
228  /// Preserve Requests:
229  /// A preserve request is a request that people create a new
230  /// GU_DetailHandle rather than editting the current one. It
231  /// is used by SOPs to determine if it is safe to do an in place
232  /// cook.
234  { myDetailHandle.addPreserveRequest(); }
236  { myDetailHandle.removePreserveRequest(); }
237  int getPreserveRequest() const
238  { return myDetailHandle.getPreserveRequest(); }
239 
240  /// Return the amount of memory owned by the GU_DetailHandle itself,
241  /// *NOT* the detail. This will count the memory of the GU_DetailHandleRef,
242  /// which could be shared, so only the definitive "original" handle
243  /// should be counted, e.g. the one on SOP_Node.
244  int64 getMemoryUsage(bool inclusive) const
245  { return myDetailHandle.getMemoryUsage(inclusive); }
246 
247  /// NOTE: Locking is not enforced, and no longer encouraged.
248  /// This will acquire a read lock on the GU_Detail. The result is 0
249  /// if no lock can be acquired, or no underlying detail exists.
250  /// The returned detail should be passed to unlock(). (Technically,
251  /// no locking occurs on error, but unlock is a no-op with a 0 gdp)
253  { return myDetailHandle.readLock(); }
254 
255  /// NOTE: Locking is not enforced, and no longer encouraged.
256  /// This will unlock one layer of locking.
257  /// If the passed in gdp is null, no unlocking occurs.
258  /// Otherwise, the passed in gdp is asserted to match the one
259  /// which myHandle points to.
260  void unlock(const GU_Detail *gdp)
261  { myDetailHandle.unlock(gdp); }
262 
263  /// NOTE: Locking is not enforced, and no longer encouraged.
264  /// Returns the number of locks made to the base handle for debugging.
265  int getLockCount() const
266  { return myDetailHandle.getLockCount(); }
267 
268 private:
269  GU_DetailHandle myDetailHandle;
270 };
271 
272 /// NOTE: Locking is no longer encouraged, and never was enforced.
273 /// Use .gdp() instead.
274 ///
275 /// GU_DetalHandleAutoFOOLock is a utility class to allow the easy extraction
276 /// of const GU_Detail * from GU_DetailHandles. It uses the C++ scoping
277 /// mechanism to make the locking & unlocking transparent to the caller.
278 /// One can thus do:
279 /// GU_DetailHandleAutoFOOLock gdl(sop->getCookedGeo())
280 /// const GU_Detail *gdp = gdl.getGdp();
281 /// The FOO = Read returns const GU_Details and does a read lock.
282 /// The FOO = Write returns non-const GU_Details and does a write lock.
283 ///
284 class
286 {
287 public:
289  {
290  myHandle = handle;
291  myGdp = myHandle.readLock();
292  }
294  {
295  myHandle = handle;
296  myGdp = myHandle.readLock();
297  }
299  {
300  myHandle.unlock(myGdp);
301  }
302 
303  bool isValid() const { return myGdp != 0; }
304  const GU_Detail *getGdp() const { return myGdp; }
305  const GU_ConstDetailHandle &handle() const { return myHandle; }
306  const GU_Detail *operator->() const { return myGdp; }
307  const GU_Detail &operator*() const { UT_ASSERT_P(myGdp); return *myGdp; }
308 
309  /// Safe-bool operator to return whether the handle is valid
310  SYS_SAFE_BOOL operator bool() const { return isValid(); }
311 
312 private:
313  GU_ConstDetailHandle myHandle;
314  const GU_Detail *myGdp;
315 };
316 
317 /// NOTE: Locking is no longer encouraged, and never was enforced.
318 /// Use .gdpNC() instead (after ensuring uniqueness)
319 class
321 {
322 public:
324  {
325  myHandle = handle;
326  myGdp = myHandle.writeLock();
327  }
329  {
330  myHandle.unlock(myGdp);
331  }
332 
333  bool isValid() const { return myGdp != 0; }
334  GU_Detail *getGdp() const { return myGdp; }
335  GU_Detail *operator->() const { return myGdp; }
336  GU_Detail &operator*() const { UT_ASSERT_P(myGdp); return *myGdp; }
337  const GU_DetailHandle &handle() const { return myHandle; }
338 
339  /// Safe-bool operator to return whether the handle is valid
340  SYS_SAFE_BOOL operator bool() const { return isValid(); }
341 
342 private:
343  GU_DetailHandle myHandle;
344  GU_Detail *myGdp;
345 };
346 
347 #endif
GU_Detail * getGdp() const
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:210
GU_DetailHandle castAwayConst() const
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)
GU_Detail & operator*() const
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
#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)
#define GU_API
Definition: GU_API.h:14
int getPreserveRequest() const
uint hash() const
const GU_Detail * operator->() const
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.