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