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  */
109 INLINE int NodeReferenceCount::
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  */
121 INLINE void NodeReferenceCount::
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  */
138 INLINE bool NodeReferenceCount::
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  */
148 INLINE bool NodeReferenceCount::
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  */
162 INLINE void NodeReferenceCount::
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 }
bool node_unref() const
Explicitly decrements the node reference count and the normal reference count simultaneously.
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_integrity() const
Does some easy checks to make sure that the reference count isn't completely bogus.
int get_node_ref_count() const
Returns the current reference count.
This class specializes ReferenceCount to add an additional counter, called node_ref_count,...
void node_unref_only() const
Decrements the node reference count without affecting the normal reference count.
void node_unref_delete(RefCountType *ptr)
This global helper function will unref the given ReferenceCount object, and if the reference count re...
This works like RefCountObj, but it inherits from NodeReferenceCount instead of ReferenceCount.
void node_ref() const
Explicitly increments the node reference count and the normal reference count simultaneously.
static Integer get(const Integer &var)
Atomically retrieves the snapshot value of the indicated variable.
void ref() const
Explicitly increments the reference count.
A base class for all things that want to be reference-counted.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
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:69
virtual bool unref() const
Explicitly decrements the reference count.