Panda3D
nodeReferenceCount.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 nodeReferenceCount.I
10  * @author drose
11  * @date 2006-05-01
12  */
13 
14 template<class Base>
16 
17 /**
18  * The ReferenceCount constructor is protected because you almost never want
19  * to create just a ReferenceCount object by itself, and it's probably a
20  * mistake if you try.
21  *
22  * ReferenceCount doesn't store any useful information in its own right; its
23  * only purpose is to add reference-counting to some other class via
24  * inheritance.
25  */
26 INLINE NodeReferenceCount::
27 NodeReferenceCount() {
28  _node_ref_count = 0;
29 }
30 
31 /**
32  * The copies of reference-counted objects do not themselves inherit the
33  * reference count!
34  *
35  * This copy constructor is protected because you almost never want to create
36  * just a ReferenceCount object by itself, and it's probably a mistake if you
37  * try.
38  */
39 INLINE NodeReferenceCount::
40 NodeReferenceCount(const NodeReferenceCount &copy) : ReferenceCount(copy) {
41  _node_ref_count = 0;
42 }
43 
44 /**
45  * The copies of reference-counted objects do not themselves inherit the
46  * reference count!
47  *
48  * This copy assignment operator is protected because you almost never want to
49  * copy just a ReferenceCount object by itself, and it's probably a mistake if
50  * you try. Instead, this should only be called from a derived class that
51  * implements this operator and then calls up the inheritance chain.
52  */
53 INLINE void NodeReferenceCount::
54 operator = (const NodeReferenceCount &copy) {
55  // If this assertion fails, our own pointer was recently deleted. Possibly
56  // you used a real pointer instead of a PointerTo at some point, and the
57  // object was deleted when the PointerTo went out of scope. Maybe you tried
58  // to create an automatic (local variable) instance of a class that derives
59  // from ReferenceCount. Or maybe your headers are out of sync, and you need
60  // to make clean in direct or some higher tree.
61  nassertv(_node_ref_count != -100);
62 
63  ReferenceCount::operator = (copy);
64 }
65 
66 /**
67  * The ReferenceCount destructor is protected to discourage users from
68  * accidentally trying to delete a ReferenceCount pointer directly. This is
69  * almost always a bad idea, since the destructor is not virtual, and you've
70  * almost certainly got some pointer to something that inherits from
71  * ReferenceCount, not just a plain old ReferenceCount object.
72  */
73 INLINE NodeReferenceCount::
74 ~NodeReferenceCount() {
75  // If this assertion fails, we're trying to delete an object that was just
76  // deleted. Possibly you used a real pointer instead of a PointerTo at some
77  // point, and the object was deleted when the PointerTo went out of scope.
78  // Maybe you tried to create an automatic (local variable) instance of a
79  // class that derives from ReferenceCount. Or maybe your headers are out of
80  // sync, and you need to make clean in direct or some higher tree.
81  nassertv(_node_ref_count != -100);
82 
83  // If this assertion fails, the reference counts are all screwed up
84  // altogether. Maybe some errant code stomped all over memory somewhere.
85  nassertv(_node_ref_count >= 0);
86 
87  // If this assertion fails, someone tried to delete this object while its
88  // reference count was still positive. Maybe you tried to point a PointerTo
89  // at a static object (a local variable, instead of one allocated via new)?
90  // The test below against 0x7f is supposed to check for that, but it's a
91  // pretty hokey test.
92 
93  // Another possibility is you inadvertently omitted a copy constructor for a
94  // ReferenceCount object, and then bitwise copied a dynamically allocated
95  // value--reference count and all--onto a locally allocated one.
96  nassertv(_node_ref_count == 0);
97 
98 #ifndef NDEBUG
99  // Ok, all clear to delete. Now set the reference count to -100, so we'll
100  // have a better chance of noticing if we happen to have a stray pointer to
101  // it still out there.
102  _node_ref_count = -100;
103 #endif
104 }
105 
106 /**
107  * Returns the current reference count.
108  */
110 get_node_ref_count() const {
111 #ifdef _DEBUG
113 #endif
114  return (int)AtomicAdjust::get(_node_ref_count);
115 }
116 
117 /**
118  * Explicitly increments the node reference count and the normal reference
119  * count simultaneously.
120  */
122 node_ref() const {
123 #ifdef _DEBUG
124  nassertv(test_ref_count_integrity());
125 #endif
126 
127  ref();
128  AtomicAdjust::inc(_node_ref_count);
129 }
130 
131 /**
132  * Explicitly decrements the node reference count and the normal reference
133  * count simultaneously.
134  *
135  * The return value is true if the new reference count is nonzero, false if it
136  * is zero.
137  */
139 node_unref() const {
140  node_unref_only();
141  return unref();
142 }
143 
144 /**
145  * Does some easy checks to make sure that the reference count isn't
146  * completely bogus.
147  */
149 test_ref_count_integrity() const {
150 #ifndef NDEBUG
151  return do_test_ref_count_integrity();
152 #else
153  return true;
154 #endif
155 }
156 
157 /**
158  * Decrements the node reference count without affecting the normal reference
159  * count. Intended to be called by derived classes only, presumably to
160  * reimplement node_unref().
161  */
163 node_unref_only() const {
164 #ifdef _DEBUG
165  nassertv(test_ref_count_integrity());
166 #endif
167 
168  // If this assertion fails, you tried to unref an object with a zero
169  // reference count. Are you using ref() and unref() directly? Are you sure
170  // you can't use PointerTo's?
171  nassertv(_node_ref_count > 0);
172 
173  AtomicAdjust::dec(_node_ref_count);
174 }
175 
176 /**
177  * This global helper function will unref the given ReferenceCount object, and
178  * if the reference count reaches zero, automatically delete it. It can't be
179  * a member function because it's usually a bad idea to delete an object from
180  * within its own member function. It's a template function so the destructor
181  * doesn't have to be virtual.
182  */
183 template<class RefCountType>
184 INLINE void
185 node_unref_delete(RefCountType *ptr) {
186  if (!ptr->node_unref()) {
187  delete ptr;
188  }
189 }
190 
191 
192 
193 /**
194  *
195  */
196 template<class Base>
198 NodeRefCountObj() {
199 }
200 
201 /**
202  *
203  */
204 template<class Base>
206 NodeRefCountObj(const Base &copy) : Base(copy) {
207 }
208 
209 
210 /**
211  *
212  */
213 template<class Base>
215 init_type() {
216 #if defined(HAVE_RTTI) && !defined(__EDG__)
217  // If we have RTTI, we can determine the name of the base type.
218  std::string base_name = typeid(Base).name();
219 #else
220  std::string base_name = "unknown";
221 #endif
222 
223  TypeHandle base_type = register_dynamic_type(base_name);
224 
225  ReferenceCount::init_type();
226  _type_handle =
227  register_dynamic_type("NodeRefCountObj<" + base_name + ">",
228  base_type, ReferenceCount::get_class_type());
229 }
static bool dec(Integer &var)
Atomically decrements the indicated variable and returns true if the new value is nonzero,...
static void inc(Integer &var)
Atomically increments the indicated variable.
static Integer get(const Integer &var)
Atomically retrieves the snapshot value of the indicated variable.
This works like RefCountObj, but it inherits from NodeReferenceCount instead of ReferenceCount.
This class specializes ReferenceCount to add an additional counter, called node_ref_count,...
void node_ref() const
Explicitly increments the node reference count and the normal reference count simultaneously.
bool test_ref_count_integrity() const
Does some easy checks to make sure that the reference count isn't completely bogus.
bool node_unref() const
Explicitly decrements the node reference count and the normal reference count simultaneously.
int get_node_ref_count() const
Returns the current reference count.
void node_unref_only() const
Decrements the node reference count without affecting the normal reference count.
A base class for all things that want to be reference-counted.
void ref() const
Explicitly increments the reference count.
virtual bool unref() const
Explicitly decrements the reference count.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
void node_unref_delete(RefCountType *ptr)
This global helper function will unref the given ReferenceCount object, and if the reference count re...
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...
Definition: register_type.I:73