This document is for a version of USD that is under development. See this page for the current release.
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.