mirror of
https://github.com/electronicarts/CnC_Renegade.git
synced 2025-12-16 07:31:40 -05:00
Initial commit of Command & Conquer Renegade source code.
This commit is contained in:
436
Code/wwlib/ref_ptr.h
Normal file
436
Code/wwlib/ref_ptr.h
Normal file
@@ -0,0 +1,436 @@
|
||||
/*
|
||||
** 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
|
||||
Reference in New Issue
Block a user