ref_ptr.h 13 KB

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