Loading...
Searching...
No Matches
weakBase.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_BASE_H
25#define PXR_BASE_TF_WEAK_BASE_H
26
29
30#include "pxr/pxr.h"
31
32#include "pxr/base/tf/api.h"
34#include "pxr/base/tf/refPtr.h"
35#include <atomic>
36
37PXR_NAMESPACE_OPEN_SCOPE
38
39// The _Remnant structure is simply a persistent memory of an object's
40// address. When the object dies, the pointer is set to NULL. A _Remnant
41// object is destroyed when both the original whose address it was
42// initialized with, and there are no weak pointers left pointing to that
43// remnant.
44class Tf_Remnant : public TfSimpleRefBase
45{
46public:
47
48 TF_API virtual ~Tf_Remnant();
49
50 void _Forget() {
51 _alive = false;
52
53 if (_notify2)
54 Tf_ExpiryNotifier::Invoke2(this);
55 }
56
57 // Note that only "false" is of value in a multi-threaded world...
58 bool _IsAlive() const {
59 return _alive;
60 }
61
62 // Must return an object's address whose lifetime is as long or longer than
63 // this object. Default implementation returns 'this'.
64 TF_API virtual void const *_GetUniqueIdentifier() const;
65
66 // Note: this initializes a class member -- the parameter is a non-const
67 // reference.
69 Register(std::atomic<Tf_Remnant*> &remnantPtr) {
70 if (Tf_Remnant *remnant = remnantPtr.load()) {
71 // Remnant exists. Return additional reference.
72 return TfRefPtr<Tf_Remnant>(remnant);
73 } else {
74 // Allocate a remnant and attempt to register it.
75 return Register(remnantPtr, new Tf_Remnant);
76 }
77 }
78
79 // Note: this initializes a class member -- the parameter is a non-const
80 // reference.
81 template <class T>
83 Register(std::atomic<Tf_Remnant*> &remnantPtr, T *candidate) {
84 Tf_Remnant *existing = nullptr;
85 if (remnantPtr.compare_exchange_strong(
86 existing,
87 static_cast<Tf_Remnant*>(candidate))) {
88 // Candidate registered. Return additional reference.
89 return TfRefPtr<Tf_Remnant>(candidate);
90 } else {
91 // Somebody beat us to it.
92 // Discard candidate and return additional reference.
93 delete candidate;
94 return TfRefPtr<Tf_Remnant>(existing);
95 }
96 }
97
98 // Mark this remnant to call the expiry notification callback function when
99 // it dies. See ExpiryNotifier.h
100 TF_API virtual void EnableNotification() const;
101
102protected:
103 friend class TfWeakBase;
104
105 Tf_Remnant()
106 : _notify(false),
107 _notify2(false),
108 _alive(true)
109 {
110 }
111
112private:
113
114 mutable bool _notify, _notify2;
115 bool _alive;
116};
117
142public:
143 TfWeakBase() : _remnantPtr(nullptr) {}
144
145 TfWeakBase(const TfWeakBase&) : _remnantPtr(nullptr) {
146 // A newly created copy of a weak base doesn't start with a remnant
147 }
148
149 // Don't call this method -- only for Tf internal use. The presence of this
150 // method is used by TfWeakPtr and related classes to determine whether a
151 // class may be pointed to by a TfWeakPtr. It is named nonstandardly to
152 // avoid any possible conflict with other names in derived classes.
153 const TfWeakBase& __GetTfWeakBase__() const {
154 return *this;
155 }
156
157 const TfWeakBase& operator= (const TfWeakBase&) {
158 // Do nothing. An assignment should NOT assign the other object's
159 // remnant and should NOT create a new remnant. We want to keep
160 // the one we already have (if any).
161 return *this;
162 }
163
164 // Don't call this. Really.
165 void EnableNotification2() const;
166
167 TF_API void const* GetUniqueIdentifier() const;
168
169protected:
170 /*
171 * Prohibit deletion through a TfWeakBase pointer.
172 */
173
174 ~TfWeakBase() {
175 if (Tf_Remnant *remnant = _remnantPtr.load(std::memory_order_relaxed)) {
176 remnant->_Forget();
177 // Briefly forge a TfRefPtr to handle dropping our implied
178 // reference to the remnant.
179 TfRefPtr<Tf_Remnant> lastRef = TfCreateRefPtr(remnant);
180 }
181 }
182
183 /*
184 * This needs to be atomic, for multithreading.
185 */
186 TfRefPtr<Tf_Remnant> _Register() const {
187 return Tf_Remnant::Register(_remnantPtr);
188 }
189
190 template <class T>
191 TfRefPtr<Tf_Remnant> _Register(T *tempRmnt) const {
192 return Tf_Remnant::Register<T>(_remnantPtr, tempRmnt);
193 }
194
195 bool _HasRemnant() const {
196 return _remnantPtr.load(std::memory_order_relaxed) ? true : false;
197 }
198
199private:
200
201 // XXX Conceptually this plays the same role as a TfRefPtr to the
202 // Tf_Remnant, in the sense that we want TfWeakBase to participate
203 // in the ref-counted lifetime tracking of its remnant.
204 // However, we require atomic initialization of this pointer.
205 mutable std::atomic<Tf_Remnant*> _remnantPtr;
206
207 friend class Tf_WeakBaseAccess;
208};
209
210class Tf_WeakBaseAccess {
211public:
212 static TfRefPtr<Tf_Remnant> GetRemnant(TfWeakBase const &wb) {
213 return wb._Register();
214 }
215private:
216 Tf_WeakBaseAccess();
217};
218
219PXR_NAMESPACE_CLOSE_SCOPE
220
221#endif // PXR_BASE_TF_WEAK_BASE_H
Reference-counted smart pointer utility class.
Definition: refPtr.h:601
Enable a concrete base class for use with TfRefPtr that inhibits the "unique changed" facility of TfR...
Definition: refBase.h:156
Enable a concrete base class for use with TfWeakPtr.
Definition: weakBase.h:141
Reference counting.