Torque3D/Engine/source/core/module.h
2012-09-19 11:15:01 -04:00

358 lines
13 KiB
C++

//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _MODULE_H_
#define _MODULE_H_
#ifndef _TSINGLETON_H_
#include "core/util/tSingleton.h"
#endif
#ifndef _TVECTOR_H_
#include "core/util/tVector.h"
#endif
/// @file
/// A system for keeping initialization and shutdown modular while
/// avoiding non-trivial global constructors/destructors.
/// An engine component that requires initialization and/or cleanup.
class Module
{
public:
typedef void Parent;
friend struct ModuleManager;
protected:
struct Dependency;
friend struct Dependency;
enum Mode
{
ModeInitialize,
ModeShutdown
};
/// Direction of a dependency edge.
enum DependencyType
{
DependencyBefore,
DependencyAfter
};
/// Entry in the list of dependencies.
struct Dependency
{
/// Direction of dependence. A "before" dependence goes the reverse direction.
DependencyType mType;
/// Name of the module that this module depends on.
const char* mModuleName;
/// Pointer to module. Filled by init code.
Module* mModule;
/// Next dependency or NULL.
Dependency* mNext;
Dependency( Mode mode, DependencyType type, Module* parentModule, const char* moduleName )
: mType( type ),
mNext( mode == ModeInitialize ? parentModule->mInitDependencies : parentModule->mShutdownDependencies ),
mModuleName( moduleName ),
mModule( NULL )
{
if( mode == ModeInitialize )
parentModule->mInitDependencies = this;
else
parentModule->mShutdownDependencies = this;
}
};
/// Record for module that this module overrides.
struct Override
{
/// Name of module being overridden.
const char* mModuleName;
/// Next override or NULL.
Override* mNext;
Override( Module* parentModule, const char* moduleName )
: mModuleName( moduleName ),
mNext( parentModule->mOverrides )
{
parentModule->mOverrides = this;
}
};
/// Flag to make sure we don't shutdown modules that have not been initialized.
bool mIsInitialized;
/// Next module in the global module list.
Module* mNext;
/// List of modules to which the initialization of this module has dependency relations.
Dependency* mInitDependencies;
/// List of modules to which the shutdown of this module has dependency relations.
Dependency* mShutdownDependencies;
/// List of modules being overriden by this module.
Override* mOverrides;
/// Global list of modules.
static Module* smFirst;
/// Return true if this module is constrained to precede "module" in the given "mode".
bool _constrainedToComeBefore( Module* module, Mode mode );
/// Return true if this module is constrained to follow "module" in the given "mode".
bool _constrainedToComeAfter( Module* module, Mode mode );
///
Dependency* _getDependencies( Mode mode )
{
if( mode == ModeInitialize )
return mInitDependencies;
else
return mShutdownDependencies;
}
Module()
: mNext( smFirst ),
mInitDependencies( NULL ),
mShutdownDependencies( NULL ),
mOverrides( NULL ),
mIsInitialized( false )
{
smFirst = this;
}
public:
/// Return the module name.
virtual const char* getName() const = 0;
/// Initialize the module. This is only called after all modules that this
/// module depends on have been initialized.
virtual void initialize() {}
/// Shut down the module. This is called before any module that this module
/// depends on have been shut down.
virtual void shutdown() {}
};
/// Begin a module definition.
///
/// @code
/// MODULE_BEGIN( MyModule )
///
/// MODULE_INIT_AFTER( Sim )
/// MODULE_INIT_BEFORE( 3D )
/// MODULE_SHUTDOWN_BEFORE( Sim )
///
/// MODULE_INIT
/// {
/// // Init code...
/// }
///
/// MODULE_SHUTDOWN
/// {
/// // Cleanup code...
/// }
///
/// MODULE_END;
/// @endcode
#define MODULE_BEGIN( name ) \
namespace { namespace _ ## name { \
class _ModuleInst : public ::Module { \
public: \
typedef ::Module Parent; \
static _ModuleInst smInstance; \
virtual const char* getName() const { return #name; }
/// Make sure this module is initialized before the module called "name".
///
/// @code
/// MODULE_BEGIN( MyModule )
/// MODULE_INIT_BEFORE( MyOtherModule )
/// MODULE_END;
/// @endcode
#define MODULE_INIT_BEFORE( name ) \
struct _DepInitBefore ## name : public Parent::Dependency \
{ \
_DepInitBefore ## name() \
: Parent::Dependency( ModeInitialize, DependencyBefore, &smInstance, #name ) {} \
} mDepInitBefore ## name;
/// Make sure this module is initialized after the module called "name".
///
/// @code
/// MODULE_BEGIN( MyModule )
/// MODULE_INIT_AFTER( MyOtherModule )
/// MODULE_END;
/// @endcode
#define MODULE_INIT_AFTER( name ) \
struct _DepInitAfter ## name : public Parent::Dependency \
{ \
_DepInitAfter ## name() \
: Parent::Dependency( ModeInitialize, DependencyAfter, &smInstance, #name ) {} \
} mDepInitAfter ## name;
/// Make sure this module is initialized before the module called "name".
///
/// @code
/// MODULE_BEGIN( MyModule )
/// MODULE_SHUTDOWN_BEFORE( MyOtherModule )
/// MODULE_END;
/// @endcode
#define MODULE_SHUTDOWN_BEFORE( name ) \
struct _DepShutdownBefore ## name : public Parent::Dependency \
{ \
_DepShutdownBefore ## name() \
: Parent::Dependency( ModeShutdown, DependencyBefore, &smInstance, #name ) {} \
} mDepShutdownBefore ## name;
/// Make sure this module is initialized after the module called "name".
///
/// @code
/// MODULE_BEGIN( MyModule )
/// MODULE_SHUTDOWN_AFTER( MyOtherModule )
/// MODULE_END;
/// @endcode
#define MODULE_SHUTDOWN_AFTER( name ) \
struct _DepShutdownAfter ## name : public Parent::Dependency \
{ \
_DepShutdownAfter ## name() \
: Parent::Dependency( ModeShutdown, DependencyAfter, &smInstance, #name ) {} \
} mDepShutdownAfter ## name;
/// Replace the given module in both the init and the shutdown sequence.
///
/// @code
/// MODULE_BEGIN( MyMoveManager )
/// MODULE_OVERRIDE( MoveManager )
/// MODULE_END;
/// @endcode
#define MODULE_OVERRIDE( name ) \
struct _Override ## name : public Parent::Override \
{ \
_Override ## name() \
: Parent::Override( &smInstance, #name ) {} \
} mOverride ## name;
/// Define initialization code for the module.
///
/// @code
/// MODULE_BEGIN( MyModule )
/// MODULE_INIT
/// {
/// // Init code goes here.
/// }
/// MODULE_END;
/// @endcode
#define MODULE_INIT \
virtual void initialize()
/// Define cleanup code for the module.
///
/// @code
/// MODULE_BEGIN( MyModule )
/// MODULE_SHUTDOWN
/// {
/// // Cleanup code goes here.
/// }
/// MODULE_END;
/// @endcode
#define MODULE_SHUTDOWN \
virtual void shutdown()
/// Terminate a module definition.
///
/// @code
/// MODULE_BEGIN( MyModule )
/// MODULE_END;
/// @endcode
#define MODULE_END \
}; \
_ModuleInst _ModuleInst::smInstance; \
} }
/// Used to define a function which will be called right
/// after the named module is initialized.
///
/// @code
/// AFTER_MODULE_INIT( Sim )
/// {
/// Con::addVariable( "$myBool", TypeBool, &smMyBool );
/// }
/// @endcode
///
#define AFTER_MODULE_INIT( name ) \
namespace { \
class _AfterModuleInit : public ::Module { \
public: \
typedef ::Module Parent; \
static _AfterModuleInit smInstance; \
virtual const char* getName() const { return "AFTER_MODULE_INIT( " #name " ) in " __FILE__; } \
struct _DepInitAfter : public Parent::Dependency \
{ \
_DepInitAfter() \
: Parent::Dependency( ModeInitialize, DependencyAfter, &smInstance, #name ) {} \
} mDepInitAfter; \
virtual void initialize(); \
}; \
_AfterModuleInit _AfterModuleInit::smInstance; \
} \
void _AfterModuleInit::initialize()
struct ModuleManager
{
/// Initialize all modules registered with the system.
static void initializeSystem();
/// Shutdown all modules registered with the system.
static void shutdownSystem();
/// Return the instance of the module called "name" or NULL if no such module is defined.
static Module* findModule( const char* name );
private:
static Module* _findOverrideFor( Module* module );
static String _moduleListToString( Vector< Module* >& moduleList );
static void _printModuleList( Vector< Module* >& moduleList );
static void _insertIntoModuleList( Module::Mode mode, Vector< Module* >& moduleList, Module* module );
static S32 _getIndexOfModuleInList( Vector< Module* >& moduleList, Module* module );
static S32 _getIndexOfModuleInList( Vector< Module* >& moduleList, const char* moduleName );
static void _createModuleList( Module::Mode mode, Vector< Module* >& moduleList );
};
#endif // !_MODULE_H_