ref_ptr.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. /*
  2. ** Command & Conquer Generals Zero Hour(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : WWLIB *
  23. * *
  24. * $Archive:: /VSS_Sync/wwlib/ref_ptr.h $*
  25. * *
  26. * $Author:: Vss_sync $*
  27. * *
  28. * $Modtime:: 6/13/01 2:16p $*
  29. * *
  30. * $Revision:: 3 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #if defined(_MSC_VER)
  36. #pragma once
  37. #endif
  38. #ifndef REF_PTR_H
  39. #define REF_PTR_H
  40. #ifndef ALWAYS_H
  41. #include "always.h"
  42. #endif
  43. #include "wwdebug.h"
  44. /*
  45. RefCountPtr<T> is a smart pointer for reference counted objects.
  46. RefCountPtr<T> is designed to support objects derived from RefCountClass, although any class
  47. supporting the required interface may also be used.
  48. The reference counted objects must implement the following interface:
  49. 1. new objects must be created with reference count 1.
  50. 2. Add_Ref() to increase reference count by 1
  51. 3. Release_Ref() to decrease reference count. The object will be deleted when the reference
  52. count is reduced to 0.
  53. RefCountPtr<T> is designed to behave _mostly_ like a normal pointer. However, like most pointer
  54. wrappers, it does not support:
  55. 1. type hierarchy relationships. RefCountPtr<Derived> is unrelated to RefCountPtr<Base>.
  56. However, the templates support conversion from RefCountPtr<Derived> to RefCountPtr<Base>
  57. There is no support for casting upward (i.e. dynamic cast from RefCountPtr<Base> to RefCountPtr<Derived>
  58. This may be added in the future.
  59. 2. const'ness. RefCountPtr<const T> will probably misbehave.
  60. 3. address of pointer. There is no conversion to T**, nor should there be.
  61. 4. direct conversion to T*. Please keep object wrappered in RefCountPtr<T> and use dereferencing
  62. operators (*myptr.f() and/or myptr->f())
  63. You may also use Peek() to get a raw pointer. Peek does not modify the reference count of the object
  64. Using RefCountPtr<T>
  65. Example of usage :
  66. class MyClass : public RefCountClass
  67. {
  68. public:
  69. static RefCountPtr<T> Create(void)
  70. {
  71. return NEW MyClass;
  72. }
  73. void Do_Something(void);
  74. void Do_Something_Else(void);
  75. bool Is_Nice() const;
  76. private:
  77. MyClass(void);
  78. };
  79. void MyOtherClass
  80. {
  81. public:
  82. MyOtherClass(const RefCountPtr<T> & my_object) : MyObject(my_object) {}
  83. void Do_It(void)
  84. {
  85. if (MyObject) {
  86. MyObject->Do_Something();
  87. *MyObject.Do_Something_Else();
  88. }
  89. }
  90. void Set_Object(const RefCountPtr<T> & object) {
  91. MyObject = object;
  92. }
  93. const RefCountPtr<T> & Get_Object(void) {
  94. return MyObject;
  95. }
  96. private:
  97. RefCountPtr<T> MyObject;
  98. };
  99. RefCountPtr<T> Get_Nice_One(void)
  100. {
  101. do {
  102. RefCountPtr<T> object = MyClass::Create();
  103. if (object && object->Is_Nice()) {
  104. return object;
  105. }
  106. }
  107. }
  108. In general, a reference counted object should always be wrapped by RefCountPtr<T>. Since the
  109. smart pointer provides dereferencing operators (*myptr and myptr->), there is typically no
  110. need to access the raw pointer.
  111. Code that consistently uses RefCountPtr should be safer, cleaner and easier to use than code
  112. than manually manages reference counts.
  113. RefCountPtr<T> provides a default constructor, which corresponds to a null pointer, and a copy
  114. constructor, which handles initialization and an assignment operator, which handles pointer
  115. copying.
  116. To create a RefCountPtr<T> from a raw pointer, use the global template functions
  117. Create_NEW should be used when wrapping a pointer that has just been created with NEW
  118. Create_Get should be used when wrapping a pointer that has been returned from a "Get" function
  119. (the function added a reference prior to returning the pointer)
  120. Create_Peek should be used when wrapping a pointer that has been returned from a "Peek" function
  121. (the function did not add a reference prior to returning the pointer).
  122. Create_Get and Create_Peek are provided to allow old code to migrate from manual reference count
  123. management to RefCountPtr. New code written with RefCountPtr should rarely if ever use
  124. Create_Get and Create_Peek.
  125. If it is absolutely necessary to extract the raw pointer, use Peek. Peek does not add a new
  126. reference to the object. Using a Peek'd object after its RefCountPtr has gone out of scope requires
  127. care and typically requires the client to Add_Ref/Release_Ref the Peek'd object.
  128. Rewrapping and Peeking reference counted objects is primarily useful when converting old code to
  129. use RefCountPtr instead of manually managing the reference count. These two functions are designed
  130. for safety, NOT convenience.
  131. Automatic construction of a RefCountPtr from a raw pointer is enabled if
  132. ALLOW_AUTOMATIC_REF_COUNT_PTR_CONSTRUCTION is defined.
  133. This may be useful when migrating existing code to use RefCountPtr, but is completely safe,
  134. since it is not possible to determine if the pointer is being Get'd or Peek'd.
  135. Please note that the constructor WILL add a reference to the object, which errs on the side
  136. of leaking references rather than prematurely deleting objects. Whenever possible, use the
  137. explicit global Create_* functions rather than the automatic conversion.
  138. When used...
  139. 1. As a local variable. use RefCountPtr<T> :
  140. void My_Function(void)
  141. {
  142. RefCountPtr<T> myobject = MyClass::Get();
  143. if (myobject) {
  144. myobject->Do_Something();
  145. }
  146. }
  147. 2. As a member variable. use RefCountPtr<T> :
  148. class MyClass
  149. {
  150. private:
  151. RefCountPtr<T> MyObject;
  152. };
  153. 3. As a return value. use RefCountPtr<T> or const RefCountPtr<T> & (member variables)
  154. class MyClass
  155. {
  156. public:
  157. RefCountPtr<T> Make_Something(void);
  158. const RefCountPtr<T> & Get_Something(void) const {return MyObject;}
  159. private:
  160. RefCountPtr<T> MyObject;
  161. };
  162. 4. As a function parameter. user const RefCountPtr<T> & or RefCountPtr<T> & (for modifiable parameter)
  163. void My_Function(const RefCountPtr<T> & my_parameter)
  164. {
  165. my_parameter->Do_Something();
  166. }
  167. class MyClass
  168. {
  169. public:
  170. void Set(const RefCountPtr<T> & newthing)
  171. {
  172. MyThing = newthing;
  173. }
  174. // Get using an OUT parameter
  175. void Get(RefCountPtr<T> & thing)
  176. {
  177. thing = MyThing;
  178. }
  179. // Get using a return value. Preferable to above
  180. const RefCountPtr<T> & Get(void) const {return MyThing;}
  181. private:
  182. RefCountPtr<T> MyThing;
  183. };
  184. */
  185. class DummyPtrType;
  186. template <class T>
  187. class RefCountPtr
  188. {
  189. public:
  190. friend RefCountPtr<T> Create_NEW(T *t)
  191. {
  192. return RefCountPtr<T>(t, RefCountPtr<T>::GET);
  193. }
  194. friend RefCountPtr<T> Create_Get(T *t)
  195. {
  196. return RefCountPtr<T>(t, RefCountPtr<T>::GET);
  197. }
  198. friend RefCountPtr<T> Create_Peek(T *t)
  199. {
  200. return RefCountPtr<T>(t, RefCountPtr<T>::PEEK);
  201. }
  202. RefCountPtr(void)
  203. : Referent(0)
  204. {
  205. }
  206. #ifdef ALLOW_AUTOMATIC_REF_COUNT_PTR_CONSTRUCTION
  207. RefCountPtr(T * referent)
  208. : Referent(referent)
  209. {
  210. if (Referent) {
  211. Referent->Add_Ref();
  212. }
  213. }
  214. #else
  215. // This allows construction of the smart pointer from 0 (null)
  216. // Without allows unwanted conversions from T * (and related types, including void *)
  217. RefCountPtr(DummyPtrType * dummy)
  218. : Referent(0)
  219. {
  220. WWASSERT(dummy == 0);
  221. }
  222. #endif
  223. template <class RHS>
  224. RefCountPtr(const RefCountPtr<RHS> & rhs)
  225. : Referent(rhs.Peek())
  226. {
  227. if (Referent) {
  228. Referent->Add_Ref();
  229. }
  230. }
  231. RefCountPtr(const RefCountPtr & rhs)
  232. : Referent(rhs.Referent)
  233. {
  234. if (Referent) {
  235. Referent->Add_Ref();
  236. }
  237. }
  238. #ifdef ALLOW_AUTOMATIC_REF_COUNT_PTR_CONSTRUCTION
  239. const RefCountPtr<T> & operator =(T * object)
  240. {
  241. if (Referent == object) {
  242. return *this;
  243. }
  244. Referent = object;
  245. if (Referent) {
  246. Referent->Add_Ref();
  247. }
  248. return *this;
  249. }
  250. #else
  251. const RefCountPtr<T> & operator =(DummyPtrType * dummy_ptr)
  252. {
  253. if (Referent) {
  254. Referent->Release_Ref();
  255. }
  256. Referent = 0;
  257. return *this;
  258. }
  259. #endif
  260. template <class RHS>
  261. const RefCountPtr<T> & operator =(const RefCountPtr<RHS> & rhs)
  262. {
  263. if (rhs.Peek()) {
  264. rhs.Peek()->Add_Ref();
  265. }
  266. if (Referent) {
  267. Referent->Release_Ref();
  268. }
  269. Referent = rhs.Peek();
  270. return *this;
  271. }
  272. const RefCountPtr<T> & operator =(const RefCountPtr & rhs)
  273. {
  274. if (rhs.Referent) {
  275. rhs.Referent->Add_Ref();
  276. }
  277. if (Referent) {
  278. Referent->Release_Ref();
  279. }
  280. Referent = rhs.Referent;
  281. return *this;
  282. }
  283. ~RefCountPtr(void)
  284. {
  285. if (Referent) {
  286. Referent->Release_Ref();
  287. Referent = 0;
  288. }
  289. }
  290. // This strange conversion allows us to test pointers against null (0) without
  291. // providing an unsafe conversion to T * (very unsafe) or bool (which can be silently
  292. // converted to int, defeating type-safety in some cases).
  293. // The compiler will convert our smart pointer to this raw pointer of an undefined
  294. // class automatically when trying to compare against 0 or with !my_ptr
  295. // However, the compiler will not perform conversions from DummyPtrType *
  296. // (except to void *, which is probably acceptable).
  297. operator const DummyPtrType *(void) const
  298. {
  299. return (DummyPtrType *)(Referent);
  300. }
  301. void Clear(void)
  302. {
  303. if (Referent) {
  304. Referent->Release_Ref();
  305. Referent = 0;
  306. }
  307. }
  308. T * operator ->(void) const
  309. {
  310. return Referent;
  311. }
  312. T & operator *(void) const
  313. {
  314. G_ASSERT(0 != Referent);
  315. return *Referent;
  316. }
  317. // Note : This should typiccally only be used when mixing code that uses RefCountPtr and
  318. // manually managed ref counts on raw points.
  319. // Code that consistently uses RefCountPtr should never get ahold of a raw T*
  320. T * Peek(void) const
  321. {
  322. return Referent;
  323. }
  324. private:
  325. enum ReferenceHandling { GET, PEEK};
  326. RefCountPtr(T * referent, ReferenceHandling reference_handling)
  327. : Referent(referent)
  328. {
  329. if (reference_handling == PEEK && 0 != referent) {
  330. referent->Add_Ref();
  331. }
  332. }
  333. T * Referent;
  334. };
  335. // LHS and RHS should be related or compiler will barf
  336. // this follows same rules as LHS * lhs; RHS * rhs; lhs==rhs;
  337. template <class LHS, class RHS>
  338. bool operator ==(const RefCountPtr<LHS> & lhs, const RefCountPtr<RHS> & rhs)
  339. {
  340. return lhs.Peek() == rhs.Peek();
  341. }
  342. template <class LHS, class RHS>
  343. bool operator <(const RefCountPtr<LHS> & lhs, const RefCountPtr<RHS> & rhs)
  344. {
  345. return lhs.Peek() < rhs.Peek();
  346. }
  347. // This comparison allows us to test our smart pointer against 0 using
  348. // 0 == my_ptr
  349. template <class RHS>
  350. bool operator ==(DummyPtrType * dummy, const RefCountPtr<RHS> & rhs)
  351. {
  352. FAIL_IF(0 != dummy) {
  353. return false;
  354. }
  355. return 0 == rhs.Peek();
  356. }
  357. // This comparison allows us to test our smart pointer against 0 using
  358. // 0 != my_ptr
  359. template <class RHS>
  360. bool operator !=(DummyPtrType * dummy, const RefCountPtr<RHS> & rhs)
  361. {
  362. FAIL_IF(0 != dummy) {
  363. return true;
  364. }
  365. return 0 != rhs.Peek();
  366. }
  367. template <class Derived, class Base>
  368. RefCountPtr<Derived> Static_Cast(const RefCountPtr<Base> & base)
  369. {
  370. return Create_Peek((Derived *)base.Peek());
  371. }
  372. #endif