Panda3D
Loading...
Searching...
No Matches
referenceCount.I
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file referenceCount.I
10 * @author drose
11 * @date 1998-10-23
12 */
13
14template<class Base>
15TypeHandle RefCountProxy<Base>::_type_handle;
16
17template<class Base>
18TypeHandle RefCountObj<Base>::_type_handle;
19
20/**
21 * The ReferenceCount constructor is protected because you almost never want
22 * to create just a ReferenceCount object by itself, and it's probably a
23 * mistake if you try.
24 *
25 * ReferenceCount doesn't store any useful information in its own right; its
26 * only purpose is to add reference-counting to some other class via
27 * inheritance.
28 */
29INLINE ReferenceCount::
30ReferenceCount() {
31 _weak_list = nullptr;
32 _ref_count = 0;
33#ifdef DO_MEMORY_USAGE
35#endif
36}
37
38/**
39 * The copies of reference-counted objects do not themselves inherit the
40 * reference count!
41 *
42 * This copy constructor is protected because you almost never want to create
43 * just a ReferenceCount object by itself, and it's probably a mistake if you
44 * try.
45 */
46INLINE ReferenceCount::
47ReferenceCount(const ReferenceCount &) {
48 _weak_list = nullptr;
49 _ref_count = 0;
50#ifdef DO_MEMORY_USAGE
52#endif
53}
54
55/**
56 * The copies of reference-counted objects do not themselves inherit the
57 * reference count!
58 *
59 * This copy assignment operator is protected because you almost never want to
60 * copy just a ReferenceCount object by itself, and it's probably a mistake if
61 * you try. Instead, this should only be called from a derived class that
62 * implements this operator and then calls up the inheritance chain.
63 */
64INLINE void ReferenceCount::
65operator = (const ReferenceCount &) {
66 // If this assertion fails, our own pointer was recently deleted. Possibly
67 // you used a real pointer instead of a PointerTo at some point, and the
68 // object was deleted when the PointerTo went out of scope. Maybe you tried
69 // to create an automatic (local variable) instance of a class that derives
70 // from ReferenceCount. Or maybe your headers are out of sync, and you need
71 // to make clean in direct or some higher tree.
72 nassertv(_ref_count != deleted_ref_count);
73}
74
75/**
76 *
77 */
78ReferenceCount::
79~ReferenceCount() {
80 TAU_PROFILE("ReferenceCount::~ReferenceCount()", " ", TAU_USER);
81 // If this assertion fails, we're trying to delete an object that was just
82 // deleted. Possibly you used a real pointer instead of a PointerTo at some
83 // point, and the object was deleted when the PointerTo went out of scope.
84 // Maybe you tried to create an automatic (local variable) instance of a
85 // class that derives from ReferenceCount. Or maybe your headers are out of
86 // sync, and you need to make clean in direct or some higher tree.
87 nassertv(_ref_count != deleted_ref_count);
88
89 // If this assertion fails, we're trying to delete a static object that
90 // still has an outstanding reference count. You should make sure that all
91 // references to your static objects are gone by the time the object itself
92 // destructs.
93 nassertv(_ref_count <= local_ref_count);
94
95 // If this assertion fails, the reference counts are all screwed up
96 // altogether. Maybe some errant code stomped all over memory somewhere.
97 nassertv(_ref_count >= 0);
98
99 // If this assertion fails, someone tried to delete this object while its
100 // reference count was still positive. Maybe you tried to point a PointerTo
101 // at a static object (a local variable, instead of one allocated via new)?
102 // The test below against 0x7f is supposed to check for that, but it's a
103 // pretty hokey test.
104
105 // Another possibility is you inadvertently omitted a copy constructor for a
106 // ReferenceCount object, and then bitwise copied a dynamically allocated
107 // value--reference count and all--onto a locally allocated one.
108 nassertv(_ref_count == 0 || _ref_count == local_ref_count);
109
110 // Tell our weak reference holders that we're going away now.
111 if (_weak_list != nullptr) {
112 ((WeakReferenceList *)_weak_list)->mark_deleted();
113 _weak_list = nullptr;
114 }
115
116#ifndef NDEBUG
117 // Ok, all clear to delete. Now set the reference count to
118 // deleted_ref_count, so we'll have a better chance of noticing if we happen
119 // to have a stray pointer to it still out there.
120 _ref_count = deleted_ref_count;
121#endif
122
123#ifdef DO_MEMORY_USAGE
125#endif
126}
127
128/**
129 * Returns the current reference count.
130 */
131INLINE int ReferenceCount::
132get_ref_count() const {
133#ifdef _DEBUG
135#endif
136 return (int)AtomicAdjust::get(_ref_count);
137}
138
139/**
140 * Explicitly increments the reference count. User code should avoid using
141 * ref() and unref() directly, which can result in missed reference counts.
142 * Instead, let a PointerTo object manage the reference counting
143 * automatically.
144 *
145 * This function is const, even though it changes the object, because
146 * generally fiddling with an object's reference count isn't considered part
147 * of fiddling with the object. An object might be const in other ways, but
148 * we still need to accurately count the number of references to it.
149 */
151ref() const {
152 TAU_PROFILE("void ReferenceCount::ref()", " ", TAU_USER);
153#ifdef _DEBUG
154 nassertv(test_ref_count_integrity());
155#endif
156
157 AtomicAdjust::inc(_ref_count);
158}
159
160/**
161 * Explicitly decrements the reference count. Note that the object will not
162 * be implicitly deleted by unref() simply because the reference count drops
163 * to zero. (Having a member function delete itself is problematic.) However,
164 * see the helper function unref_delete().
165 *
166 * User code should avoid using ref() and unref() directly, which can result
167 * in missed reference counts. Instead, let a PointerTo object manage the
168 * reference counting automatically.
169 *
170 * This function is const, even though it changes the object, because
171 * generally fiddling with an object's reference count isn't considered part
172 * of fiddling with the object. An object might be const in other ways, but
173 * we still need to accurately count the number of references to it.
174 *
175 * The return value is true if the new reference count is nonzero, false if it
176 * is zero.
177 */
179unref() const {
180 TAU_PROFILE("void ReferenceCount::unref()", " ", TAU_USER);
181#ifdef _DEBUG
182 nassertr(test_ref_count_integrity(), 0);
183
184 // If this assertion fails, you tried to unref an object with a zero
185 // reference count. Are you using ref() and unref() directly? Are you sure
186 // you can't use PointerTo's?
187 nassertr(_ref_count > 0, 0);
188#endif
189 return AtomicAdjust::dec(_ref_count);
190}
191
192/**
193 * Does some easy checks to make sure that the reference count isn't
194 * completely bogus. Returns true if ok, false otherwise.
195 */
198#ifndef NDEBUG
199 return do_test_ref_count_integrity();
200#else
201 return true;
202#endif
203}
204
205/**
206 * Does some easy checks to make sure that the reference count isn't zero, or
207 * completely bogus. Returns true if ok, false otherwise.
208 */
211#ifndef NDEBUG
212 return do_test_ref_count_nonzero();
213#else
214 return true;
215#endif
216}
217
218/**
219 * This function should be called, once, immediately after creating a new
220 * instance of some ReferenceCount-derived object on the stack.
221 *
222 * This allows the object to be passed to functions that will increment and
223 * decrement the object's reference count temporarily, and it will prevent the
224 * object from being deleted (inappropriately), when the reference count
225 * returns to zero. It actually achieves this by setting a large positive
226 * value in the reference count field.
227 */
229local_object() {
230 // If this assertion fails, you didn't call this immediately after creating
231 // a local object.
232 nassertv(_ref_count == 0);
233
234 _ref_count = local_ref_count;
235}
236
237/**
238 * Returns true if this particular ReferenceCount object has a
239 * WeakReferenceList created, false otherwise. In general, this will be true
240 * if there was ever a WeakPointerTo created for this object (even if there is
241 * not any for it now).
242 */
244has_weak_list() const {
245 return _weak_list != nullptr;
246}
247
248/**
249 * Returns the WeakReferenceList associated with this ReferenceCount object.
250 * If there has never been a WeakReferenceList associated with this object,
251 * creates one now.
252 *
253 * The returned object will be deleted automatically when all weak and strong
254 * references to the object have gone.
255 */
257get_weak_list() const {
258 if (AtomicAdjust::get_ptr(_weak_list) == nullptr) {
259 ((ReferenceCount *)this)->create_weak_list();
260 }
261 return (WeakReferenceList *)AtomicAdjust::get_ptr(_weak_list);
262}
263
264/**
265 * Adds the indicated PointerToVoid as a weak reference to this object.
266 * Returns an object that will persist as long as any reference (strong or
267 * weak) exists, for calling unref() or checking whether the object still
268 * exists.
269 */
271weak_ref() {
272 TAU_PROFILE("void ReferenceCount::weak_ref()", " ", TAU_USER);
273#ifdef _DEBUG
274 nassertr(test_ref_count_integrity(), nullptr);
275#else
276 nassertr(_ref_count != deleted_ref_count, nullptr);
277#endif
279 weak_ref->ref();
280 return weak_ref;
281}
282
283/**
284 * Removes the indicated PointerToVoid as a weak reference to this object. It
285 * must have previously been added via a call to weak_ref().
286 */
288weak_unref() {
289 TAU_PROFILE("void ReferenceCount::weak_unref()", " ", TAU_USER);
290#ifdef _DEBUG
291 nassertv(test_ref_count_integrity());
292#endif
293 WeakReferenceList *weak_list = (WeakReferenceList *)_weak_list;
294 nassertv(weak_list != nullptr);
295 bool nonzero = weak_list->unref();
296 nassertv(nonzero);
297}
298
299/**
300 * Atomically increases the reference count of this object if it is not zero.
301 * Do not use this. This exists only to implement a special case for weak
302 * pointers.
303 * @return true if the reference count was incremented, false if it was zero.
304 */
306ref_if_nonzero() const {
307#ifdef _DEBUG
309#endif
310 AtomicAdjust::Integer ref_count;
311 do {
312 ref_count = AtomicAdjust::get(_ref_count);
313 if (ref_count <= 0) {
314 return false;
315 }
316 } while (ref_count != AtomicAdjust::compare_and_exchange(_ref_count, ref_count, ref_count + 1));
317 return true;
318}
319
320/**
321 * Atomically decreases the reference count of this object if it is one.
322 * Do not use this. This exists only to implement a special case with the
323 * state cache.
324 * @return false if the reference count was decremented to zero.
325 */
327unref_if_one() const {
328#ifdef _DEBUG
329 nassertr(test_ref_count_integrity(), 0);
330 nassertr(_ref_count > 0, 0);
331#endif
332 return (AtomicAdjust::compare_and_exchange(_ref_count, 1, 0) != 1);
333}
334
335/**
336 * This global helper function will unref the given ReferenceCount object, and
337 * if the reference count reaches zero, automatically delete it. It can't be
338 * a member function because it's usually a bad idea to delete an object from
339 * within its own member function. It's a template function so the destructor
340 * doesn't have to be virtual.
341 */
342template<class RefCountType>
343INLINE void
344unref_delete(RefCountType *ptr) {
345 TAU_PROFILE("void unref_delete(RefCountType *)", " ", TAU_USER);
346 // Although it may be tempting to try to upcast ptr to a ReferenceCount
347 // object (particularly to get around inheritance issues), resist that
348 // temptation, since some classes (in particular, TransformState and
349 // RenderState) rely on a non-virtual overloading of the unref() method.
350
351 if (!ptr->unref()) {
352 // If the reference count has gone to zero, delete the object.
353 delete ptr;
354 }
355}
356
357/**
358 *
359 */
360template<class Base>
363}
364
365/**
366 *
367 */
368template<class Base>
370RefCountProxy(const Base &copy) : _base(copy) {
371}
372
373/**
374 *
375 */
376template<class Base>
377INLINE RefCountProxy<Base>::
378operator Base &() {
379 return _base;
380}
381
382/**
383 *
384 */
385template<class Base>
386INLINE RefCountProxy<Base>::
387operator const Base &() const {
388 return _base;
389}
390
391/**
392 *
393 */
394template<class Base>
396init_type() {
397 do_init_type(Base);
398 register_type(_type_handle,
399 "RefCountProxy<" + get_type_handle(Base).get_name() + ">",
400 get_type_handle(Base));
401}
402
403
404/**
405 *
406 */
407template<class Base>
409RefCountObj() {
410}
411
412/**
413 *
414 */
415template<class Base>
417RefCountObj(const Base &copy) : Base(copy) {
418}
419
420
421/**
422 *
423 */
424template<class Base>
426init_type() {
427#if defined(HAVE_RTTI) && !defined(__EDG__) && (!defined(__GNUC__) || defined(__GXX_RTTI))
428 // If we have RTTI, we can determine the name of the base type.
429 std::string base_name = typeid(Base).name();
430#else
431 std::string base_name = "unknown";
432#endif
433
434 TypeHandle base_type = register_dynamic_type(base_name);
435
436 ReferenceCount::init_type();
437 _type_handle =
438 register_dynamic_type("RefCountObj<" + base_name + ">",
439 base_type, ReferenceCount::get_class_type());
440}
static bool dec(Integer &var)
Atomically decrements the indicated variable and returns true if the new value is nonzero,...
static Integer compare_and_exchange(Integer &mem, Integer old_value, Integer new_value)
Atomic compare and exchange.
static void inc(Integer &var)
Atomically increments the indicated variable.
static Pointer get_ptr(const Pointer &var)
Atomically retrieves the snapshot value of the indicated variable.
static Integer get(const Integer &var)
Atomically retrieves the snapshot value of the indicated variable.
static void record_pointer(ReferenceCount *ptr)
Indicates that the given pointer has been recently allocated.
Definition memoryUsage.I:32
static void remove_pointer(ReferenceCount *ptr)
Indicates that the given pointer has been recently freed.
Definition memoryUsage.I:90
Another kind of proxy, similar to RefCountProxy.
A "proxy" to use to make a reference-countable object whenever the object cannot inherit from Referen...
A base class for all things that want to be reference-counted.
void ref() const
Explicitly increments the reference count.
WeakReferenceList * get_weak_list() const
Returns the WeakReferenceList associated with this ReferenceCount object.
bool test_ref_count_integrity() const
Does some easy checks to make sure that the reference count isn't completely bogus.
void local_object()
This function should be called, once, immediately after creating a new instance of some ReferenceCoun...
bool ref_if_nonzero() const
Atomically increases the reference count of this object if it is not zero.
bool unref_if_one() const
Atomically decreases the reference count of this object if it is one.
get_ref_count
Returns the current reference count.
virtual bool unref() const
Explicitly decrements the reference count.
WeakReferenceList * weak_ref()
Adds the indicated PointerToVoid as a weak reference to this object.
bool has_weak_list() const
Returns true if this particular ReferenceCount object has a WeakReferenceList created,...
bool test_ref_count_nonzero() const
Does some easy checks to make sure that the reference count isn't zero, or completely bogus.
void weak_unref()
Removes the indicated PointerToVoid as a weak reference to this object.
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
This is an object shared by all the weak pointers that point to the same ReferenceCount object.
bool unref() const
Decreases the number of weak references.
void unref_delete(RefCountType *ptr)
This global helper function will unref the given ReferenceCount object, and if the reference count re...
void register_type(TypeHandle &type_handle, const std::string &name)
This inline function is just a convenient way to call TypeRegistry::register_type(),...
TypeHandle register_dynamic_type(const std::string &name)
This is essentially similar to register_type(), except that it doesn't store a reference to any TypeH...