All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules 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
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
20PXR_NAMESPACE_OPEN_SCOPE
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.
27class Tf_Remnant : public TfSimpleRefBase
28{
29public:
30
31 TF_API virtual ~Tf_Remnant();
32
33 void _Forget() {
34 _alive = false;
35
36 if (_notify2)
37 Tf_ExpiryNotifier::Invoke2(this);
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
85protected:
86 friend class TfWeakBase;
87
88 Tf_Remnant()
89 : _notify(false),
90 _notify2(false),
91 _alive(true)
92 {
93 }
94
95private:
96
97 mutable bool _notify, _notify2;
98 bool _alive;
99};
100
125public:
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
140 const TfWeakBase& operator= (const TfWeakBase&) {
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
152protected:
153 /*
154 * Prohibit deletion through a TfWeakBase pointer.
155 */
156
157 ~TfWeakBase() {
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 */
169 TfRefPtr<Tf_Remnant> _Register() const {
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
182private:
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
193class Tf_WeakBaseAccess {
194public:
195 static TfRefPtr<Tf_Remnant> GetRemnant(TfWeakBase const &wb) {
196 return wb._Register();
197 }
198private:
199 Tf_WeakBaseAccess();
200};
201
202PXR_NAMESPACE_CLOSE_SCOPE
203
204#endif // PXR_BASE_TF_WEAK_BASE_H
Reference-counted smart pointer utility class.
Definition: refPtr.h:590
Enable a concrete base class for use with TfRefPtr that inhibits the "unique changed" facility of TfR...
Definition: refBase.h:139
Enable a concrete base class for use with TfWeakPtr.
Definition: weakBase.h:124
Reference counting.