| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436 |
- /*
- ** Command & Conquer Renegade(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- /***********************************************************************************************
- *** 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 ***
- ***********************************************************************************************
- * *
- * Project Name : WWLIB *
- * *
- * $Archive:: /VSS_Sync/wwlib/ref_ptr.h $*
- * *
- * $Author:: Vss_sync $*
- * *
- * $Modtime:: 6/13/01 2:16p $*
- * *
- * $Revision:: 3 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #if defined(_MSC_VER)
- #pragma once
- #endif
- #ifndef REF_PTR_H
- #define REF_PTR_H
- #ifndef ALWAYS_H
- #include "always.h"
- #endif
- /*
- RefCountPtr<T> is a smart pointer for reference counted objects.
-
- RefCountPtr<T> is designed to support objects derived from RefCountClass, although any class
- supporting the required interface may also be used.
- The reference counted objects must implement the following interface:
- 1. new objects must be created with reference count 1.
- 2. Add_Ref() to increase reference count by 1
- 3. Release_Ref() to decrease reference count. The object will be deleted when the reference
- count is reduced to 0.
- RefCountPtr<T> is designed to behave _mostly_ like a normal pointer. However, like most pointer
- wrappers, it does not support:
- 1. type hierarchy relationships. RefCountPtr<Derived> is unrelated to RefCountPtr<Base>.
- However, the templates support conversion from RefCountPtr<Derived> to RefCountPtr<Base>
- There is no support for casting upward (i.e. dynamic cast from RefCountPtr<Base> to RefCountPtr<Derived>
- This may be added in the future.
- 2. const'ness. RefCountPtr<const T> will probably misbehave.
- 3. address of pointer. There is no conversion to T**, nor should there be.
- 4. direct conversion to T*. Please keep object wrappered in RefCountPtr<T> and use dereferencing
- operators (*myptr.f() and/or myptr->f())
- You may also use Peek() to get a raw pointer. Peek does not modify the reference count of the object
- Using RefCountPtr<T>
- Example of usage :
-
- class MyClass : public RefCountClass
- {
- public:
- static RefCountPtr<T> Create(void)
- {
- return NEW MyClass;
- }
- void Do_Something(void);
- void Do_Something_Else(void);
- bool Is_Nice() const;
- private:
- MyClass(void);
- };
- void MyOtherClass
- {
- public:
- MyOtherClass(const RefCountPtr<T> & my_object) : MyObject(my_object) {}
- void Do_It(void)
- {
- if (MyObject) {
- MyObject->Do_Something();
- *MyObject.Do_Something_Else();
- }
- }
- void Set_Object(const RefCountPtr<T> & object) {
- MyObject = object;
- }
- const RefCountPtr<T> & Get_Object(void) {
- return MyObject;
- }
- private:
- RefCountPtr<T> MyObject;
- };
- RefCountPtr<T> Get_Nice_One(void)
- {
- do {
- RefCountPtr<T> object = MyClass::Create();
- if (object && object->Is_Nice()) {
- return object;
- }
- }
- }
- In general, a reference counted object should always be wrapped by RefCountPtr<T>. Since the
- smart pointer provides dereferencing operators (*myptr and myptr->), there is typically no
- need to access the raw pointer.
- Code that consistently uses RefCountPtr should be safer, cleaner and easier to use than code
- than manually manages reference counts.
- RefCountPtr<T> provides a default constructor, which corresponds to a null pointer, and a copy
- constructor, which handles initialization and an assignment operator, which handles pointer
- copying.
- To create a RefCountPtr<T> from a raw pointer, use the global template functions
- Create_NEW should be used when wrapping a pointer that has just been created with NEW
- Create_Get should be used when wrapping a pointer that has been returned from a "Get" function
- (the function added a reference prior to returning the pointer)
- Create_Peek should be used when wrapping a pointer that has been returned from a "Peek" function
- (the function did not add a reference prior to returning the pointer).
- Create_Get and Create_Peek are provided to allow old code to migrate from manual reference count
- management to RefCountPtr. New code written with RefCountPtr should rarely if ever use
- Create_Get and Create_Peek.
- If it is absolutely necessary to extract the raw pointer, use Peek. Peek does not add a new
- reference to the object. Using a Peek'd object after its RefCountPtr has gone out of scope requires
- care and typically requires the client to Add_Ref/Release_Ref the Peek'd object.
- Rewrapping and Peeking reference counted objects is primarily useful when converting old code to
- use RefCountPtr instead of manually managing the reference count. These two functions are designed
- for safety, NOT convenience.
- Automatic construction of a RefCountPtr from a raw pointer is enabled if
- ALLOW_AUTOMATIC_REF_COUNT_PTR_CONSTRUCTION is defined.
- This may be useful when migrating existing code to use RefCountPtr, but is completely safe,
- since it is not possible to determine if the pointer is being Get'd or Peek'd.
- Please note that the constructor WILL add a reference to the object, which errs on the side
- of leaking references rather than prematurely deleting objects. Whenever possible, use the
- explicit global Create_* functions rather than the automatic conversion.
- When used...
- 1. As a local variable. use RefCountPtr<T> :
- void My_Function(void)
- {
- RefCountPtr<T> myobject = MyClass::Get();
- if (myobject) {
- myobject->Do_Something();
- }
- }
- 2. As a member variable. use RefCountPtr<T> :
- class MyClass
- {
- private:
- RefCountPtr<T> MyObject;
- };
- 3. As a return value. use RefCountPtr<T> or const RefCountPtr<T> & (member variables)
- class MyClass
- {
- public:
- RefCountPtr<T> Make_Something(void);
- const RefCountPtr<T> & Get_Something(void) const {return MyObject;}
- private:
- RefCountPtr<T> MyObject;
- };
- 4. As a function parameter. user const RefCountPtr<T> & or RefCountPtr<T> & (for modifiable parameter)
- void My_Function(const RefCountPtr<T> & my_parameter)
- {
- my_parameter->Do_Something();
- }
- class MyClass
- {
- public:
- void Set(const RefCountPtr<T> & newthing)
- {
- MyThing = newthing;
- }
- // Get using an OUT parameter
- void Get(RefCountPtr<T> & thing)
- {
- thing = MyThing;
- }
- // Get using a return value. Preferable to above
- const RefCountPtr<T> & Get(void) const {return MyThing;}
- private:
- RefCountPtr<T> MyThing;
- };
- */
- class DummyPtrType;
- template <class T>
- class RefCountPtr
- {
- public:
- friend RefCountPtr<T> Create_NEW(T *t)
- {
- return RefCountPtr<T>(t, RefCountPtr<T>::GET);
- }
- friend RefCountPtr<T> Create_Get(T *t)
- {
- return RefCountPtr<T>(t, RefCountPtr<T>::GET);
- }
- friend RefCountPtr<T> Create_Peek(T *t)
- {
- return RefCountPtr<T>(t, RefCountPtr<T>::PEEK);
- }
- RefCountPtr(void)
- : Referent(0)
- {
- }
- #ifdef ALLOW_AUTOMATIC_REF_COUNT_PTR_CONSTRUCTION
- RefCountPtr(T * referent)
- : Referent(referent)
- {
- if (Referent) {
- Referent->Add_Ref();
- }
- }
- #else
- // This allows construction of the smart pointer from 0 (null)
- // Without allows unwanted conversions from T * (and related types, including void *)
- RefCountPtr(DummyPtrType * dummy)
- : Referent(0)
- {
- G_ASSERT(dummy == 0);
- }
- #endif
- template <class RHS>
- RefCountPtr(const RefCountPtr<RHS> & rhs)
- : Referent(rhs.Peek())
- {
- if (Referent) {
- Referent->Add_Ref();
- }
- }
- RefCountPtr(const RefCountPtr & rhs)
- : Referent(rhs.Referent)
- {
- if (Referent) {
- Referent->Add_Ref();
- }
- }
- #ifdef ALLOW_AUTOMATIC_REF_COUNT_PTR_CONSTRUCTION
- const RefCountPtr<T> & operator =(T * object)
- {
- if (Referent == object) {
- return *this;
- }
- Referent = object;
- if (Referent) {
- Referent->Add_Ref();
- }
- return *this;
- }
- #else
- const RefCountPtr<T> & operator =(DummyPtrType * dummy_ptr)
- {
- if (Referent) {
- Referent->Release_Ref();
- }
- Referent = 0;
- return *this;
- }
- #endif
- template <class RHS>
- const RefCountPtr<T> & operator =(const RefCountPtr<RHS> & rhs)
- {
- if (rhs.Peek()) {
- rhs.Peek()->Add_Ref();
- }
- if (Referent) {
- Referent->Release_Ref();
- }
- Referent = rhs.Peek();
- return *this;
- }
- const RefCountPtr<T> & operator =(const RefCountPtr & rhs)
- {
- if (rhs.Referent) {
- rhs.Referent->Add_Ref();
- }
- if (Referent) {
- Referent->Release_Ref();
- }
- Referent = rhs.Referent;
- return *this;
- }
- ~RefCountPtr(void)
- {
- if (Referent) {
- Referent->Release_Ref();
- Referent = 0;
- }
- }
- // This strange conversion allows us to test pointers against null (0) without
- // providing an unsafe conversion to T * (very unsafe) or bool (which can be silently
- // converted to int, defeating type-safety in some cases).
- // The compiler will convert our smart pointer to this raw pointer of an undefined
- // class automatically when trying to compare against 0 or with !my_ptr
- // However, the compiler will not perform conversions from DummyPtrType *
- // (except to void *, which is probably acceptable).
- operator const DummyPtrType *(void) const
- {
- return (DummyPtrType *)(Referent);
- }
- void Clear(void)
- {
- if (Referent) {
- Referent->Release_Ref();
- }
- }
- T * operator ->(void) const
- {
- return Referent;
- }
- T & operator *(void) const
- {
- G_ASSERT(0 != Referent);
- return *Referent;
- }
- // Note : This should typiccally only be used when mixing code that uses RefCountPtr and
- // manually managed ref counts on raw points.
- // Code that consistently uses RefCountPtr should never get ahold of a raw T*
- T * Peek(void) const
- {
- return Referent;
- }
- private:
- enum ReferenceHandling { GET, PEEK};
- RefCountPtr(T * referent, ReferenceHandling reference_handling)
- : Referent(referent)
- {
- if (reference_handling == PEEK && 0 != referent) {
- referent->Add_Ref();
- }
- }
- T * Referent;
- };
- // LHS and RHS should be related or compiler will barf
- // this follows same rules as LHS * lhs; RHS * rhs; lhs==rhs;
- template <class LHS, class RHS>
- bool operator ==(const RefCountPtr<LHS> & lhs, const RefCountPtr<RHS> & rhs)
- {
- return lhs.Peek() == rhs.Peek();
- }
- template <class LHS, class RHS>
- bool operator <(const RefCountPtr<LHS> & lhs, const RefCountPtr<RHS> & rhs)
- {
- return lhs.Peek() < rhs.Peek();
- }
- // This comparison allows us to test our smart pointer against 0 using
- // 0 == my_ptr
- template <class RHS>
- bool operator ==(DummyPtrType * dummy, const RefCountPtr<RHS> & rhs)
- {
- FAIL_IF(0 != dummy) {
- return false;
- }
- return 0 == rhs.Peek();
- }
- // This comparison allows us to test our smart pointer against 0 using
- // 0 != my_ptr
- template <class RHS>
- bool operator !=(DummyPtrType * dummy, const RefCountPtr<RHS> & rhs)
- {
- FAIL_IF(0 != dummy) {
- return true;
- }
- return 0 != rhs.Peek();
- }
- #endif
|