HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
weakBase.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_BASE_H
8 #define PXR_BASE_TF_WEAK_BASE_H
9 
10 /// \file tf/weakBase.h
11 /// \ingroup group_tf_Memory
12 
13 #include "pxr/pxr.h"
14 
15 #include "pxr/base/tf/api.h"
17 #include "pxr/base/tf/refPtr.h"
18 #include <atomic>
19 
21 
22 // The _Remnant structure is simply a persistent memory of an object's
23 // address. When the object dies, the pointer is set to NULL. A _Remnant
24 // object is destroyed when both the original whose address it was
25 // initialized with, and there are no weak pointers left pointing to that
26 // remnant.
28 {
29 public:
30 
31  TF_API virtual ~Tf_Remnant();
32 
33  void _Forget() {
34  _alive = false;
35 
36  if (_notify2)
38  }
39 
40  // Note that only "false" is of value in a multi-threaded world...
41  bool _IsAlive() const {
42  return _alive;
43  }
44 
45  // Must return an object's address whose lifetime is as long or longer than
46  // this object. Default implementation returns 'this'.
47  TF_API virtual void const *_GetUniqueIdentifier() const;
48 
49  // Note: this initializes a class member -- the parameter is a non-const
50  // reference.
52  Register(std::atomic<Tf_Remnant*> &remnantPtr) {
53  if (Tf_Remnant *remnant = remnantPtr.load()) {
54  // Remnant exists. Return additional reference.
55  return TfRefPtr<Tf_Remnant>(remnant);
56  } else {
57  // Allocate a remnant and attempt to register it.
58  return Register(remnantPtr, new Tf_Remnant);
59  }
60  }
61 
62  // Note: this initializes a class member -- the parameter is a non-const
63  // reference.
64  template <class T>
66  Register(std::atomic<Tf_Remnant*> &remnantPtr, T *candidate) {
67  Tf_Remnant *existing = nullptr;
68  if (remnantPtr.compare_exchange_strong(
69  existing,
70  static_cast<Tf_Remnant*>(candidate))) {
71  // Candidate registered. Return additional reference.
72  return TfRefPtr<Tf_Remnant>(candidate);
73  } else {
74  // Somebody beat us to it.
75  // Discard candidate and return additional reference.
76  delete candidate;
77  return TfRefPtr<Tf_Remnant>(existing);
78  }
79  }
80 
81  // Mark this remnant to call the expiry notification callback function when
82  // it dies. See ExpiryNotifier.h
83  TF_API virtual void EnableNotification() const;
84 
85 protected:
86  friend class TfWeakBase;
87 
89  : _notify(false),
90  _notify2(false),
91  _alive(true)
92  {
93  }
94 
95 private:
96 
97  mutable bool _notify, _notify2;
98  bool _alive;
99 };
100 
101 /// \class TfWeakBase
102 /// \ingroup group_tf_Memory
103 ///
104 /// Enable a concrete base class for use with \c TfWeakPtr.
105 ///
106 /// You should be familiar with the \c TfWeakPtr type before reading further.
107 ///
108 /// A class is enabled for use with the \c TfWeakPtr type by publicly deriving
109 /// from \c TfWeakBase. (Note that deriving from \c TfWeakBase adds data to a
110 /// structure, so the result is no longer a "pure" interface class.)
111 ///
112 /// For example,
113 /// \code
114 /// #include "pxr/base/tf/weakBase.h"
115 ///
116 /// class Simple : public TfWeakBase {
117 /// ...
118 /// };
119 /// \endcode
120 ///
121 /// Given the above inheritance, a \c Simple* can now be used to initialize an
122 /// object of type \c TfWeakPtr<Simple>.
123 ///
124 class TfWeakBase {
125 public:
126  TfWeakBase() : _remnantPtr(nullptr) {}
127 
128  TfWeakBase(const TfWeakBase&) : _remnantPtr(nullptr) {
129  // A newly created copy of a weak base doesn't start with a remnant
130  }
131 
132  // Don't call this method -- only for Tf internal use. The presence of this
133  // method is used by TfWeakPtr and related classes to determine whether a
134  // class may be pointed to by a TfWeakPtr. It is named nonstandardly to
135  // avoid any possible conflict with other names in derived classes.
136  const TfWeakBase& __GetTfWeakBase__() const {
137  return *this;
138  }
139 
141  // Do nothing. An assignment should NOT assign the other object's
142  // remnant and should NOT create a new remnant. We want to keep
143  // the one we already have (if any).
144  return *this;
145  }
146 
147  // Don't call this. Really.
148  void EnableNotification2() const;
149 
150  TF_API void const* GetUniqueIdentifier() const;
151 
152 protected:
153  /*
154  * Prohibit deletion through a TfWeakBase pointer.
155  */
156 
158  if (Tf_Remnant *remnant = _remnantPtr.load(std::memory_order_relaxed)) {
159  remnant->_Forget();
160  // Briefly forge a TfRefPtr to handle dropping our implied
161  // reference to the remnant.
162  TfRefPtr<Tf_Remnant> lastRef = TfCreateRefPtr(remnant);
163  }
164  }
165 
166  /*
167  * This needs to be atomic, for multithreading.
168  */
170  return Tf_Remnant::Register(_remnantPtr);
171  }
172 
173  template <class T>
174  TfRefPtr<Tf_Remnant> _Register(T *tempRmnt) const {
175  return Tf_Remnant::Register<T>(_remnantPtr, tempRmnt);
176  }
177 
178  bool _HasRemnant() const {
179  return _remnantPtr.load(std::memory_order_relaxed) ? true : false;
180  }
181 
182 private:
183 
184  // XXX Conceptually this plays the same role as a TfRefPtr to the
185  // Tf_Remnant, in the sense that we want TfWeakBase to participate
186  // in the ref-counted lifetime tracking of its remnant.
187  // However, we require atomic initialization of this pointer.
188  mutable std::atomic<Tf_Remnant*> _remnantPtr;
189 
190  friend class Tf_WeakBaseAccess;
191 };
192 
194 public:
196  return wb._Register();
197  }
198 private:
200 };
201 
203 
204 #endif // PXR_BASE_TF_WEAK_BASE_H
TfRefPtr< T > TfCreateRefPtr(T *ptr)
Definition: refPtr.h:1190
virtual TF_API ~Tf_Remnant()
#define TF_API
Definition: api.h:23
TfRefPtr< Tf_Remnant > _Register(T *tempRmnt) const
Definition: weakBase.h:174
bool _HasRemnant() const
Definition: weakBase.h:178
const TfWeakBase & operator=(const TfWeakBase &)
Definition: weakBase.h:140
static TfRefPtr< Tf_Remnant > GetRemnant(TfWeakBase const &wb)
Definition: weakBase.h:195
const TfWeakBase & __GetTfWeakBase__() const
Definition: weakBase.h:136
TfWeakBase(const TfWeakBase &)
Definition: weakBase.h:128
void EnableNotification2() const
static TfRefPtr< Tf_Remnant > Register(std::atomic< Tf_Remnant * > &remnantPtr)
Definition: weakBase.h:52
static TF_API void Invoke2(void const *p)
Tf_Remnant()
Definition: weakBase.h:88
~TfWeakBase()
Definition: weakBase.h:157
virtual TF_API void const * _GetUniqueIdentifier() const
TfWeakBase()
Definition: weakBase.h:126
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1425
static TfRefPtr< Tf_Remnant > Register(std::atomic< Tf_Remnant * > &remnantPtr, T *candidate)
Definition: weakBase.h:66
bool _IsAlive() const
Definition: weakBase.h:41
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
TfRefPtr< Tf_Remnant > _Register() const
Definition: weakBase.h:169
virtual TF_API void EnableNotification() const
TF_API void const * GetUniqueIdentifier() const
void _Forget()
Definition: weakBase.h:33