mirror of
https://github.com/thug1src/thug.git
synced 2025-01-21 21:33:46 +00:00
366 lines
12 KiB
C
366 lines
12 KiB
C
|
/*****************************************************************************
|
||
|
** **
|
||
|
** Neversoft Entertainment **
|
||
|
** **
|
||
|
** Copyright (C) 2000 - All Rights Reserved **
|
||
|
** **
|
||
|
******************************************************************************
|
||
|
** **
|
||
|
** Project: Core Library **
|
||
|
** **
|
||
|
** Module: Template Singleton class **
|
||
|
** **
|
||
|
** File name: core/singleton.h **
|
||
|
** **
|
||
|
** Created: 10/17/00 - mjb **
|
||
|
** **
|
||
|
** **
|
||
|
*****************************************************************************/
|
||
|
|
||
|
#ifndef __CORE_SINGLETON_H
|
||
|
#define __CORE_SINGLETON_H
|
||
|
|
||
|
/*
|
||
|
|
||
|
Singletons
|
||
|
(Documentation by Mick)
|
||
|
|
||
|
A singleton is a single instance of a class which is dynamically
|
||
|
allocated just once.
|
||
|
|
||
|
To make a class such as CStats a singleton class, you do this:
|
||
|
|
||
|
|
||
|
class CStats
|
||
|
{
|
||
|
// Normal Class definition goes here...
|
||
|
...
|
||
|
|
||
|
// Constructor and destructor MUST BE PRIVATE, for it to be a singleton
|
||
|
private:
|
||
|
CStats( void );
|
||
|
~CStats( void );
|
||
|
|
||
|
// Macro to include the singleton code
|
||
|
DeclareSingletonClass( CStats );
|
||
|
}
|
||
|
|
||
|
This macro just places some static functions in the class, and a static pointer to
|
||
|
the single instance of class itself (initially NULL)
|
||
|
|
||
|
You can then initialize the singleton by the line
|
||
|
|
||
|
Spt::SingletonPtr< CStats > p_stats( true );
|
||
|
|
||
|
This is somewhere at a high level in the code (currently they are all in main())
|
||
|
|
||
|
The original design of our singletons had in mind that there would be reference counting
|
||
|
of the references tot he singleton, and when it was no longer referenced, it would
|
||
|
delete itself. So, in many places in the code, the singletons are reference by creating a
|
||
|
"Spt::SingletonPtr", which is a smart pointer to the instance of the singleton.
|
||
|
|
||
|
For example:
|
||
|
|
||
|
Spt::SingletonPtr< CStats > p_stats;
|
||
|
p_stats->Update();
|
||
|
|
||
|
In the ultimate version of this idea, the game would be comprised of many modules,
|
||
|
systems and subsystems. Each would be a singleton. Each could be dependent on
|
||
|
other singletons, but more that one module could depend on a particular singleton,
|
||
|
so you coudl not rely on a module to de-initialize the singletons it needed
|
||
|
as they might be needed elsewhere.
|
||
|
|
||
|
So, each module would include a Spt::SingletonPtr for each of the modules that it
|
||
|
needed, so when a module was created it would increase the reference on the singletons
|
||
|
and create any that did not exists. Then when it shut down, the pointers would automatically
|
||
|
go out of scope, and any singleton that was not referenced would automatically be deleted,
|
||
|
so there would never be more systems active than there needed to be.
|
||
|
|
||
|
However, it turned out that this was generally overkill. Most systems were initialized at the start,
|
||
|
and those that were not, we wanted to have control over the initialization of them.
|
||
|
The use of smart pointers here also obfuscated the code, and introduced a significant
|
||
|
execution overhead that was totally unnecessary.
|
||
|
|
||
|
So, the prefered method to access a singleton now is:
|
||
|
|
||
|
CStats::Instance()->Update();
|
||
|
|
||
|
This simply references the instance directly (as it's inline), and so
|
||
|
does no addition processing. It's easier to type as well.
|
||
|
|
||
|
|
||
|
*/
|
||
|
|
||
|
|
||
|
|
||
|
/*****************************************************************************
|
||
|
** Includes **
|
||
|
*****************************************************************************/
|
||
|
|
||
|
#ifndef __CORE_DEFINES_H
|
||
|
#include <core/defines.h>
|
||
|
#endif
|
||
|
#include <core/support.h>
|
||
|
|
||
|
#ifndef __SYS_MEM_MEMPTR_H
|
||
|
#include <sys/mem/memptr.h>
|
||
|
#endif
|
||
|
|
||
|
/*****************************************************************************
|
||
|
** Defines **
|
||
|
*****************************************************************************/
|
||
|
|
||
|
namespace Spt
|
||
|
{
|
||
|
|
||
|
/*****************************************************************************
|
||
|
** Class Definitions **
|
||
|
*****************************************************************************/
|
||
|
|
||
|
|
||
|
template< class _T >
|
||
|
class SingletonPtr : public Spt::Class
|
||
|
{
|
||
|
|
||
|
public:
|
||
|
|
||
|
SingletonPtr( bool create = false );
|
||
|
virtual ~SingletonPtr( void );
|
||
|
|
||
|
|
||
|
#if ( defined ( __PLAT_XBOX__ ) || defined ( __PLAT_WN32__ ))
|
||
|
SingletonPtr( const SingletonPtr< _T > & rhs );
|
||
|
SingletonPtr< _T >& operator= ( const SingletonPtr< _T >& rhs );
|
||
|
|
||
|
#else
|
||
|
|
||
|
template < class _NewT > // template copy contructor
|
||
|
SingletonPtr( const SingletonPtr< _NewT >& rhs ); // needed to support inheritance correctly
|
||
|
|
||
|
template < class _NewT >
|
||
|
SingletonPtr< _T >& operator= ( const SingletonPtr< _NewT >& rhs ); // template assignment operator
|
||
|
|
||
|
#endif
|
||
|
|
||
|
_T* operator-> () const;
|
||
|
_T& operator* () const;
|
||
|
|
||
|
private:
|
||
|
|
||
|
Mem::Ptr< _T > mp_instance;
|
||
|
};
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
template < class _T > inline
|
||
|
SingletonPtr< _T >::SingletonPtr( bool create )
|
||
|
: mp_instance ( _T::sSgltnInstance( create ) )
|
||
|
{
|
||
|
|
||
|
#ifdef __NOPT_FULL_DEBUG__
|
||
|
SetName( const_cast< char* >( sClassNode()->GetName() ));
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
template < class _T > inline
|
||
|
SingletonPtr< _T >::~SingletonPtr()
|
||
|
{
|
||
|
|
||
|
|
||
|
mp_instance->sSgltnDelete();
|
||
|
}
|
||
|
|
||
|
#if ( defined ( __PLAT_XBOX__ ) || defined ( __PLAT_WN32__ ))
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
template < class _T > inline
|
||
|
SingletonPtr< _T >::SingletonPtr ( const SingletonPtr< _T >& rhs )
|
||
|
: mp_instance ( _T::sSgltnInstance() )
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
template < class _T > inline
|
||
|
SingletonPtr< _T >& SingletonPtr< _T >::operator= ( const SingletonPtr< _T >& rhs )
|
||
|
{
|
||
|
|
||
|
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
template < class _T > template < class _NewT > inline
|
||
|
SingletonPtr< _T >::SingletonPtr< _T >( const SingletonPtr< _NewT >& rhs )
|
||
|
: mp_instance ( _NewT::sSgltnInstance() )
|
||
|
{
|
||
|
|
||
|
|
||
|
Dbg_MsgAssert( false,( "Microsoft VC++ sucks - don't do this (yet)" ));
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
template < class _T > template < class _NewT > inline
|
||
|
SingletonPtr< _T >& SingletonPtr< _T >::operator= ( const SingletonPtr< _NewT >& rhs )
|
||
|
{
|
||
|
|
||
|
|
||
|
Dbg_MsgAssert( false,( "Microsoft VC++ sucks - don't do this (yet)" ));
|
||
|
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
template < class _T > inline
|
||
|
_T* SingletonPtr< _T >::operator-> () const
|
||
|
{
|
||
|
|
||
|
|
||
|
return mp_instance.Addr();
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
template < class _T > inline
|
||
|
_T& SingletonPtr< _T >::operator* () const
|
||
|
{
|
||
|
|
||
|
|
||
|
return *mp_instance;
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
#define DeclareSingletonClass(_T) \
|
||
|
private: \
|
||
|
static _T* sSgltnInstance( bool create = false ); \
|
||
|
static void sSgltnDelete( void ); \
|
||
|
\
|
||
|
static _T* sp_sgltn_instance; \
|
||
|
static uint s_sgltn_count; \
|
||
|
public: \
|
||
|
inline static void Create(void) {sp_sgltn_instance = new _T;} \
|
||
|
inline static _T* Instance(void) {return sp_sgltn_instance;} \
|
||
|
inline bool Initilized(void) {return (sp_sgltn_instance!=NULL);} \
|
||
|
\
|
||
|
friend class Spt::SingletonPtr< _T >; \
|
||
|
|
||
|
|
||
|
#define DefinePlacementSingletonClass(_T, _P, _N ) \
|
||
|
\
|
||
|
_T* _T::sp_sgltn_instance = NULL; \
|
||
|
uint _T::s_sgltn_count = 0; \
|
||
|
\
|
||
|
_T* _T::sSgltnInstance( bool create ) \
|
||
|
{ \
|
||
|
\
|
||
|
\
|
||
|
if ( !sp_sgltn_instance && create ) \
|
||
|
{ \
|
||
|
sp_sgltn_instance = new (_P) _T; \
|
||
|
} \
|
||
|
\
|
||
|
Dbg_AssertType( sp_sgltn_instance, _T ); \
|
||
|
\
|
||
|
++s_sgltn_count; \
|
||
|
return sp_sgltn_instance; \
|
||
|
} \
|
||
|
\
|
||
|
void _T::sSgltnDelete( void ) \
|
||
|
{ \
|
||
|
\
|
||
|
\
|
||
|
Dbg_MsgAssert(( s_sgltn_count > 0 ),( "Reference count imbalance" )); \
|
||
|
\
|
||
|
if ( s_sgltn_count > 1 ) \
|
||
|
{ \
|
||
|
s_sgltn_count--; \
|
||
|
return; \
|
||
|
} \
|
||
|
\
|
||
|
delete sp_sgltn_instance; \
|
||
|
sp_sgltn_instance = NULL; \
|
||
|
s_sgltn_count = 0; \
|
||
|
} \
|
||
|
|
||
|
|
||
|
#define DefineSingletonClass(_T,_N) \
|
||
|
DefinePlacementSingletonClass(_T, (Mem::Allocator*)NULL, _N )
|
||
|
|
||
|
/*****************************************************************************
|
||
|
** Private Declarations **
|
||
|
*****************************************************************************/
|
||
|
|
||
|
|
||
|
/*****************************************************************************
|
||
|
** Private Prototypes **
|
||
|
*****************************************************************************/
|
||
|
|
||
|
|
||
|
/*****************************************************************************
|
||
|
** Public Declarations **
|
||
|
*****************************************************************************/
|
||
|
|
||
|
|
||
|
/*****************************************************************************
|
||
|
** Public Prototypes **
|
||
|
*****************************************************************************/
|
||
|
|
||
|
|
||
|
/*****************************************************************************
|
||
|
** Inline Functions **
|
||
|
*****************************************************************************/
|
||
|
|
||
|
|
||
|
/*****************************************************************************
|
||
|
** Macros **
|
||
|
*****************************************************************************/
|
||
|
|
||
|
} // namespace Spt
|
||
|
|
||
|
#endif // __CORE_SINGLETON_H
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|