nodeCachedReferenceCount.I 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. // Filename: nodeCachedReferenceCount.I
  2. // Created by: drose (07May05)
  3. //
  4. ////////////////////////////////////////////////////////////////////
  5. //
  6. // PANDA 3D SOFTWARE
  7. // Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
  8. //
  9. // All use of this software is subject to the terms of the Panda 3d
  10. // Software license. You should have received a copy of this license
  11. // along with this source code; you will also find a current copy of
  12. // the license at http://etc.cmu.edu/panda3d/docs/license/ .
  13. //
  14. // To contact the maintainers of this program write to
  15. // [email protected] .
  16. //
  17. ////////////////////////////////////////////////////////////////////
  18. ////////////////////////////////////////////////////////////////////
  19. // Function: NodeCachedReferenceCount::Constructor
  20. // Access: Protected
  21. // Description: The ReferenceCount constructor is protected because
  22. // you almost never want to create just a ReferenceCount
  23. // object by itself, and it's probably a mistake if you
  24. // try.
  25. //
  26. // ReferenceCount doesn't store any useful information
  27. // in its own right; its only purpose is to add
  28. // reference-counting to some other class via
  29. // inheritance.
  30. ////////////////////////////////////////////////////////////////////
  31. INLINE NodeCachedReferenceCount::
  32. NodeCachedReferenceCount() {
  33. _node_ref_count = 0;
  34. }
  35. ////////////////////////////////////////////////////////////////////
  36. // Function: NodeCachedReferenceCount::Copy Constructor
  37. // Access: Protected
  38. // Description: The copies of reference-counted objects do not
  39. // themselves inherit the reference count!
  40. //
  41. // This copy constructor is protected because you almost
  42. // never want to create just a ReferenceCount object by
  43. // itself, and it's probably a mistake if you try.
  44. ////////////////////////////////////////////////////////////////////
  45. INLINE NodeCachedReferenceCount::
  46. NodeCachedReferenceCount(const NodeCachedReferenceCount &copy) : CachedTypedWritableReferenceCount(copy) {
  47. _node_ref_count = 0;
  48. }
  49. ////////////////////////////////////////////////////////////////////
  50. // Function: NodeCachedReferenceCount::Copy Assignment Operator
  51. // Access: Protected
  52. // Description: The copies of reference-counted objects do not
  53. // themselves inherit the reference count!
  54. //
  55. // This copy assignment operator is protected because
  56. // you almost never want to copy just a ReferenceCount
  57. // object by itself, and it's probably a mistake if you
  58. // try. Instead, this should only be called from a
  59. // derived class that implements this operator and then
  60. // calls up the inheritance chain.
  61. ////////////////////////////////////////////////////////////////////
  62. INLINE void NodeCachedReferenceCount::
  63. operator = (const NodeCachedReferenceCount &copy) {
  64. nassertv(this != NULL);
  65. // If this assertion fails, our own pointer was recently deleted.
  66. // Possibly you used a real pointer instead of a PointerTo at some
  67. // point, and the object was deleted when the PointerTo went out of
  68. // scope. Maybe you tried to create an automatic (local variable)
  69. // instance of a class that derives from ReferenceCount. Or maybe
  70. // your headers are out of sync, and you need to make clean in
  71. // direct or some higher tree.
  72. nassertv(_node_ref_count != -100);
  73. CachedTypedWritableReferenceCount::operator = (copy);
  74. }
  75. ////////////////////////////////////////////////////////////////////
  76. // Function: NodeCachedReferenceCount::Destructor
  77. // Access: Protected
  78. // Description: The ReferenceCount destructor is protected to
  79. // discourage users from accidentally trying to delete a
  80. // ReferenceCount pointer directly. This is almost
  81. // always a bad idea, since the destructor is not
  82. // virtual, and you've almost certainly got some pointer
  83. // to something that inherits from ReferenceCount, not
  84. // just a plain old ReferenceCount object.
  85. ////////////////////////////////////////////////////////////////////
  86. INLINE NodeCachedReferenceCount::
  87. ~NodeCachedReferenceCount() {
  88. nassertv(this != NULL);
  89. // If this assertion fails, we're trying to delete an object that
  90. // was just deleted. Possibly you used a real pointer instead of a
  91. // PointerTo at some point, and the object was deleted when the
  92. // PointerTo went out of scope. Maybe you tried to create an
  93. // automatic (local variable) instance of a class that derives from
  94. // ReferenceCount. Or maybe your headers are out of sync, and you
  95. // need to make clean in direct or some higher tree.
  96. nassertv(_node_ref_count != -100);
  97. // If this assertion fails, the reference counts are all screwed
  98. // up altogether. Maybe some errant code stomped all over memory
  99. // somewhere.
  100. nassertv(_node_ref_count >= 0);
  101. // If this assertion fails, someone tried to delete this object
  102. // while its reference count was still positive. Maybe you tried
  103. // to point a PointerTo at a static object (a local variable,
  104. // instead of one allocated via new)? The test below against 0x7f
  105. // is supposed to check for that, but it's a pretty hokey test.
  106. // Another possibility is you inadvertently omitted a copy
  107. // constructor for a ReferenceCount object, and then bitwise
  108. // copied a dynamically allocated value--reference count and
  109. // all--onto a locally allocated one.
  110. nassertv(_node_ref_count == 0);
  111. #ifndef NDEBUG
  112. // Ok, all clear to delete. Now set the reference count to -100,
  113. // so we'll have a better chance of noticing if we happen to have
  114. // a stray pointer to it still out there.
  115. _node_ref_count = -100;
  116. #endif
  117. }
  118. ////////////////////////////////////////////////////////////////////
  119. // Function: NodeCachedReferenceCount::get_node_ref_count
  120. // Access: Published
  121. // Description: Returns the current reference count.
  122. ////////////////////////////////////////////////////////////////////
  123. INLINE int NodeCachedReferenceCount::
  124. get_node_ref_count() const {
  125. #ifndef NDEBUG
  126. test_ref_count_integrity();
  127. #endif
  128. return _node_ref_count;
  129. }
  130. ////////////////////////////////////////////////////////////////////
  131. // Function: NodeCachedReferenceCount::node_ref
  132. // Access: Published
  133. // Description: Explicitly increments the reference count.
  134. //
  135. // This function is const, even though it changes the
  136. // object, because generally fiddling with an object's
  137. // reference count isn't considered part of fiddling
  138. // with the object. An object might be const in other
  139. // ways, but we still need to accurately count the
  140. // number of references to it.
  141. //
  142. // The return value is the new reference count.
  143. ////////////////////////////////////////////////////////////////////
  144. INLINE int NodeCachedReferenceCount::
  145. node_ref() const {
  146. nassertr(this != NULL, 0);
  147. // If this assertion fails, we're trying to delete an object that
  148. // was just deleted. Possibly you used a real pointer instead of a
  149. // PointerTo at some point, and the object was deleted when the
  150. // PointerTo went out of scope. Maybe you tried to create an
  151. // automatic (local variable) instance of a class that derives from
  152. // ReferenceCount. Or maybe your headers are out of sync, and you
  153. // need to make clean in direct or some higher tree.
  154. nassertr(_node_ref_count != -100, 0);
  155. // If this assertion fails, the reference counts are all screwed
  156. // up altogether. Maybe some errant code stomped all over memory
  157. // somewhere.
  158. nassertr(_node_ref_count >= 0, 0);
  159. ref();
  160. return AtomicAdjust::inc(((NodeCachedReferenceCount *)this)->_node_ref_count);
  161. }
  162. ////////////////////////////////////////////////////////////////////
  163. // Function: NodeCachedReferenceCount::node_unref
  164. // Access: Published
  165. // Description: Explicitly decrements the reference count. Note that
  166. // the object will not be implicitly deleted by unref()
  167. // simply because the reference count drops to zero.
  168. // (Having a member function delete itself is
  169. // problematic; plus, we don't have a virtual destructor
  170. // anyway.) However, see the helper function
  171. // unref_delete().
  172. //
  173. // User code should avoid using ref() and unref()
  174. // directly, which can result in missed reference
  175. // counts. Instead, let a PointerTo object manage the
  176. // reference counting automatically.
  177. //
  178. // This function is const, even though it changes the
  179. // object, because generally fiddling with an object's
  180. // reference count isn't considered part of fiddling
  181. // with the object. An object might be const in other
  182. // ways, but we still need to accurately count the
  183. // number of references to it.
  184. //
  185. // The return value is the new reference count.
  186. ////////////////////////////////////////////////////////////////////
  187. INLINE int NodeCachedReferenceCount::
  188. node_unref() const {
  189. nassertr(this != NULL, false);
  190. // If this assertion fails, we're trying to delete an object that
  191. // was just deleted. Possibly you used a real pointer instead of a
  192. // PointerTo at some point, and the object was deleted when the
  193. // PointerTo went out of scope. Maybe you tried to create an
  194. // automatic (local variable) instance of a class that derives from
  195. // ReferenceCount. Or maybe your headers are out of sync, and you
  196. // need to make clean in direct or some higher tree.
  197. nassertr(_node_ref_count != -100, false);
  198. // If this assertion fails, the reference counts are all screwed
  199. // up altogether. Maybe some errant code stomped all over memory
  200. // somewhere.
  201. nassertr(_node_ref_count >= 0, false);
  202. // If this assertion fails, you tried to unref an object with a
  203. // zero reference count. Are you using ref() and unref()
  204. // directly? Are you sure you can't use PointerTo's?
  205. nassertr(_node_ref_count > 0, false);
  206. unref();
  207. return AtomicAdjust::dec(((NodeCachedReferenceCount *)this)->_node_ref_count);
  208. }
  209. ////////////////////////////////////////////////////////////////////
  210. // Function: NodeCachedReferenceCount::test_ref_count_integrity
  211. // Access: Published
  212. // Description: Does some easy checks to make sure that the reference
  213. // count isn't completely bogus.
  214. ////////////////////////////////////////////////////////////////////
  215. INLINE void NodeCachedReferenceCount::
  216. test_ref_count_integrity() const {
  217. #ifndef NDEBUG
  218. nassertv(this != NULL);
  219. // If this assertion fails, we're trying to delete an object that
  220. // was just deleted. Possibly you used a real pointer instead of a
  221. // PointerTo at some point, and the object was deleted when the
  222. // PointerTo went out of scope. Maybe you tried to create an
  223. // automatic (local variable) instance of a class that derives from
  224. // ReferenceCount. Or maybe your headers are out of sync, and you
  225. // need to make clean in direct or some higher tree.
  226. nassertv(_node_ref_count != -100);
  227. // If this assertion fails, the reference counts are all screwed
  228. // up altogether. Maybe some errant code stomped all over memory
  229. // somewhere.
  230. nassertv(_node_ref_count >= 0);
  231. CachedTypedWritableReferenceCount::test_ref_count_integrity();
  232. #endif
  233. }
  234. ////////////////////////////////////////////////////////////////////
  235. // Function: NodeCachedReferenceCount::get_referenced_bits
  236. // Access: Published
  237. // Description: Returns the union of the values defined in the
  238. // Referenced enum that represents the various things
  239. // that appear to be holding a pointer to this object.
  240. //
  241. // If R_node is included, at least one node is holding a
  242. // pointer; if R_cache is included, at least one cache
  243. // element is.
  244. ////////////////////////////////////////////////////////////////////
  245. INLINE int NodeCachedReferenceCount::
  246. get_referenced_bits() const {
  247. int result = 0;
  248. if (get_node_ref_count() != 0) {
  249. result |= R_node;
  250. }
  251. if (get_cache_ref_count() != 0) {
  252. result |= R_cache;
  253. }
  254. return result;
  255. }
  256. ////////////////////////////////////////////////////////////////////
  257. // Function: node_unref_delete
  258. // Description: This global helper function will unref the given
  259. // ReferenceCount object, and if the reference count
  260. // reaches zero, automatically delete it. It can't be a
  261. // member function because it's usually a bad idea to
  262. // delete an object from within its own member function.
  263. // It's a template function so the destructor doesn't
  264. // have to be virtual.
  265. ////////////////////////////////////////////////////////////////////
  266. template<class RefCountType>
  267. INLINE void
  268. node_unref_delete(RefCountType *ptr) {
  269. ptr->node_unref();
  270. if (ptr->get_ref_count() == 0) {
  271. #ifndef NDEBUG
  272. if (get_leak_memory()) {
  273. // In leak-memory mode, we don't actually delete the pointer,
  274. // although we do call the destructor explicitly. This has
  275. // exactly the same effect as deleting it, without actually
  276. // freeing up the memory it uses.
  277. // Furthermore, if we have never-destruct set, we don't even
  278. // call the destructor.
  279. if (!get_never_destruct()) {
  280. ptr->~RefCountType();
  281. }
  282. return;
  283. }
  284. #endif
  285. delete ptr;
  286. }
  287. }