referenceCount.I 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. // Filename: referenceCount.I
  2. // Created by: drose (23Oct98)
  3. //
  4. ////////////////////////////////////////////////////////////////////
  5. template<class Base>
  6. TypeHandle RefCountProxy<Base>::_type_handle;
  7. template<class Base>
  8. TypeHandle RefCountObj<Base>::_type_handle;
  9. ////////////////////////////////////////////////////////////////////
  10. // Function: ReferenceCount::Constructor
  11. // Access: Protected
  12. // Description: The ReferenceCount constructor is protected because
  13. // you almost never want to create just a ReferenceCount
  14. // object by itself, and it's probably a mistake if you
  15. // try.
  16. //
  17. // ReferenceCount doesn't store any useful information
  18. // in its own right; its only purpose is to add
  19. // reference-counting to some other class via
  20. // inheritance.
  21. ////////////////////////////////////////////////////////////////////
  22. INLINE ReferenceCount::
  23. ReferenceCount() {
  24. _ref_count = 0;
  25. MemoryUsage::record_pointer(this);
  26. }
  27. ////////////////////////////////////////////////////////////////////
  28. // Function: ReferenceCount::Copy Constructor
  29. // Access: Protected
  30. // Description: The copies of reference-counted objects do not
  31. // themselves inherit the reference count!
  32. //
  33. // This copy constructor is protected because you almost
  34. // never want to create just a ReferenceCount object by
  35. // itself, and it's probably a mistake if you try.
  36. ////////////////////////////////////////////////////////////////////
  37. INLINE ReferenceCount::
  38. ReferenceCount(const ReferenceCount &) {
  39. _ref_count = 0;
  40. MemoryUsage::record_pointer(this);
  41. }
  42. ////////////////////////////////////////////////////////////////////
  43. // Function: ReferenceCount::Copy Assignment Operator
  44. // Access: Protected
  45. // Description: The copies of reference-counted objects do not
  46. // themselves inherit the reference count!
  47. //
  48. // This copy assignment operator is protected because
  49. // you almost never want to copy just a ReferenceCount
  50. // object by itself, and it's probably a mistake if you
  51. // try.
  52. ////////////////////////////////////////////////////////////////////
  53. INLINE void ReferenceCount::
  54. operator = (const ReferenceCount &) {
  55. nassertv(this != NULL);
  56. // If this assertion fails, our own pointer was recently deleted.
  57. // Yikes!
  58. nassertv(_ref_count != -100);
  59. }
  60. ////////////////////////////////////////////////////////////////////
  61. // Function: ReferenceCount::Destructor
  62. // Access: Protected
  63. // Description: The ReferenceCount destructor is protected to
  64. // discourage users from accidentally trying to delete a
  65. // ReferenceCount pointer directly. This is almost
  66. // always a bad idea, since the destructor is not
  67. // virtual, and you've almost certainly got some pointer
  68. // to something that inherits from ReferenceCount, not
  69. // just a plain old ReferenceCount object.
  70. ////////////////////////////////////////////////////////////////////
  71. INLINE ReferenceCount::
  72. ~ReferenceCount() {
  73. prepare_delete();
  74. MemoryUsage::remove_pointer(this);
  75. }
  76. ////////////////////////////////////////////////////////////////////
  77. // Function: ReferenceCount::prepare_delete
  78. // Access: Public
  79. // Description: This function is called by the ReferenceCount
  80. // destructor to check on all of the numbers and make
  81. // sure it's all right to delete the object. Normally
  82. // it will never be called explicitly elsewhere, except
  83. // maybe in unref_delete() to simulate deleting the node
  84. // without actually deleting it, when we want to test
  85. // ref count integrities.
  86. ////////////////////////////////////////////////////////////////////
  87. INLINE void ReferenceCount::
  88. prepare_delete() {
  89. nassertv(this != NULL);
  90. // If this assertion fails, we're trying to delete an object that
  91. // was just deleted. Probably you've accidentally made a bitwise
  92. // copy of a PointerTo, by forgetting to write a copy constructor
  93. // for a class that contains PointerTo's.
  94. nassertv(_ref_count != -100);
  95. // If this assertion fails, the reference counts are all screwed
  96. // up altogether. Maybe some errant code stomped all over memory
  97. // somewhere.
  98. nassertv(_ref_count >= 0);
  99. // If this assertion fails, someone tried to delete this object
  100. // while its reference count was still positive. Maybe you tried
  101. // to point a PointerTo at a static object (a local variable,
  102. // instead of one allocated via new)? The test below against 0x7f
  103. // is supposed to check for that, but it's a pretty hokey test.
  104. // Another possibility is you inadvertently omitted a copy
  105. // constructor for a ReferenceCount object, and then bitwise
  106. // copied a dynamically allocated value--reference count and
  107. // all--onto a locally allocated one.
  108. nassertv(_ref_count == 0);
  109. // Ok, all clear to delete. Now set the reference count to -100,
  110. // so we'll have a better chance of noticing if we happen to have
  111. // a stray pointer to it still out there.
  112. _ref_count = -100;
  113. }
  114. ////////////////////////////////////////////////////////////////////
  115. // Function: ReferenceCount::get_count
  116. // Access: Public
  117. // Description: Returns the current reference count.
  118. ////////////////////////////////////////////////////////////////////
  119. INLINE int ReferenceCount::
  120. get_count() const {
  121. test_ref_count_integrity();
  122. return _ref_count;
  123. }
  124. ////////////////////////////////////////////////////////////////////
  125. // Function: ReferenceCount::ref
  126. // Access: Public
  127. // Description: Explicitly increments the reference count. User code
  128. // should avoid using ref() and unref() directly, which
  129. // can result in missed reference counts. Instead, let
  130. // a PointerTo object manage the reference counting
  131. // automatically.
  132. //
  133. // This function is const, even though it changes the
  134. // object, because generally fiddling with an object's
  135. // reference count isn't considered part of fiddling
  136. // with the object. An object might be const in other
  137. // ways, but we still need to accurately count the
  138. // number of references to it.
  139. ////////////////////////////////////////////////////////////////////
  140. INLINE void ReferenceCount::
  141. ref() const {
  142. nassertv(this != NULL);
  143. // If this assertion fails, we're trying to ref a pointer that was
  144. // just deleted. Probably you used a real pointer instead of a
  145. // PointerTo at some point, and the object was deleted when the
  146. // PointerTo went out of scope. Either that, or you forgot to
  147. // define a copy constructor for a class that contains
  148. // PointerTo's.
  149. nassertv(_ref_count != -100);
  150. // If this assertion fails, the reference counts are all screwed
  151. // up altogether. Maybe some errant code stomped all over memory
  152. // somewhere.
  153. nassertv(_ref_count >= 0);
  154. #if 0
  155. // This is an SGI-specific hack. Maybe this isn't a valid test at
  156. // all. This is supposed to fail if the 'this' pointer is on the
  157. // stack, instead of on the heap--I assume if the first two hex
  158. // digits of the pointer of 0x7f it's on the stack, possibly a bad
  159. // assumption. In any case, if you ref-count a pointer on the
  160. // stack, you just goofed. Don't assign a PointerTo to refer to
  161. // any local variables!
  162. nassertv(((long)this & 0xff000000) != 0x7f000000);
  163. #endif
  164. ((ReferenceCount *)this)->_ref_count++;
  165. // If this assertion fails, we have just wrapped! Either there
  166. // are actually 2^32 pointers to this thing somewhere, or
  167. // something is really screwy.
  168. nassertv(_ref_count > 0);
  169. }
  170. ////////////////////////////////////////////////////////////////////
  171. // Function: ReferenceCount::unref
  172. // Access: Public
  173. // Description: Explicitly decrements the reference count. Note that
  174. // the object will not be implicitly deleted by unref()
  175. // simply because the reference count drops to zero.
  176. // However, see the helper function unref_delete().
  177. //
  178. // User code should avoid using ref() and unref()
  179. // directly, which can result in missed reference
  180. // counts. Instead, let a PointerTo object manage the
  181. // reference counting automatically.
  182. //
  183. // This function is const, even though it changes the
  184. // object, because generally fiddling with an object's
  185. // reference count isn't considered part of fiddling
  186. // with the object. An object might be const in other
  187. // ways, but we still need to accurately count the
  188. // number of references to it.
  189. ////////////////////////////////////////////////////////////////////
  190. INLINE void ReferenceCount::
  191. unref() const {
  192. nassertv(this != NULL);
  193. // If this assertion fails, we're trying to unref a pointer that
  194. // was just deleted. Probably you used a real pointer instead of
  195. // a PointerTo at some point, and the object was deleted when the
  196. // PointerTo went out of scope. Either that, or you forgot to
  197. // define a copy constructor for a class that contains
  198. // PointerTo's.
  199. nassertv(_ref_count != -100);
  200. // If this assertion fails, the reference counts are all screwed
  201. // up altogether. Maybe some errant code stomped all over memory
  202. // somewhere.
  203. nassertv(_ref_count >= 0);
  204. // If this assertion fails, you tried to unref an object with a
  205. // zero reference count. Are you using ref() and unref()
  206. // directly? Are you sure you can't use PointerTo's?
  207. nassertv(_ref_count > 0);
  208. ((ReferenceCount *)this)->_ref_count--;
  209. }
  210. ////////////////////////////////////////////////////////////////////
  211. // Function: ReferenceCount::test_ref_count_integrity
  212. // Access: Public
  213. // Description: Does some easy checks to make sure that the reference
  214. // count isn't completely bogus.
  215. ////////////////////////////////////////////////////////////////////
  216. INLINE void ReferenceCount::
  217. test_ref_count_integrity() const {
  218. nassertv(this != NULL);
  219. // If this assertion fails, we're trying to access a pointer that
  220. // was just deleted. Probably you used a real pointer instead of
  221. // a PointerTo at some point, and the object was deleted when the
  222. // PointerTo went out of scope. Either that, or you forgot to
  223. // define a copy constructor for a class that contains
  224. // PointerTo's.
  225. nassertv(_ref_count != -100);
  226. // If this assertion fails, the reference counts are all screwed
  227. // up altogether. Maybe some errant code stomped all over memory
  228. // somewhere.
  229. nassertv(_ref_count >= 0);
  230. }
  231. ////////////////////////////////////////////////////////////////////
  232. // Function: unref_delete
  233. // Description: This global helper function will unref the given
  234. // ReferenceCount object, and if the reference count
  235. // reaches zero, automatically delete it. It can't be a
  236. // member function because it's usually a bad idea to
  237. // delete an object from within its own member function.
  238. // It's a template function so the destructor doesn't
  239. // have to be virtual.
  240. ////////////////////////////////////////////////////////////////////
  241. template<class RefCountType>
  242. INLINE void
  243. unref_delete(RefCountType *ptr) {
  244. ptr->unref();
  245. if (ptr->get_count() == 0) {
  246. delete ptr;
  247. // If we're testing reference counts, it's sometimes useful to do
  248. // the following instead of actually deleting the pointer:
  249. // ptr->prepare_delete();
  250. }
  251. }
  252. ////////////////////////////////////////////////////////////////////
  253. // Function: RefCountProxy::Constructor
  254. // Access: Public
  255. // Description:
  256. ////////////////////////////////////////////////////////////////////
  257. template<class Base>
  258. INLINE RefCountProxy<Base>::
  259. RefCountProxy() {
  260. }
  261. ////////////////////////////////////////////////////////////////////
  262. // Function: RefCountProxy::Copy Constructor
  263. // Access: Public
  264. // Description:
  265. ////////////////////////////////////////////////////////////////////
  266. template<class Base>
  267. INLINE RefCountProxy<Base>::
  268. RefCountProxy(const Base &copy) : _base(copy) {
  269. }
  270. ////////////////////////////////////////////////////////////////////
  271. // Function: RefCountProxy::Base Typecast Operator
  272. // Access: Public
  273. // Description:
  274. ////////////////////////////////////////////////////////////////////
  275. template<class Base>
  276. INLINE RefCountProxy<Base>::
  277. operator Base &() {
  278. return _base;
  279. }
  280. ////////////////////////////////////////////////////////////////////
  281. // Function: RefCountProxy::Base Typecast Operator
  282. // Access: Public
  283. // Description:
  284. ////////////////////////////////////////////////////////////////////
  285. template<class Base>
  286. INLINE RefCountProxy<Base>::
  287. operator const Base &() const {
  288. return _base;
  289. }
  290. ////////////////////////////////////////////////////////////////////
  291. // Function: RefCountProxy::init_type
  292. // Access: Public
  293. // Description:
  294. ////////////////////////////////////////////////////////////////////
  295. template<class Base>
  296. void RefCountProxy<Base>::
  297. init_type() {
  298. do_init_type(Base);
  299. register_type(_type_handle,
  300. "RefCountProxy<" + get_type_handle(Base).get_name() + ">",
  301. get_type_handle(Base));
  302. }
  303. ////////////////////////////////////////////////////////////////////
  304. // Function: RefCountObj::Constructor
  305. // Access: Public
  306. // Description:
  307. ////////////////////////////////////////////////////////////////////
  308. template<class Base>
  309. INLINE RefCountObj<Base>::
  310. RefCountObj() {
  311. }
  312. ////////////////////////////////////////////////////////////////////
  313. // Function: RefCountObj::Copy Constructor
  314. // Access: Public
  315. // Description:
  316. ////////////////////////////////////////////////////////////////////
  317. template<class Base>
  318. INLINE RefCountObj<Base>::
  319. RefCountObj(const Base &copy) : Base(copy) {
  320. }
  321. ////////////////////////////////////////////////////////////////////
  322. // Function: RefCountObj::init_type
  323. // Access: Public
  324. // Description:
  325. ////////////////////////////////////////////////////////////////////
  326. template<class Base>
  327. void RefCountObj<Base>::
  328. init_type() {
  329. #ifdef RTTI
  330. // If we have RTTI, we can determine the name of the base type.
  331. string base_name = typeid(Base).name();
  332. #else
  333. string base_name = "unknown";
  334. #endif
  335. TypeHandle base_type = register_dynamic_type(base_name);
  336. ReferenceCount::init_type();
  337. _type_handle =
  338. register_dynamic_type("RefCountObj<" + base_name + ">",
  339. base_type, ReferenceCount::get_class_type());
  340. }