HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros 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. It provides a level of indirection so that
10  * the underlying GU_Detail may be deleted or changed
11  * without those interested in the GU_Detail having to tell.
12  * It also provides write/read lock tests to allow memory
13  * managers to tell what is safe to be deleted.
14  */
15 
16 #ifndef __GU_DetailHandle__
17 #define __GU_DetailHandle__
18 
19 #include "GU_API.h"
20 #include <SYS/SYS_Math.h>
21 #include <UT/UT_NonCopyable.h>
22 #include <GA/GA_Types.h>
23 
24 class GU_Detail;
25 class GU_DetailHandleRef;
26 
27 /// A GU_DetailHandle is designed to allow arms length references to
28 /// GU_Details. The underlying GU_Detail can be deleted or swapped
29 /// and things which use the GU_DetailHandle will properly be notified.
30 /// Further, it provides access control to the GU_Detail, ensuring multiple
31 /// entities do not write to it at once. This is currently used to ensure
32 /// deletion is not performed on active GU_Details. Eventually it could
33 /// be used for multi-threaded support.
34 /// NOTE: The locks are not enforced.
36 {
37 public:
39  GU_DetailHandle(const GU_DetailHandle &handle);
41 
42  ~GU_DetailHandle();
43 
44  void clear();
45 
46  /// This method will duplicate the geometry associated with the handle,
47  /// returning a new handle.
48  GU_DetailHandle duplicateGeometry(GA_DataIdStrategy data_id_strategy = GA_DATA_ID_BUMP) const;
49 
50  GU_DetailHandle &operator=(const GU_DetailHandle &handle);
51  GU_DetailHandle &operator=(GU_DetailHandle &&handle);
52 
53  bool operator==(const GU_DetailHandle &handle) const;
54  bool operator!=(const GU_DetailHandle &handle) const;
55 
56  /// Compute a hash based on myHandle. This is not on the contents
57  /// of the gdp!
58  uint hash() const { return SYSpointerHash(myHandle); }
59 
60 
61  /// Ensures this is the only handle referring to the underlying
62  /// geometry, ie, getRefCount() == 1. A no-op if the geometry
63  /// is already unique, otherwise invokes duplicateGeometry().
64  void makeUnique(GA_DataIdStrategy data_id_strategy = GA_DATA_ID_BUMP);
65  bool isUnique() const { return getRefCount() <= 1; }
66 
67  /// Unlocked readable & writeable pointers.
68  /// If acquiring a write pointer, it is expected one will ensure uniqueness
69  /// prior to acquiring it.
70  GU_Detail *gdpNC();
71  const GU_Detail *gdp() const;
72 
73  /// peekDetail does no locking. Thus, it should be avoided unless
74  /// the goal is just to test if the GU_Detail is present. This
75  /// is largely provided for supporting old code in hackish situations.
76  const GU_Detail *peekDetail() const;
77 
78  /// This will acquire a read lock on the GU_Detail. The result is 0
79  /// if no lock can be acquired, or no underlying detail exists.
80  /// The returned detail should be passed to unlock(). (Technically,
81  /// no locking occurs on error, but unlock is a no-op with a 0 gdp)
82  const GU_Detail *readLock();
83 
84  /// This will acquire a write lock on the GU_Detail. The result is 0
85  /// if no lock can be acquired, or no underlying detail is present.
86  /// The returned detail should be passed to unlock() when finished.
87  /// There can only be one active write lock at a time. Do not destroy
88  /// or modify the pointer itself and expect the unlock to update
89  /// the GU_Detail *. Instead, use one of the delete or change functions.
90  /// No readlocks or write locks can be active for this to work.
91  GU_Detail *writeLock();
92 
93  /// This will unlock one layer of locking.
94  /// If the passed in gdp is null, no unlocking occurs.
95  /// Otherwise, the passed in gdp is asserted to match the one
96  /// which myHandle points to.
97  void unlock(const GU_Detail *gdp);
98 
99  /// Create a new underlying reference & set it to point to the
100  /// given gdp.
101  /// The own flag determines if the GU_Detail will be deleted by
102  /// the handle system when the underlying reference is deleted.
103  void allocateAndSet(GU_Detail *gdp, bool own=true);
104 
105  /// Deletes the underlying gdp and sets the gdp pointer to be null.
106  /// It returns true if the gdp was successfully deleted, false if not.
107  /// Failure likely results from a lock being present.
108  bool deleteGdp();
109 
110  /// Determines if anyone has a lock on this handle.
111  bool hasActiveLock() const;
112 
113  /// Determine if this is a null handle. This means it
114  /// points to a null handle, or the handle's gdp is null.
115  bool isNull() const;
116 
117  /// Determine if this is a valid handle (!isNull())
118  bool isValid() const { return !isNull(); }
119 
120  /// Safe-bool operator to return whether the handle is valid
121  SYS_SAFE_BOOL operator bool() const { return isValid(); }
122 
123  /// Returns the number of references made to the base handle.
124  int getRefCount() const;
125 
126  /// Returns the number of locks made to the base handle for debugging.
127  int getLockCount() const;
128 
129  /// Preserve Requests:
130  /// A preserve request is a request that people create a new
131  /// GU_DetailHandle rather than editting the current one. It
132  /// is used by SOPs to determine if it is safe to do an in place
133  /// cook.
134  void addPreserveRequest();
135  void removePreserveRequest();
136  int getPreserveRequest() const;
137 
138  /// External references should not block unload requests at the SOP
139  /// level. Normally if any external GU_DetailHandles still refer
140  /// to the handle, unloading is prevented.
141  void addExternalReference();
142  void removeExternalReference();
143  int getExternalReference() const;
144 
145  /// Return the amount of memory owned by the GU_DetailHandle itself,
146  /// *NOT* the detail. This will count the memory of the GU_DetailHandleRef,
147  /// which could be shared, so only the definitive "original" handle
148  /// should be counted, e.g. the one on SOP_Node.
149  int64 getMemoryUsage(bool inclusive) const;
150 
151 private:
152  /// This changes the underlying gdp of the handle. The old
153  /// gdp is returned. This fails if there are any locks on the gdp, and so
154  /// it should never be called.
155  GU_Detail *setGdp(GU_Detail *gdp);
156 
157  GU_DetailHandleRef *myHandle;
158 };
159 
160 /// A GU_ConstDetailHandle uses a GU_DetailHandle to provide const-only
161 /// access to a GU_Detail. It uses a GU_DetailHandle member variable to
162 /// do all the actual work, and simply hides any functionality that is
163 /// unsafe or inappropriate for a const GU_Detail.
165 {
166 public:
168  { }
170  { myDetailHandle = handle; }
171 
173  {
174  myDetailHandle = handle;
175  return *this;
176  }
177 
178  bool operator==(const GU_ConstDetailHandle &handle) const
179  { return myDetailHandle == handle.myDetailHandle; }
180  bool operator!=(const GU_ConstDetailHandle &handle) const
181  { return myDetailHandle != handle.myDetailHandle; }
182 
183  uint hash() const { return myDetailHandle.hash(); }
184 
185  void clear()
186  { myDetailHandle.clear(); }
187 
188  /// This method casts from a GU_ConstDetailHandle to a GU_DetailHandle.
189  /// Use it carefully. Calling getWriteableCopy() is preferred.
191  { return myDetailHandle; }
192 
193  /// Create a writeable copy of the detail
195  { return myDetailHandle.duplicateGeometry(); }
196 
197  /// Unlocked readable pointers.
198  const GU_Detail *gdp() const { return myDetailHandle.gdp(); }
199 
200  /// This will acquire a read lock on the GU_Detail. The result is 0
201  /// if no lock can be acquired, or no underlying detail exists.
202  /// The returned detail should be passed to unlock(). (Technically,
203  /// no locking occurs on error, but unlock is a no-op with a 0 gdp)
205  { return myDetailHandle.readLock(); }
206 
207  /// This will unlock one layer of locking.
208  /// If the passed in gdp is null, no unlocking occurs.
209  /// Otherwise, the passed in gdp is asserted to match the one
210  /// which myHandle points to.
211  void unlock(const GU_Detail *gdp)
212  { myDetailHandle.unlock(gdp); }
213 
214  /// Determine if this is a null handle. This means it
215  /// points to a null handle, or the handle's gdp is null.
216  bool isNull() const
217  { return myDetailHandle.isNull(); }
218  /// Check if this is a valid handle.
219  bool isValid() const
220  { return myDetailHandle.isValid(); }
221 
222  /// Safe-bool operator to return whether the handle is valid
223  SYS_SAFE_BOOL operator bool() const { return isValid(); }
224 
225  /// Returns the number of references made to the base handle.
226  int getRefCount() const
227  { return myDetailHandle.getRefCount(); }
228 
229  /// Returns the number of locks made to the base handle for debugging.
230  int getLockCount() const
231  { return myDetailHandle.getLockCount(); }
232 
233  /// Preserve Requests:
234  /// A preserve request is a request that people create a new
235  /// GU_DetailHandle rather than editting the current one. It
236  /// is used by SOPs to determine if it is safe to do an in place
237  /// cook.
239  { myDetailHandle.addPreserveRequest(); }
241  { myDetailHandle.removePreserveRequest(); }
242  int getPreserveRequest() const
243  { return myDetailHandle.getPreserveRequest(); }
244 
245  /// Return the amount of memory owned by the GU_DetailHandle itself,
246  /// *NOT* the detail. This will count the memory of the GU_DetailHandleRef,
247  /// which could be shared, so only the definitive "original" handle
248  /// should be counted, e.g. the one on SOP_Node.
249  int64 getMemoryUsage(bool inclusive) const
250  { return myDetailHandle.getMemoryUsage(inclusive); }
251 
252 private:
253  GU_DetailHandle myDetailHandle;
254 };
255 
256 /// GU_DetalHandleAutoFOOLock is a utility class to allow the easy extraction
257 /// of const GU_Detail * from GU_DetailHandles. It uses the C++ scoping
258 /// mechanism to make the locking & unlocking transparent to the caller.
259 /// One can thus do:
260 /// GU_DetailHandleAutoFOOLock gdl(sop->getCookedGeo())
261 /// const GU_Detail *gdp = gdl.getGdp();
262 /// The FOO = Read returns const GU_Details and does a read lock.
263 /// The FOO = Write returns non-const GU_Details and does a write lock.
264 ///
265 class
267 {
268 public:
270  {
271  myHandle = handle;
272  myGdp = myHandle.readLock();
273  }
275  {
276  myHandle = handle;
277  myGdp = myHandle.readLock();
278  }
280  {
281  myHandle.unlock(myGdp);
282  }
283 
284  bool isValid() const { return myGdp != 0; }
285  const GU_Detail *getGdp() const { return myGdp; }
286  const GU_ConstDetailHandle &handle() const { return myHandle; }
287  const GU_Detail *operator->() const { return myGdp; }
288  const GU_Detail &operator*() const { return *myGdp; }
289 
290  /// Safe-bool operator to return whether the handle is valid
291  SYS_SAFE_BOOL operator bool() const { return isValid(); }
292 
293 private:
294  GU_ConstDetailHandle myHandle;
295  const GU_Detail *myGdp;
296 };
297 
298 class
300 {
301 public:
303  {
304  myHandle = handle;
305  myGdp = myHandle.writeLock();
306  }
308  {
309  myHandle.unlock(myGdp);
310  }
311 
312  bool isValid() const { return myGdp != 0; }
313  GU_Detail *getGdp() const { return myGdp; }
314  GU_Detail *operator->() const { return myGdp; }
315  GU_Detail &operator*() const { return *myGdp; }
316  const GU_DetailHandle &handle() const { return myHandle; }
317 
318  /// Safe-bool operator to return whether the handle is valid
319  SYS_SAFE_BOOL operator bool() const { return isValid(); }
320 
321 private:
322  GU_DetailHandle myHandle;
323  GU_Detail *myGdp;
324 };
325 
326 #endif
GU_Detail * getGdp() const
GU_Detail * writeLock()
GU_DetailHandle getWriteableCopy() const
Create a writeable copy of the detail.
int getLockCount() const
Returns the number of locks made to the base handle for debugging.
const GU_DetailHandle & handle() const
bool isValid() const
Determine if this is a valid handle (!isNull())
GA_DataIdStrategy
Definition: GA_Types.h:186
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)
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.
long long int64
Definition: SYS_Types.h:100
const GU_ConstDetailHandle & handle() const
GU_Detail * operator->() const
#define SYS_SAFE_BOOL
Definition: SYS_Compiler.h:56
bool operator!=(const GU_ConstDetailHandle &handle) const
void unlock(const GU_Detail *gdp)
#define GU_API
Definition: GU_API.h:11
unsigned int uint
Definition: SYS_Types.h:33
int getPreserveRequest() const
uint hash() const
const GU_Detail * operator->() const
bool operator==(const GU_ConstDetailHandle &handle) const
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
const GU_Detail * getGdp() const
const GU_ConstDetailHandle & operator=(const GU_DetailHandle &handle)
bool isValid() const
Check if this is a valid handle.