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