HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
weakPtr.h
Go to the documentation of this file.
1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the terms set forth in the LICENSE.txt file available at
5 // https://openusd.org/license.
6 //
7 #ifndef PXR_BASE_TF_WEAK_PTR_H
8 #define PXR_BASE_TF_WEAK_PTR_H
9 
10 /// \file tf/weakPtr.h
11 /// \ingroup group_tf_Memory
12 /// Pointer storage with deletion detection.
13 
14 #include "pxr/pxr.h"
15 
16 #include "pxr/base/tf/nullPtr.h"
17 #include "pxr/base/tf/refPtr.h"
18 #include "pxr/base/tf/tf.h"
19 #include "pxr/base/tf/weakBase.h"
21 
22 #include <cstddef>
23 #include <type_traits>
24 
26 
27 class TfHash;
28 template <class U> class TfRefPtr;
29 template <class T> class TfWeakPtr;
30 
31 /// \class TfWeakPtr
32 /// \ingroup group_tf_Memory
33 ///
34 /// Pointer storage with deletion detection.
35 ///
36 /// <b>Overview</b>
37 ///
38 /// A \c TfWeakPtr is used to cache a pointer to an object; before
39 /// retrieving/using this pointer, one queries the \c TfWeakPtr object to
40 /// verify that the objected pointed to has not been deleted in the interim.
41 ///
42 /// \include test/weakPtr.cpp
43 ///
44 /// In the code above, if \c PossiblyDeleteLemur() deletes the object pointed
45 /// to by \c lemur, then the test \c if(lPtr) returns false. Otherwise, it is
46 /// safe to call a method on \c lPtr.
47 ///
48 /// To declare a \c TfWeakPtr<T>, the type \c T must publicly derive from \c
49 /// TfWeakBase.
50 ///
51 /// <b>Basic Use</b>
52 ///
53 /// A \c TfWeakPtr<T> can access \c T's public members by the \c -> operator
54 /// and can be dereferenced by the "\c *" operator.
55 ///
56 /// A \c TfWeakPtr converts to a \c true bool value (for example, in an \c if
57 /// statement) only if the pointer points to an unexpired object. Otherwise,
58 /// if the pointer was either initialized to NULL, or points to an expired
59 /// object, the test returns false.
60 ///
61 /// Occasionally, it is useful to distinguish between a \c TfWeakPtr being
62 /// explicitly initialized to NULL versus a \c TfWeakPtr whose object has
63 /// expired: the member function \c IsInvalid() returns \c true only if the
64 /// pointer points to an expired object.
65 ///
66 /// <b>Opaqueness</b>
67 ///
68 /// See the parallel discussion about these concepts in the documentation for
69 /// \c TfRefPtr; the same concepts apply.
70 ///
71 /// <b>Comparisons, Const and Non-Const, Inheritance and Casting</b>
72 ///
73 /// See the parallel discussion about these concepts in the documentation for
74 /// \c TfRefPtr; the same concepts apply.
75 ///
76 /// While it is possible to create TfWeakPtrs to const contents, we recommend
77 /// against it. TfCreateNonConstWeakPtr will always create a non-const weak
78 /// pointer even when passed a const argument (it casts away const).
79 ///
80 /// The recommendation against use of weak pointers to const content is due to
81 /// the fact that weak pointers cannot be implicitly cast for both inheritance
82 /// (derived to base) and const-ness (non-const to const) at the same time.
83 /// Because of this, using weak pointers to const content is most often much
84 /// more trouble than the benefit it gives. Therefore our policy is to not
85 /// use them.
86 ///
87 /// <b>Pointer Generality</b>
88 ///
89 /// While \c TfWeakPtr<TfWeakBase> is specifically forbidden (you cannot
90 /// construct this kind of object), you can assign any \c TfWeakPtr<T> to a \c
91 /// TfWeakPtr<void> or TfWeakPtr<const void>. The only thing you can do with
92 /// the latter is check to see if it points to an object that has expired.
93 /// You cannot manipulate the object itself (i.e. access its member
94 /// functions).
95 ///
96 /// This is useful when you need to watch for object expiration without being
97 /// bound by the type(s) of the objects you're watching. Similarly, you can
98 /// create a TfWeakPtr<void> from a \c TfWeakBase * using \c
99 /// TfCreateWeakPtr().
100 ///
101 /// <b>Performance</b>
102 ///
103 /// Deriving from \c TfWeakBase results in a single \c TfRefPtr variable being
104 /// added to a class, which is the size of a regular pointer. The cost of
105 /// deleting an object derived from \c TfWeakBase is an extra inline boolean
106 /// comparison, and possible decrement of a reference count if the object's
107 /// address was ever given out as a \c TfWeakPtr.
108 ///
109 /// The cost to create a \c TfWeakPtr is as follows: initial creation of the
110 /// pointer from a \c TfWeakBase object dynamically creates an object called a
111 /// \e remnant, whose size is that of two pointers. Subsequent transfers of
112 /// the same object's address to another \c TfWeakPtr merely bump a reference
113 /// count to the remnant. When all \c TfWeakPtrs to the object (and the object
114 /// itself) are destroyed, the remnant is deleted. An object can have a
115 /// remnant created and destroyed at most once, regardless of how many times
116 /// its address is given out in the form of a \c TfWeakPtr.
117 ///
118 /// Summarizing, the cost of guarding an object is a small amount of extra
119 /// space, and near-zero runtime cost if the guarding is never used. Even if
120 /// the guarding is used, the overhead at deletion time is minimal.
121 ///
122 /// The time to test if a \c TfWeakPtr is NULL, or to call a member function
123 /// through a \c TfWeakPtr is small, involving only a single inline boolean
124 /// comparison.
125 ///
126 template <class T>
127 class TfWeakPtr : public TfWeakPtrFacade<TfWeakPtr, T>
128 {
129 public:
130 
131  friend class TfWeakPtrFacadeAccess;
132  template <class U> friend class TfWeakPtr;
133 
134  template <class U> struct Rebind {
136  };
137 
138  TfWeakPtr() : _rawPtr(0) {}
139 
140  /// Construction, implicit conversion from TfNullPtr.
141  TfWeakPtr(TfNullPtrType) : _rawPtr(0) {}
142 
143  /// Construction, implicit conversion from nullptr.
144  TfWeakPtr(std::nullptr_t) : _rawPtr(nullptr) {}
145 
146  /// Copy construction
147  TfWeakPtr(TfWeakPtr const &p) = default;
148 
149  /// Move construction
150  TfWeakPtr(TfWeakPtr &&p) noexcept
151  : _rawPtr(p._rawPtr), _remnant(std::move(p._remnant)) {
152  p._rawPtr = nullptr;
153  }
154 
155  /// Conversion from \a RefPtr where \a U* is convertible to \a T* (this
156  /// pointer type).
157  template <class U>
159  typename std::enable_if<
161  >::type *dummy = 0) : _rawPtr(get_pointer(p))
162  {
163  TF_UNUSED(dummy);
164  if (ARCH_LIKELY(_rawPtr))
165  _remnant = Tf_WeakBaseAccess::
166  GetRemnant(_rawPtr->__GetTfWeakBase__());
167  }
168 
169  /// Explicitly construct from a raw pointer \a p.
170  template <class U>
171  explicit TfWeakPtr(U *p, typename std::enable_if<
172  std::is_convertible<U*, T*>::value>::type *dummy = nullptr) : _rawPtr(p)
173  {
174  TF_UNUSED(dummy);
175  if (ARCH_LIKELY(_rawPtr))
176  _remnant = Tf_WeakBaseAccess::
177  GetRemnant(_rawPtr->__GetTfWeakBase__());
178  }
179 
180  template <class U>
182  typename std::enable_if<
184  >::type *dummy = 0) : _rawPtr(p._rawPtr), _remnant(p._remnant)
185  {
186  }
187 
188  /// Copy assignment
189  TfWeakPtr &operator=(TfWeakPtr const &p) = default;
190 
191  /// Move assignment
192  TfWeakPtr &operator=(TfWeakPtr &&p) noexcept {
193  _rawPtr = p._rawPtr;
194  _remnant = std::move(p._remnant);
195  p._rawPtr = nullptr;
196  return *this;
197  }
198 
199  bool IsExpired() const {
200  return this->IsInvalid();
201  }
202 
203 private:
204 
205  T *_FetchPointer() const {
206  if (ARCH_LIKELY(_remnant && _remnant->_IsAlive()))
207  return _rawPtr;
208  return 0;
209  }
210 
211  bool _IsInvalid() const {
212  return _remnant && !_remnant->_IsAlive();
213  }
214 
215  void const *_GetUniqueIdentifier() const {
216  return _remnant ? _remnant->_GetUniqueIdentifier() : 0;
217  }
218 
219  void _EnableExtraNotification() const {
220  _remnant->EnableNotification();
221  }
222 
223  T *_rawPtr;
224  mutable TfRefPtr<Tf_Remnant> _remnant;
225 
226 };
227 
228 
229 template <class U>
231  return TfWeakPtr<U>(p);
232 }
233 
234 template <class U>
236  return TfWeakPtr<U>(const_cast<U *>(p));
237 }
238 
239 /// Thread-safe creation of a Tf ref pointer from a Tf weak pointer.
240 ///
241 /// This is thread-safe in the sense that the result will be either a ref
242 /// pointer to a live object with non-zero ref-count, or a NULL ref pointer.
243 /// However, this depends on the client to provide a guarantee to protect the
244 /// pointed-to object.
245 ///
246 /// Specifically, the caller must guarantee that the TfRefBase part of the
247 /// pointed-to object is not destroyed during this call. It is fine if the
248 /// destruction process for the object begins (due to the ref-count going to
249 /// zero as another thread drops the last ref) as long as the TfRefBase
250 /// portion is not destroyed. If object destruction begins because the
251 /// ref-count goes to zero before this call completes, this function will
252 /// reliably return a NULL ref pointer.
253 ///
254 /// Note that this is not a general mechanism for safely converting weak
255 /// pointers to ref pointers, because it relies on the type T to provide the
256 /// above guarantee.
257 ///
258 template <class T>
261  typedef typename TfRefPtr<T>::_Counter Counter;
262  if (T *rawPtr = get_pointer(p)) {
263  // Atomically increment the ref-count iff it's nonzero.
264  if (Counter::AddRefIfNonzero(rawPtr)) {
265  // There was at least 1 other ref at the time we acquired our ref,
266  // so this object is safe from destruction. Transfer ownership of
267  // the ref to a new TfRefPtr.
268  return TfCreateRefPtr(rawPtr);
269  }
270  // There were 0 refs to this object, so we know it is expiring and
271  // we cannot use it.
272  }
273  return TfNullPtr;
274 }
275 
276 
277 #if !defined(doxygen)
278 
279 //
280 // Allow TfWeakPtr<void> to be used simply for expiration checking.
281 //
282 template <>
283 class TfWeakPtr<void> {
284 public:
286  }
287 
288  template <class U>
290  : _remnant(wp._remnant) {
291  }
292 
293  template <template <class> class PtrTemplate, class Type>
295  : _remnant(_GetRemnant(wpf)) {
296  }
297 
298  template <class U>
301  _remnant = wp._remnant;
302  return *this;
303  }
304 
305  template <template <class> class PtrTemplate, class Type>
308  _remnant = _GetRemnant(wpf);
309  return *this;
310  }
311 
312  template <class U>
313  bool operator== (TfWeakPtr<U> const& wp) const {
314  return wp._remnant == _remnant;
315  }
316 
317  template <template <class> class PtrTemplate, class Type>
319  return _GetRemnant(wpf) == _remnant;
320  }
321 
322  template <class U>
323  bool operator!= (TfWeakPtr<U> const& wp) const {
324  return wp._remnant != _remnant;
325  }
326 
327  template <template <class> class PtrTemplate, class Type>
329  return _GetRemnant(wpf) != _remnant;
330  }
331 
332  template <class U>
333  bool operator< (TfWeakPtr<U> const& wp) {
334  return wp._remnant < _remnant;
335  }
336 
337  template <template <class> class PtrTemplate, class Type>
338  bool operator< (TfWeakPtrFacade<PtrTemplate, Type> const& wpf) {
339  return _GetRemnant(wpf) < _remnant;
340  }
341 
343 
344  operator UnspecifiedBoolType() const {
345  return (_remnant && _remnant->_IsAlive())
346  ? &TfWeakPtr::_remnant : nullptr;
347  }
348 
349  bool operator !() const {
350  return !bool(*this);
351  }
352 
353  bool IsExpired() const {
354  return _remnant && !_remnant->_IsAlive();
355  }
356 
357 private:
358  template <template <class> class PtrTemplate, class Type>
359  static TfRefPtr<Tf_Remnant>
360  _GetRemnant(TfWeakPtrFacade<PtrTemplate, Type> const& wpf) {
361  TfWeakBase const *weakBase = wpf.GetWeakBase();
362  if (ARCH_LIKELY(weakBase)) {
363  return Tf_WeakBaseAccess::GetRemnant(*weakBase);
364  }
365  return TfNullPtr;
366  }
367 
368 private:
369  TfRefPtr<Tf_Remnant> _remnant;
370 };
371 
372 #endif
373 
374 
375 //
376 // A mechanism to determine whether a class type has a method
377 // __GetTfWeakBase__ with the correct signature.
378 //
379 // _HasSig can only be called with a pointer-to-member-function that matches
380 // the desired signature of __GetTfWeakBase__.
381 //
382 // _Deduce has two possible overloads. The first overload's return value uses
383 // expression SFINAE to detect if a call to _HasSig(&T::__GetTfWeakBase__) is
384 // well-formed. If so, the overload's return type is the return type of
385 // _HasSig, specifically std::true_type. The second _Deduce overload returns
386 // std::false_type and is viable for all types.
387 //
388 template <class T>
390 {
391 private:
392 
393  // The required method signature of __GetTfWeakBase__ for implementations
394  // of the weak pointable interface.
395  template <class U>
396  using _SignatureOf__GetTfWeakBase__ = TfWeakBase const & (U::*)() const;
397 
398  template <class U>
399  static std::true_type
400  _HasSig(_SignatureOf__GetTfWeakBase__<U>);
401 
402  template <class U>
403  static decltype(_HasSig(&U::__GetTfWeakBase__))
404  _Deduce(U*);
405 
406  static std::false_type
407  _Deduce(...);
408 
409 public:
410  using type = decltype(_Deduce(static_cast<T*>(nullptr)));
411  using value_type = bool;
412  static const bool value = type::value;
413 };
414 
415 template <class T>
417 {
418  static const bool value =
420 };
421 
422 #define TF_SUPPORTS_WEAKPTR(T) (Tf_SupportsWeakPtr<T>::value)
423 #define TF_TRULY_SUPPORTS_WEAKPTR(T) std::is_base_of<TfWeakBase, T >::value
424 
425 #define TF_DECLARE_WEAK_POINTABLE_INTERFACE \
426  virtual TfWeakBase const &__GetTfWeakBase__() const = 0
427 
428 #define TF_IMPLEMENT_WEAK_POINTABLE_INTERFACE \
429  virtual TfWeakBase const &__GetTfWeakBase__() const { \
430  return *this; \
431  }
432 
434 
435 #endif // PXR_BASE_TF_WEAK_PTR_H
#define ARCH_LIKELY(x)
Definition: hints.h:29
TfRefPtr< T > TfCreateRefPtr(T *ptr)
Definition: refPtr.h:1190
TfRefPtr< T > TfCreateRefPtrFromProtectedWeakPtr(TfWeakPtr< T > const &p)
Definition: weakPtr.h:260
TfWeakPtr & operator=(TfWeakPtr const &p)=default
Copy assignment.
TfRefPtr< Tf_Remnant >(TfWeakPtr::*) UnspecifiedBoolType
Definition: weakPtr.h:342
bool operator==(PtrTemplate< Other > const &p) const
Definition: weakPtrFacade.h:84
bool operator!=(PtrTemplate< Other > const &p) const
Definition: weakPtrFacade.h:91
void
Definition: png.h:1083
decltype(_Deduce(static_cast< T * >(nullptr))) type
Definition: weakPtr.h:410
GLsizei const GLfloat * value
Definition: glcorearb.h:824
TF_API const TfNullPtrType TfNullPtr
TfWeakPtr(TfWeakPtrFacade< PtrTemplate, Type > const &wpf)
Definition: weakPtr.h:294
static TfRefPtr< Tf_Remnant > GetRemnant(TfWeakBase const &wb)
Definition: weakBase.h:195
TfWeakPtr(std::nullptr_t)
Construction, implicit conversion from nullptr.
Definition: weakPtr.h:144
TfWeakPtr()
Definition: weakPtr.h:138
OutGridT const XformOp bool bool
Y * get_pointer(TfWeakPtrFacade< X, Y > const &p)
Definition: weakPtrFacade.h:63
Definition: hash.h:472
DataType *(TfWeakPtrFacade::*)(void) const UnspecifiedBoolType
TfWeakPtr< U > Type
Definition: weakPtr.h:135
GLint GLint GLsizei GLint GLenum GLenum type
Definition: glcorearb.h:108
TfWeakPtr< U > TfCreateNonConstWeakPtr(U const *p)
Definition: weakPtr.h:235
TfWeakPtr(TfRefPtr< U > const &p, typename std::enable_if< std::is_convertible< U *, T * >::value >::type *dummy=0)
Definition: weakPtr.h:158
constexpr enabler dummy
An instance to use in EnableIf.
Definition: CLI11.h:985
bool IsExpired() const
Definition: weakPtr.h:353
virtual TF_API void const * _GetUniqueIdentifier() const
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1425
bool IsExpired() const
Definition: weakPtr.h:199
#define TF_UNUSED(x)
Definition: tf.h:168
bool _IsAlive() const
Definition: weakBase.h:41
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
TfWeakPtr(U *p, typename std::enable_if< std::is_convertible< U *, T * >::value >::type *dummy=nullptr)
Explicitly construct from a raw pointer p.
Definition: weakPtr.h:171
TfWeakPtr(TfNullPtrType)
Construction, implicit conversion from TfNullPtr.
Definition: weakPtr.h:141
TfWeakPtr(TfWeakPtr &&p) noexcept
Move construction.
Definition: weakPtr.h:150
TfWeakPtr & operator=(TfWeakPtr &&p) noexcept
Move assignment.
Definition: weakPtr.h:192
TfWeakPtr(TfWeakPtr< U > const &p, typename std::enable_if< std::is_convertible< U *, T * >::value >::type *dummy=0)
Definition: weakPtr.h:181
TfWeakBase const * GetWeakBase() const
virtual TF_API void EnableNotification() const
TfWeakPtr< U > TfCreateWeakPtr(U *p)
Definition: weakPtr.h:230
TfWeakPtr(TfWeakPtr< U > const &wp)
Definition: weakPtr.h:289