1211 lines
42 KiB
C++
1211 lines
42 KiB
C++
//====== Copyright <20> 1996-2004, Valve Corporation, All rights reserved. =======
|
||
//
|
||
// Purpose:
|
||
//
|
||
//=============================================================================
|
||
|
||
#ifndef DMELEMENT_H
|
||
#define DMELEMENT_H
|
||
#ifdef _WIN32
|
||
#pragma once
|
||
#endif
|
||
|
||
#include "tier1/utlmap.h"
|
||
#include "tier1/utlhash.h"
|
||
#include "tier1/utlvector.h"
|
||
#include "tier1/utlsymbol.h"
|
||
#include "tier1/mempool.h"
|
||
#include "datamodel/attributeflags.h"
|
||
#include "datamodel/idatamodel.h"
|
||
#include "datamodel/dmattribute.h"
|
||
#include "datamodel/dmvar.h"
|
||
#include "tier0/vprof.h"
|
||
#include "tier1/utlsymbollarge.h"
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Forward declarations:
|
||
//-----------------------------------------------------------------------------
|
||
class CDmAttribute;
|
||
class Color;
|
||
class Vector;
|
||
class QAngle;
|
||
class Quaternion;
|
||
class VMatrix;
|
||
class CDmElement;
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Suppress some SWIG warnings, only for SWIG. Here because many SWIG
|
||
// projects %import this header directly
|
||
//-----------------------------------------------------------------------------
|
||
#ifdef SWIG
|
||
%ignore CAttributeReferenceIterator::operator++;
|
||
%warnfilter( 302 ) FindReferringElement;
|
||
%warnfilter( 302 ) CopyElements;
|
||
%warnfilter( 509 ) CDmElement::SetParity;
|
||
#endif // SWIG
|
||
|
||
//-----------------------------------------------------------------------------
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
typedef bool (CDmElement::*pfnCommandMethod)( const char *command, const char *args );
|
||
|
||
// element/element array traversal path item - assumes the full path does NOT contain cycles
|
||
struct ElementPathItem_t
|
||
{
|
||
ElementPathItem_t( DmElementHandle_t hElem = DMELEMENT_HANDLE_INVALID,
|
||
DmAttributeHandle_t hAttr = DMATTRIBUTE_HANDLE_INVALID,
|
||
int idx = -1 )
|
||
: hElement( hElem ), hAttribute( hAttr ), nIndex( idx )
|
||
{
|
||
}
|
||
|
||
// only uses hElement so that it can be used to search for elements
|
||
bool operator==( const ElementPathItem_t &that ) const
|
||
{
|
||
return hElement == that.hElement;
|
||
}
|
||
|
||
DmElementHandle_t hElement;
|
||
DmAttributeHandle_t hAttribute;
|
||
int nIndex;
|
||
};
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// singly-linked attribute list
|
||
//-----------------------------------------------------------------------------
|
||
struct DmAttributeList_t
|
||
{
|
||
DmAttributeList_t() : m_hAttribute( DMATTRIBUTE_HANDLE_INVALID ), m_pNext( NULL ) {}
|
||
DmAttributeHandle_t m_hAttribute;
|
||
DmAttributeList_t *m_pNext;
|
||
|
||
private:
|
||
DECLARE_FIXEDSIZE_ALLOCATOR( DmAttributeList_t );
|
||
};
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// helper class to allow CDmeHandle access to g_pDataModelImp
|
||
//-----------------------------------------------------------------------------
|
||
enum HandleType_t
|
||
{
|
||
HT_WEAK,
|
||
HT_STRONG,
|
||
HT_UNDO,
|
||
};
|
||
|
||
class CDmeElementRefHelper
|
||
{
|
||
protected:
|
||
void Ref ( DmElementHandle_t hElement, HandleType_t handleType );
|
||
void Unref( DmElementHandle_t hElement, HandleType_t handleType );
|
||
};
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// element reference struct - containing attribute referrers and handle refcount
|
||
//-----------------------------------------------------------------------------
|
||
struct DmElementReference_t
|
||
{
|
||
explicit DmElementReference_t( DmElementHandle_t hElement = DMELEMENT_HANDLE_INVALID ) :
|
||
m_hElement( hElement ), m_nWeakHandleCount( 0 ), m_nStrongHandleCount( 0 ), m_nUndoHandleCount( 0 ), m_bHasEverBeenReferenced( false )
|
||
{
|
||
}
|
||
DmElementReference_t( const DmElementReference_t &that ) :
|
||
m_hElement( that.m_hElement ), m_nWeakHandleCount( that.m_nWeakHandleCount ),
|
||
m_nStrongHandleCount( that.m_nStrongHandleCount ), m_nUndoHandleCount( that.m_nUndoHandleCount ),
|
||
m_bHasEverBeenReferenced( that.m_bHasEverBeenReferenced ), m_attributes( that.m_attributes )
|
||
{
|
||
}
|
||
DmElementReference_t &operator=( const DmElementReference_t &that )
|
||
{
|
||
m_hElement = that.m_hElement;
|
||
m_nWeakHandleCount = that.m_nWeakHandleCount;
|
||
m_nStrongHandleCount = that.m_nStrongHandleCount;
|
||
m_nUndoHandleCount = that.m_nUndoHandleCount;
|
||
m_bHasEverBeenReferenced = that.m_bHasEverBeenReferenced;
|
||
m_attributes.m_hAttribute = that.m_attributes.m_hAttribute;
|
||
m_attributes.m_pNext = that.m_attributes.m_pNext;
|
||
return *this;
|
||
}
|
||
~DmElementReference_t()
|
||
{
|
||
// Assert( !IsStronglyReferenced() );
|
||
}
|
||
|
||
void AddAttribute( CDmAttribute *pAttribute );
|
||
void RemoveAttribute( CDmAttribute *pAttribute );
|
||
bool FindAttribute( CDmAttribute *pAttribute );
|
||
|
||
bool IsStronglyReferenced() // should this element be kept around (even if it's DmElementHandle_t is invalidated)
|
||
{
|
||
return m_attributes.m_hAttribute != DMATTRIBUTE_HANDLE_INVALID || m_nStrongHandleCount > 0;
|
||
}
|
||
|
||
bool IsWeaklyReferenced() // should we keep this element's DmElementHandle_t mapped to it's id (even if the element is deleted)
|
||
{
|
||
return IsStronglyReferenced() || IsReferencedByUndo() || m_nWeakHandleCount > 0;
|
||
}
|
||
|
||
bool IsReferencedByUndo()
|
||
{
|
||
return m_nUndoHandleCount > 0;
|
||
}
|
||
|
||
int EstimateMemoryOverhead()
|
||
{
|
||
int nBytes = 0;
|
||
for ( DmAttributeList_t *pLink = m_attributes.m_pNext; pLink; pLink = pLink->m_pNext )
|
||
{
|
||
nBytes += sizeof( DmAttributeList_t );
|
||
}
|
||
return nBytes;
|
||
}
|
||
|
||
DmElementHandle_t m_hElement;
|
||
unsigned int m_nWeakHandleCount : 10; // CDmeHandle<T> - for auto-hookup once the element comes back, mainly used by UI
|
||
unsigned int m_nStrongHandleCount : 10; // CDmeCountedElementRef - for preventing elements from being truly deleted, mainly used by undo and file root
|
||
unsigned int m_nUndoHandleCount : 10; // CDmeUndoHandle<T> - for undo only, to allow it to keep handles to elements that may be conceptually deleted
|
||
bool m_bHasEverBeenReferenced : 1;
|
||
DmAttributeList_t m_attributes;
|
||
};
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Base DmElement we inherit from in higher-level classes
|
||
//-----------------------------------------------------------------------------
|
||
class CDmElement
|
||
{
|
||
public:
|
||
// Can be overridden by derived classes
|
||
virtual void OnAttributeChanged( CDmAttribute *pAttribute ) {}
|
||
virtual void OnAttributeArrayElementAdded( CDmAttribute *pAttribute, int nFirstElem, int nLastElem ) {}
|
||
virtual void OnAttributeArrayElementRemoved( CDmAttribute *pAttribute, int nFirstElem, int nLastElem ) {}
|
||
virtual void Resolve() {}
|
||
virtual bool IsA( CUtlSymbolLarge typeSymbol ) const;
|
||
virtual int GetInheritanceDepth( CUtlSymbolLarge typeSymbol ) const;
|
||
virtual void OnElementUnserialized() {}
|
||
virtual void OnElementSerialized() {}
|
||
virtual int AllocatedSize() const { return sizeof( CDmElement ); }
|
||
|
||
// Returns the element handle
|
||
DmElementHandle_t GetHandle() const;
|
||
|
||
// Attribute iteration, finding
|
||
// NOTE: Passing a type into GetAttribute will return NULL if the attribute exists but isn't that type
|
||
bool HasAttribute( const char *pAttributeName, DmAttributeType_t type = AT_UNKNOWN ) const;
|
||
CDmAttribute *GetAttribute( const char *pAttributeName, DmAttributeType_t type = AT_UNKNOWN );
|
||
const CDmAttribute *GetAttribute( const char *pAttributeName, DmAttributeType_t type = AT_UNKNOWN ) const;
|
||
int AttributeCount() const;
|
||
CDmAttribute* FirstAttribute();
|
||
const CDmAttribute* FirstAttribute() const;
|
||
|
||
// Element name, type, ID
|
||
// WARNING: SetType() should only be used by format conversion methods (dmxconvert)
|
||
CUtlSymbolLarge GetType() const;
|
||
const char * GetTypeString() const;
|
||
const char * GetName() const;
|
||
const DmObjectId_t& GetId() const;
|
||
void SetType( const char *pType );
|
||
void SetName( const char* pName );
|
||
|
||
// Attribute management
|
||
CDmAttribute * AddAttribute( const char *pAttributeName, DmAttributeType_t type );
|
||
template< class E > CDmAttribute* AddAttributeElement( const char *pAttributeName );
|
||
template< class E > CDmAttribute* AddAttributeElementArray( const char *pAttributeName );
|
||
void RemoveAttribute( const char *pAttributeName );
|
||
void RemoveAttributeByPtr( CDmAttribute *pAttributeName );
|
||
void RenameAttribute( const char *pAttributeName, const char *pNewName );
|
||
|
||
// get attribute value
|
||
template< class T > const T& GetValue( const char *pAttributeName ) const;
|
||
template< class T > const T& GetValue( const char *pAttributeName, const T& defaultValue ) const;
|
||
const char * GetValueString( const char *pAttributeName ) const;
|
||
template< class E > E* GetValueElement( const char *pAttributeName ) const;
|
||
|
||
// set attribute value
|
||
CDmAttribute* SetValue( const char *pAttributeName, const void *value, size_t size, bool bCreateIfNotFound = true );
|
||
template< class T > CDmAttribute* SetValue( const char *pAttributeName, const T& value, bool bCreateIfNotFound = true );
|
||
template< class E > CDmAttribute* SetValue( const char *pAttributeName, E* value, bool bCreateIfNotFound = true );
|
||
|
||
// set attribute value if the attribute doesn't already exist
|
||
CDmAttribute* InitValue( const char *pAttributeName, const void *value, size_t size );
|
||
template< class T > CDmAttribute* InitValue( const char *pAttributeName, const T& value );
|
||
template< class E > CDmAttribute* InitValue( const char *pAttributeName, E* value );
|
||
|
||
// Parses an attribute from a string
|
||
// Doesn't create an attribute if it doesn't exist and always preserves attribute type
|
||
void SetValueFromString( const char *pAttributeName, const char *value );
|
||
const char *GetValueAsString( const char *pAttributeName, char *pBuffer, size_t buflen ) const;
|
||
|
||
// Helpers for our RTTI
|
||
template< class E > bool IsA() const;
|
||
bool IsA( const char *pTypeName ) const;
|
||
int GetInheritanceDepth( const char *pTypeName ) const;
|
||
static CUtlSymbolLarge GetStaticTypeSymbol();
|
||
|
||
// Indicates whether this element should be copied or not
|
||
void SetShared( bool bShared );
|
||
bool IsShared() const;
|
||
|
||
// Copies an element and all its attributes
|
||
CDmElement* Copy( TraversalDepth_t depth = TD_DEEP ) const;
|
||
|
||
// Copies attributes from a specified element
|
||
void CopyAttributesTo( CDmElement *pCopy, TraversalDepth_t depth = TD_DEEP ) const;
|
||
|
||
// recursively set fileid's, with option to only change elements in the matched file
|
||
void SetFileId( DmFileId_t fileid, TraversalDepth_t depth, bool bOnlyIfMatch = false );
|
||
DmFileId_t GetFileId() const;
|
||
|
||
bool GetParity( int bit = 0 ) const;
|
||
void SetParity( bool bParity, int bit = 0 );
|
||
void SetParity( bool bParity, TraversalDepth_t depth, int bit = 0 ); // assumes that all elements that should be traversed have a parity of !bParity
|
||
|
||
bool IsOnlyInUndo() const;
|
||
void SetOnlyInUndo( bool bOnlyInUndo );
|
||
|
||
// returns the first path to the element found traversing all element/element
|
||
// array attributes - not necessarily the shortest.
|
||
// cycle-safe (skips any references to elements in the current path)
|
||
// but may re-traverse elements via different paths
|
||
bool FindElement( const CDmElement *pElement, CUtlVector< ElementPathItem_t > &elementPath, TraversalDepth_t depth ) const;
|
||
bool FindReferer( DmElementHandle_t hElement, CUtlVector< ElementPathItem_t > &elementPath, TraversalDepth_t depth ) const;
|
||
void RemoveAllReferencesToElement( CDmElement *pElement );
|
||
bool IsStronglyReferenced() { return m_ref.IsStronglyReferenced(); }
|
||
|
||
// Estimates the memory usage of the element, its attributes, and child elements
|
||
int EstimateMemoryUsage( TraversalDepth_t depth = TD_DEEP );
|
||
|
||
// mostly used for internal stuff, but it's occasionally useful to mark yourself dirty...
|
||
bool IsDirty() const;
|
||
void MarkDirty( bool dirty = true );
|
||
|
||
protected:
|
||
// NOTE: These are protected to ensure that the factory is the only thing that can create these
|
||
CDmElement( DmElementHandle_t handle, const char *objectType, const DmObjectId_t &id, const char *objectName, DmFileId_t fileid );
|
||
virtual ~CDmElement();
|
||
|
||
// Used by derived classes to do construction and setting up CDmaVars
|
||
void OnConstruction() { }
|
||
void OnDestruction() { }
|
||
virtual void PerformConstruction();
|
||
virtual void PerformDestruction();
|
||
|
||
virtual void OnAdoptedFromUndo() {}
|
||
virtual void OnOrphanedToUndo() {}
|
||
|
||
// Internal methods related to RTII
|
||
static void SetTypeSymbol( CUtlSymbolLarge sym );
|
||
static bool IsA_Implementation( CUtlSymbolLarge typeSymbol );
|
||
static int GetInheritanceDepth_Implementation( CUtlSymbolLarge typeSymbol, int nCurrentDepth );
|
||
|
||
// Internal method for creating a copy of this element
|
||
CDmElement* CopyInternal( TraversalDepth_t depth = TD_DEEP ) const;
|
||
|
||
// helper for making attributevarelementarray cleanup easier
|
||
template< class T > static void DeleteAttributeVarElementArray( T &array );
|
||
|
||
private:
|
||
typedef CUtlMap< DmElementHandle_t, DmElementHandle_t, int > CRefMap;
|
||
|
||
// Bogus constructor
|
||
CDmElement();
|
||
|
||
// internal recursive copy method - builds refmap of old element's handle -> copy's handle, and uses it to fixup references
|
||
void CopyAttributesTo( CDmElement *pCopy, CRefMap &refmap, TraversalDepth_t depth ) const;
|
||
void CopyElementAttribute( const CDmAttribute *pAttr, CDmAttribute *pCopyAttr, CRefMap &refmap, TraversalDepth_t depth ) const;
|
||
void CopyElementArrayAttribute( const CDmAttribute *pAttr, CDmAttribute *pCopyAttr, CRefMap &refmap, TraversalDepth_t depth ) const;
|
||
void FixupReferences( CUtlHashFast< DmElementHandle_t > &visited, const CRefMap &refmap, TraversalDepth_t depth );
|
||
|
||
void SetFileId( DmFileId_t fileid );
|
||
void SetFileId_R( CUtlHashFast< DmElementHandle_t > &visited, DmFileId_t fileid, TraversalDepth_t depth, DmFileId_t match, bool bOnlyIfMatch );
|
||
|
||
CDmAttribute* CreateAttribute( const char *pAttributeName, DmAttributeType_t type );
|
||
void RemoveAttribute( CDmAttribute **pAttrRef );
|
||
CDmAttribute* AddExternalAttribute( const char *pAttributeName, DmAttributeType_t type, void *pMemory );
|
||
CDmAttribute *FindAttribute( const char *pAttributeName ) const;
|
||
|
||
void Purge();
|
||
void SetId( const DmObjectId_t &id );
|
||
|
||
void MarkAttributesClean();
|
||
|
||
void DisableOnChangedCallbacks();
|
||
void EnableOnChangedCallbacks();
|
||
bool AreOnChangedCallbacksEnabled();
|
||
void FinishUnserialization();
|
||
|
||
// Used by the undo system only.
|
||
void AddAttributeByPtr( CDmAttribute *ptr );
|
||
void RemoveAttributeByPtrNoDelete( CDmAttribute *ptr );
|
||
|
||
// Should only be called from datamodel, who will take care of changing the fileset entry as well
|
||
void ChangeHandle( DmElementHandle_t handle );
|
||
|
||
// returns element reference struct w/ list of referrers and handle count
|
||
DmElementReference_t* GetReference();
|
||
void SetReference( const DmElementReference_t &ref );
|
||
|
||
// Estimates memory usage
|
||
int EstimateMemoryUsage( CUtlHash< DmElementHandle_t > &visited, TraversalDepth_t depth, int *pCategories );
|
||
|
||
private:
|
||
DmObjectId_t m_Id; // UUID's like to be quad-aligned
|
||
|
||
protected:
|
||
CDmaString m_Name;
|
||
|
||
private:
|
||
DmElementReference_t m_ref;
|
||
CDmAttribute *m_pAttributes;
|
||
CUtlSymbolLarge m_Type;
|
||
DmFileId_t m_fileId;
|
||
|
||
bool m_bDirty : 1;
|
||
bool m_bOnChangedCallbacksEnabled : 1;
|
||
bool m_bOnlyInUndo : 1; // only accessibly from the undo system
|
||
uint m_nParityBits : 28; // used as temporary state during traversal to avoid searching
|
||
|
||
// Stores the type symbol
|
||
static CUtlSymbolLarge m_classType;
|
||
|
||
// Factories can access our constructors
|
||
template <class T> friend class CDmElementFactory;
|
||
template <class T> friend class CDmAbstractElementFactory;
|
||
template< class T > friend class CDmaVar;
|
||
template< class T > friend class CDmaArray;
|
||
template< class T > friend class CDmaElementArray;
|
||
template< class T, class B > friend class CDmaDecorator;
|
||
template< class T > friend class CDmrElementArray;
|
||
|
||
friend class CDmElementFactoryDefault;
|
||
friend class CDmeElementAccessor;
|
||
friend class CDmeOperator;
|
||
|
||
template< class T >
|
||
friend void CopyElements( const CUtlVector< T* > &from, CUtlVector< T* > &to, TraversalDepth_t depth );
|
||
|
||
DECLARE_FIXEDSIZE_ALLOCATOR( CDmElement );
|
||
|
||
typedef CDmElement BaseClass; // only CDmElement has itself as it's BaseClass - this lets us know we're at the top of the hierarchy
|
||
};
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Fast dynamic cast
|
||
//-----------------------------------------------------------------------------
|
||
template< class E >
|
||
inline E *CastElement( CDmElement *pElement )
|
||
{
|
||
if ( pElement && pElement->IsA( E::GetStaticTypeSymbol() ) )
|
||
return static_cast< E* >( pElement );
|
||
return NULL;
|
||
}
|
||
|
||
template< class E >
|
||
inline const E *CastElement( const CDmElement *pElement )
|
||
{
|
||
if ( pElement && pElement->IsA( E::GetStaticTypeSymbol() ) )
|
||
return static_cast< const E* >( pElement );
|
||
return NULL;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Constant fast dynamic cast
|
||
//-----------------------------------------------------------------------------
|
||
template< class E >
|
||
const inline E *CastElementConst( const CDmElement *pElement )
|
||
{
|
||
if ( pElement && pElement->IsA( E::GetStaticTypeSymbol() ) )
|
||
return static_cast< const E* >( pElement );
|
||
return NULL;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// type-safe element creation and accessor helpers - infers type name string from actual type
|
||
//-----------------------------------------------------------------------------
|
||
template< class E >
|
||
inline E *GetElement( DmElementHandle_t hElement )
|
||
{
|
||
CDmElement *pElement = g_pDataModel->GetElement( hElement );
|
||
return CastElement< E >( pElement );
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Typesafe element creation + destruction
|
||
//-----------------------------------------------------------------------------
|
||
template< class E >
|
||
inline E *CreateElement( const char *pObjectName, DmFileId_t fileid, const DmObjectId_t *pObjectID = NULL )
|
||
{
|
||
return GetElement< E >( g_pDataModel->CreateElement( E::GetStaticTypeSymbol(), pObjectName, fileid, pObjectID ) );
|
||
}
|
||
|
||
template< class E >
|
||
inline E *CreateElement( const char *pElementType, const char *pObjectName, DmFileId_t fileid, const DmObjectId_t *pObjectID = NULL )
|
||
{
|
||
return GetElement< E >( g_pDataModel->CreateElement( pElementType, pObjectName, fileid, pObjectID ) );
|
||
}
|
||
|
||
inline void DestroyElement( CDmElement *pElement )
|
||
{
|
||
if ( pElement )
|
||
{
|
||
g_pDataModel->DestroyElement( pElement->GetHandle() );
|
||
}
|
||
}
|
||
|
||
void DestroyElement( CDmElement *pElement, TraversalDepth_t depth );
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// allows elements to chain OnAttributeChanged up to their parents (or at least, referrers)
|
||
//-----------------------------------------------------------------------------
|
||
void InvokeOnAttributeChangedOnReferrers( DmElementHandle_t hElement, CDmAttribute *pChangedAttr );
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Gets attributes
|
||
//-----------------------------------------------------------------------------
|
||
inline CDmAttribute *CDmElement::GetAttribute( const char *pAttributeName, DmAttributeType_t type )
|
||
{
|
||
CDmAttribute *pAttribute = FindAttribute( pAttributeName );
|
||
if ( ( type != AT_UNKNOWN ) && pAttribute && ( pAttribute->GetType() != type ) )
|
||
return NULL;
|
||
return pAttribute;
|
||
}
|
||
|
||
inline const CDmAttribute *CDmElement::GetAttribute( const char *pAttributeName, DmAttributeType_t type ) const
|
||
{
|
||
CDmAttribute *pAttribute = FindAttribute( pAttributeName );
|
||
if ( ( type != AT_UNKNOWN ) && pAttribute && ( pAttribute->GetType() != type ) )
|
||
return NULL;
|
||
return pAttribute;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// AddAttribute calls
|
||
//-----------------------------------------------------------------------------
|
||
inline CDmAttribute *CDmElement::AddAttribute( const char *pAttributeName, DmAttributeType_t type )
|
||
{
|
||
CDmAttribute *pAttribute = FindAttribute( pAttributeName );
|
||
if ( pAttribute )
|
||
return ( pAttribute->GetType() == type ) ? pAttribute : NULL;
|
||
pAttribute = CreateAttribute( pAttributeName, type );
|
||
return pAttribute;
|
||
}
|
||
|
||
template< class E > inline CDmAttribute *CDmElement::AddAttributeElement( const char *pAttributeName )
|
||
{
|
||
CDmAttribute *pAttribute = AddAttribute( pAttributeName, AT_ELEMENT );
|
||
if ( !pAttribute )
|
||
return NULL;
|
||
|
||
// FIXME: If the attribute exists but has a different element type symbol, should we complain?
|
||
pAttribute->SetElementTypeSymbol( E::GetStaticTypeSymbol() );
|
||
return pAttribute;
|
||
}
|
||
|
||
template< class E > inline CDmAttribute *CDmElement::AddAttributeElementArray( const char *pAttributeName )
|
||
{
|
||
CDmAttribute *pAttribute = AddAttribute( pAttributeName, AT_ELEMENT_ARRAY );
|
||
if ( !pAttribute )
|
||
return NULL;
|
||
|
||
// FIXME: If the attribute exists but has a different element type symbol, should we complain?
|
||
pAttribute->SetElementTypeSymbol( E::GetStaticTypeSymbol() );
|
||
return pAttribute;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// GetValue methods
|
||
//-----------------------------------------------------------------------------
|
||
template< class T >
|
||
inline const T& CDmElement::GetValue( const char *pAttributeName, const T& defaultVal ) const
|
||
{
|
||
const CDmAttribute *pAttribute = FindAttribute( pAttributeName );
|
||
if ( pAttribute != NULL )
|
||
return pAttribute->GetValue<T>();
|
||
return defaultVal;
|
||
}
|
||
|
||
template< class T >
|
||
inline const T& CDmElement::GetValue( const char *pAttributeName ) const
|
||
{
|
||
static CDmaVar<T> defaultVal;
|
||
return GetValue( pAttributeName, defaultVal.Get() );
|
||
}
|
||
|
||
inline const char *CDmElement::GetValueString( const char *pAttributeName ) const
|
||
{
|
||
CUtlSymbolLarge symbol = GetValue<CUtlSymbolLarge>( pAttributeName );
|
||
if ( symbol == UTL_INVAL_SYMBOL_LARGE )
|
||
return NULL;
|
||
|
||
return symbol.String();
|
||
}
|
||
|
||
template< class E >
|
||
inline E* CDmElement::GetValueElement( const char *pAttributeName ) const
|
||
{
|
||
DmElementHandle_t h = GetValue< DmElementHandle_t >( pAttributeName );
|
||
return GetElement<E>( h );
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// SetValue methods
|
||
//-----------------------------------------------------------------------------
|
||
template< class T >
|
||
inline CDmAttribute* CDmElement::SetValue( const char *pAttributeName, const T& value, bool bCreateIfNotFound /*= true*/ )
|
||
{
|
||
CDmAttribute *pAttribute = FindAttribute( pAttributeName );
|
||
if ( !pAttribute && bCreateIfNotFound )
|
||
{
|
||
pAttribute = CreateAttribute( pAttributeName, CDmAttributeInfo<T>::AttributeType() );
|
||
}
|
||
if ( pAttribute )
|
||
{
|
||
pAttribute->SetValue( value );
|
||
return pAttribute;
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
template< class E >
|
||
inline CDmAttribute* CDmElement::SetValue( const char *pAttributeName, E* pElement, bool bCreateIfNotFound /*= true*/ )
|
||
{
|
||
DmElementHandle_t hElement = pElement ? pElement->GetHandle() : DMELEMENT_HANDLE_INVALID;
|
||
return SetValue( pAttributeName, hElement, bCreateIfNotFound );
|
||
}
|
||
|
||
template<>
|
||
inline CDmAttribute* CDmElement::SetValue( const char *pAttributeName, const char *pValue, bool bCreateIfNotFound /*= true*/ )
|
||
{
|
||
// We don't want to add any extra entries into the string table so if bCreateIfNotFound is
|
||
// false, then check to see if the attribute exists before adding the string to the table.
|
||
if ( !bCreateIfNotFound )
|
||
{
|
||
if ( HasAttribute( pAttributeName, AT_STRING ) == false )
|
||
return NULL;
|
||
}
|
||
|
||
CUtlSymbolLarge symbol = g_pDataModel->GetSymbol( pValue );
|
||
return SetValue( pAttributeName, symbol );
|
||
}
|
||
|
||
template<>
|
||
inline CDmAttribute* CDmElement::SetValue( const char *pAttributeName, char *pValue, bool bCreateIfNotFound /*= true*/ )
|
||
{
|
||
return SetValue( pAttributeName, (const char *)pValue, bCreateIfNotFound );
|
||
}
|
||
|
||
inline CDmAttribute* CDmElement::SetValue( const char *pAttributeName, const void *pValue, size_t nSize, bool bCreateIfNotFound /*= true*/ )
|
||
{
|
||
CUtlBinaryBlock buf( pValue, nSize );
|
||
return SetValue( pAttributeName, buf, bCreateIfNotFound );
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// AddValue methods( set value if not found )
|
||
//-----------------------------------------------------------------------------
|
||
template< class T >
|
||
inline CDmAttribute* CDmElement::InitValue( const char *pAttributeName, const T& value )
|
||
{
|
||
CDmAttribute *pAttribute = GetAttribute( pAttributeName );
|
||
if ( !pAttribute )
|
||
return SetValue( pAttributeName, value );
|
||
return pAttribute;
|
||
}
|
||
|
||
template< class E >
|
||
inline CDmAttribute* CDmElement::InitValue( const char *pAttributeName, E* pElement )
|
||
{
|
||
DmElementHandle_t hElement = pElement ? pElement->GetHandle() : DMELEMENT_HANDLE_INVALID;
|
||
return InitValue( pAttributeName, hElement );
|
||
}
|
||
|
||
template<>
|
||
inline CDmAttribute* CDmElement::InitValue( const char *pAttributeName, const char *pValue )
|
||
{
|
||
CUtlSymbolLarge symbol = g_pDataModel->GetSymbol( pValue );
|
||
return InitValue( pAttributeName, symbol );
|
||
}
|
||
|
||
inline CDmAttribute* CDmElement::InitValue( const char *pAttributeName, const void *pValue, size_t size )
|
||
{
|
||
CDmAttribute *pAttribute = GetAttribute( pAttributeName );
|
||
if ( !pAttribute )
|
||
return SetValue( pAttributeName, pValue, size );
|
||
return pAttribute;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Returns the type, name, id, fileId
|
||
//-----------------------------------------------------------------------------
|
||
inline CUtlSymbolLarge CDmElement::GetType() const
|
||
{
|
||
return m_Type;
|
||
}
|
||
|
||
inline const char *CDmElement::GetTypeString() const
|
||
{
|
||
return m_Type.String();
|
||
}
|
||
|
||
inline const char *CDmElement::GetName() const
|
||
{
|
||
return m_Name.Get();
|
||
}
|
||
|
||
inline void CDmElement::SetName( const char* pName )
|
||
{
|
||
m_Name.Set( pName );
|
||
}
|
||
|
||
inline const DmObjectId_t& CDmElement::GetId() const
|
||
{
|
||
return m_Id;
|
||
}
|
||
|
||
inline DmFileId_t CDmElement::GetFileId() const
|
||
{
|
||
return m_fileId;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Controls whether the element should be copied by default
|
||
//-----------------------------------------------------------------------------
|
||
inline void CDmElement::SetShared( bool bShared )
|
||
{
|
||
if ( bShared )
|
||
{
|
||
SetValue< bool >( "shared", true );
|
||
}
|
||
else
|
||
{
|
||
RemoveAttribute( "shared" );
|
||
}
|
||
}
|
||
|
||
inline bool CDmElement::IsShared() const
|
||
{
|
||
return GetValue< bool >( "shared" ); // if attribute doesn't exist, returns default bool value, which is false
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Copies attributes from a specified element
|
||
//-----------------------------------------------------------------------------
|
||
inline CDmElement* CDmElement::Copy( TraversalDepth_t depth ) const
|
||
{
|
||
return CopyInternal( depth );
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// RTTI
|
||
//-----------------------------------------------------------------------------
|
||
inline bool CDmElement::IsA_Implementation( CUtlSymbolLarge typeSymbol )
|
||
{
|
||
return ( m_classType == typeSymbol ) || ( UTL_INVAL_SYMBOL_LARGE == typeSymbol );
|
||
}
|
||
|
||
inline int CDmElement::GetInheritanceDepth_Implementation( CUtlSymbolLarge typeSymbol, int nCurrentDepth )
|
||
{
|
||
return IsA_Implementation( typeSymbol ) ? nCurrentDepth : -1;
|
||
}
|
||
|
||
inline CUtlSymbolLarge CDmElement::GetStaticTypeSymbol()
|
||
{
|
||
return m_classType;
|
||
}
|
||
|
||
inline bool CDmElement::IsA( const char *pTypeName ) const
|
||
{
|
||
CUtlSymbolLarge typeSymbol = g_pDataModel->GetSymbol( pTypeName );
|
||
return IsA( typeSymbol );
|
||
}
|
||
|
||
template< class E > inline bool CDmElement::IsA() const
|
||
{
|
||
return IsA( E::GetStaticTypeSymbol() );
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Helper for finding elements that refer to this element
|
||
//-----------------------------------------------------------------------------
|
||
class CAttributeReferenceIterator
|
||
{
|
||
public:
|
||
explicit CAttributeReferenceIterator( const CDmElement *pElement ) :
|
||
m_curr ( pElement ? g_pDataModel->FirstAttributeReferencingElement( pElement->GetHandle() ) : DMATTRIBUTE_REFERENCE_ITERATOR_INVALID ),
|
||
m_fileid( pElement ? pElement->GetFileId() : DMFILEID_INVALID )
|
||
{
|
||
}
|
||
|
||
operator bool() const { return m_curr != DMATTRIBUTE_REFERENCE_ITERATOR_INVALID; }
|
||
|
||
CDmAttribute* operator*() const { return GetAttribute(); }
|
||
|
||
CDmAttribute *GetAttribute() const { return g_pDataModel->GetAttribute( m_curr ); }
|
||
CDmElement *GetOwner() const { if ( CDmAttribute *pAttr = GetAttribute() ) return pAttr->GetOwner(); return NULL; }
|
||
|
||
CAttributeReferenceIterator& operator++() // prefix
|
||
{
|
||
m_curr = g_pDataModel->NextAttributeReferencingElement( m_curr );
|
||
return *this;
|
||
}
|
||
CAttributeReferenceIterator operator++( int ) // postfix
|
||
{
|
||
CAttributeReferenceIterator prev = *this;
|
||
m_curr = g_pDataModel->NextAttributeReferencingElement( m_curr );
|
||
return prev;
|
||
}
|
||
|
||
template< class T >
|
||
T *FilterReference( CUtlSymbolLarge symAttrName = UTL_INVAL_SYMBOL_LARGE, bool bMustBeInSameFile = false, TraversalDepth_t depth = TD_ALL ) const
|
||
{
|
||
CDmAttribute *pAttribute = g_pDataModel->GetAttribute( m_curr );
|
||
Assert( pAttribute );
|
||
if ( !pAttribute )
|
||
return NULL;
|
||
|
||
if ( !ShouldTraverse( pAttribute, depth ) )
|
||
return NULL;
|
||
|
||
T *pParent = CastElement< T >( pAttribute->GetOwner() );
|
||
if ( !pParent )
|
||
return NULL;
|
||
|
||
if ( symAttrName != UTL_INVAL_SYMBOL_LARGE && pAttribute->GetNameSymbol() != symAttrName )
|
||
return NULL;
|
||
|
||
if ( bMustBeInSameFile && ( pParent->GetFileId() != m_fileid ) )
|
||
return NULL;
|
||
|
||
return pParent;
|
||
}
|
||
|
||
private:
|
||
DmAttributeReferenceIterator_t m_curr;
|
||
DmFileId_t m_fileid;
|
||
};
|
||
|
||
template< class T >
|
||
T *FindReferringElement( const CDmElement *pElement, const char *pAttrName = NULL, bool bMustBeInSameFile = true, TraversalDepth_t depth = TD_ALL )
|
||
{
|
||
CUtlSymbolLarge sym = pAttrName ? g_pDataModel->GetSymbol( pAttrName ) : (CUtlSymbolLarge)UTL_INVAL_SYMBOL_LARGE;
|
||
return FindReferringElement< T >( pElement, sym, bMustBeInSameFile, depth );
|
||
}
|
||
|
||
template< class T >
|
||
T *FindReferringElement( const CDmElement *pElement, CUtlSymbolLarge symAttrName = UTL_INVAL_SYMBOL_LARGE, bool bMustBeInSameFile = true, TraversalDepth_t depth = TD_ALL )
|
||
{
|
||
for ( CAttributeReferenceIterator it( pElement ); it; ++it )
|
||
{
|
||
if ( T *pParent = it.FilterReference< T >( symAttrName, bMustBeInSameFile, depth ) )
|
||
return pParent;
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
template< class T >
|
||
bool FindReferringElements( CUtlVector< T * >& list, const CDmElement *pElement, CUtlSymbolLarge symAttrName, bool bMustBeInSameFile = true, TraversalDepth_t depth = TD_ALL )
|
||
{
|
||
for ( CAttributeReferenceIterator it( pElement ); it; ++it )
|
||
{
|
||
if ( T *pParent = it.FilterReference< T >( symAttrName, bMustBeInSameFile, depth ) )
|
||
{
|
||
list.AddToTail( pParent );
|
||
}
|
||
}
|
||
|
||
return list.Count() > 0;
|
||
}
|
||
|
||
|
||
void RemoveElementFromRefereringAttributes( CDmElement *pElement, bool bPreserveOrder = true );
|
||
|
||
|
||
template< class T >
|
||
void FindAncestorsReferencingElement( const CDmElement *target, CUtlVector< T* >& list )
|
||
{
|
||
FindReferringElements( list, target, UTL_INVAL_SYMBOL_LARGE, false );
|
||
}
|
||
|
||
template< class T >
|
||
T *FindAncestorReferencingElement( const CDmElement *target )
|
||
{
|
||
return FindReferringElement< T >( target, UTL_INVAL_SYMBOL_LARGE, false );
|
||
}
|
||
|
||
template< class T >
|
||
T *FindAncestorReferencingElement_R_Impl( CUtlRBTree< CDmElement * >& visited, CDmElement *check )
|
||
{
|
||
if ( visited.Find( check ) != visited.InvalidIndex() )
|
||
return NULL;
|
||
|
||
visited.Insert( check );
|
||
|
||
// Pass one, see if it's in this ancestor list
|
||
for ( CAttributeReferenceIterator it( check ); it; ++it )
|
||
{
|
||
if ( T *pParent = it.FilterReference< T >() )
|
||
return pParent;
|
||
}
|
||
|
||
for ( CAttributeReferenceIterator it( check ); it; ++it )
|
||
{
|
||
if ( CDmElement *pParent = it.GetOwner() )
|
||
{
|
||
T *found = FindAncestorReferencingElement_R_Impl< T >( visited, pParent );
|
||
if ( found )
|
||
return found;
|
||
}
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
template< class T >
|
||
T *FindAncestorReferencingElement_R( CDmElement *target )
|
||
{
|
||
if ( !target )
|
||
return NULL;
|
||
|
||
CUtlRBTree< CDmElement * > visited( 0, 0, DefLessFunc( CDmElement * ) );
|
||
return FindAncestorReferencingElement_R_Impl< T >( visited, target );
|
||
}
|
||
|
||
// finds elements of type T that indirectly reference pElement
|
||
template< class T >
|
||
void FindAncestorsOfElement_Impl( CUtlRBTree< CDmElement * >& visited, CDmElement *pElement, CUtlVector< T* > &ancestors, bool bRecursePastFoundAncestors )
|
||
{
|
||
// Pass one, see if it's in this ancestor list
|
||
for ( CAttributeReferenceIterator it( pElement ); it; ++it )
|
||
{
|
||
if ( CDmElement *pParent = it.GetOwner() )
|
||
{
|
||
if ( visited.Find( pParent ) != visited.InvalidIndex() )
|
||
continue;
|
||
|
||
visited.Insert( pParent );
|
||
|
||
if ( T *pT = CastElement< T >( pParent ) )
|
||
{
|
||
ancestors.AddToTail( pT );
|
||
if ( !bRecursePastFoundAncestors )
|
||
continue;
|
||
}
|
||
FindAncestorsOfElement_Impl( visited, pParent, ancestors, bRecursePastFoundAncestors );
|
||
}
|
||
}
|
||
}
|
||
|
||
// finds elements of type T that indirectly reference pElement
|
||
template< class T >
|
||
void FindAncestorsOfElement( CDmElement *pElement, CUtlVector< T* > &ancestors, bool bRecursePastFoundAncestors )
|
||
{
|
||
if ( !pElement )
|
||
return;
|
||
|
||
CUtlRBTree< CDmElement * > visited( 0, 0, DefLessFunc( CDmElement * ) );
|
||
FindAncestorsOfElement_Impl< T >( visited, pElement, ancestors, bRecursePastFoundAncestors );
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
//
|
||
// generic element tree traversal helper class
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
class CElementTreeTraversal
|
||
{
|
||
public:
|
||
CElementTreeTraversal( CDmElement *pRoot, const char *pAttrName );
|
||
|
||
enum { NOT_VISITED = -2, VISITING = -1 };
|
||
|
||
void Reset( CDmElement *pRoot, const char *pAttrName );
|
||
|
||
bool IsValid() { return m_state.Count() > 0; }
|
||
CDmElement *Next( bool bSkipChildren = false );
|
||
|
||
int CurrentDepth() { return m_state.Count() - 1; }
|
||
CDmElement *GetElement();
|
||
CDmElement *GetParent ( int i );
|
||
int GetChildIndex( int i );
|
||
|
||
private:
|
||
struct State_t
|
||
{
|
||
State_t( CDmElement *p, int i ) : pElement( p ), nIndex( i ) {}
|
||
CDmElement *pElement;
|
||
int nIndex; // -2: not yet visited, -1: visiting self, 0+: visiting children
|
||
};
|
||
|
||
CUtlVector< State_t > m_state;
|
||
const char *m_pAttrName;
|
||
};
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
//
|
||
// element-specific unique name generation methods
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
template< class T >
|
||
struct ElementArrayNameAccessor
|
||
{
|
||
ElementArrayNameAccessor( const CUtlVector< T > &array ) : m_array( array ) {}
|
||
int Count() const
|
||
{
|
||
return m_array.Count();
|
||
}
|
||
const char *operator[]( int i ) const
|
||
{
|
||
CDmElement *pElement = GetElement< CDmElement >( m_array[ i ] );
|
||
return pElement ? pElement->GetName() : NULL;
|
||
}
|
||
private:
|
||
const CUtlVector< T > &m_array;
|
||
};
|
||
|
||
template< class E >
|
||
struct ElementArrayNameAccessor< E* >
|
||
{
|
||
ElementArrayNameAccessor( const CUtlVector< E* > &array ) : m_array( array ) {}
|
||
int Count() const
|
||
{
|
||
return m_array.Count();
|
||
}
|
||
const char *operator[]( int i ) const
|
||
{
|
||
E *pElement = m_array[ i ];
|
||
return pElement ? pElement->GetName() : NULL;
|
||
}
|
||
private:
|
||
const CUtlVector< E* > &m_array;
|
||
};
|
||
|
||
|
||
// returns startindex if none found, 2 if only "prefix" found, and n+1 if "prefixn" found
|
||
int GenerateUniqueNameIndex( const char *prefix, const CUtlVector< DmElementHandle_t > &array, int startindex = 0 );
|
||
|
||
bool GenerateUniqueName( char *name, int memsize, const char *prefix, const CUtlVector< DmElementHandle_t > &array );
|
||
|
||
int SplitStringIntoBaseAndIntegerSuffix( const char *pName, int len, char *pBaseName );
|
||
|
||
void MakeElementNameUnique( CDmElement *pElement, const CUtlVector< DmElementHandle_t > &array );
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// helper for making attributevarelementarray cleanup easier
|
||
//-----------------------------------------------------------------------------
|
||
template< class T >
|
||
inline void CDmElement::DeleteAttributeVarElementArray( T &array )
|
||
{
|
||
int nElements = array.Count();
|
||
for ( int i = 0; i < nElements; ++i )
|
||
{
|
||
g_pDataModel->DestroyElement( array.GetHandle( i ) );
|
||
}
|
||
array.RemoveAll();
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Default size computation
|
||
//-----------------------------------------------------------------------------
|
||
template< class T >
|
||
int DmeEstimateMemorySize( T* pElement )
|
||
{
|
||
return sizeof( T );
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// copy groups of elements together so that references between them are maintained
|
||
//-----------------------------------------------------------------------------
|
||
template< class T >
|
||
void CopyElements( const CUtlVector< T* > &from, CUtlVector< T* > &to, TraversalDepth_t depth = TD_DEEP )
|
||
{
|
||
CDisableUndoScopeGuard sg;
|
||
|
||
CUtlMap< DmElementHandle_t, DmElementHandle_t, int > refmap( DefLessFunc( DmElementHandle_t ) );
|
||
|
||
int c = from.Count();
|
||
for ( int i = 0; i < c; ++i )
|
||
{
|
||
T *pCopy = NULL;
|
||
|
||
if ( CDmElement *pFrom = from[ i ] )
|
||
{
|
||
int idx = refmap.Find( pFrom->GetHandle() );
|
||
if ( idx != refmap.InvalidIndex() )
|
||
{
|
||
pCopy = GetElement< T >( refmap[ idx ] );
|
||
}
|
||
else
|
||
{
|
||
pCopy = GetElement< T >( g_pDataModel->CreateElement( pFrom->GetType(), pFrom->GetName(), pFrom->GetFileId() ) );
|
||
if ( pCopy )
|
||
{
|
||
pFrom->CopyAttributesTo( pCopy, refmap, depth );
|
||
}
|
||
}
|
||
}
|
||
|
||
to.AddToTail( pCopy );
|
||
}
|
||
|
||
CUtlHashFast< DmElementHandle_t > visited;
|
||
uint nPow2Size = 1;
|
||
while( nPow2Size < refmap.Count() )
|
||
{
|
||
nPow2Size <<= 1;
|
||
}
|
||
visited.Init( nPow2Size );
|
||
|
||
for ( int i = 0; i < c; ++i )
|
||
{
|
||
CDmElement *pTo = to[ i ];
|
||
if ( !pTo )
|
||
continue;
|
||
|
||
to[ i ]->FixupReferences( visited, refmap, depth );
|
||
}
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Helper macro to create an element; this is used for elements that are helper base classes
|
||
//-----------------------------------------------------------------------------
|
||
#define DEFINE_UNINSTANCEABLE_ELEMENT( className, baseClassName ) \
|
||
protected: \
|
||
className( DmElementHandle_t handle, const char *pElementTypeName, const DmObjectId_t &id, const char *pElementName, DmFileId_t fileid ) : \
|
||
baseClassName( handle, pElementTypeName, id, pElementName, fileid ) \
|
||
{ \
|
||
} \
|
||
virtual ~className() \
|
||
{ \
|
||
} \
|
||
void OnConstruction(); \
|
||
void OnDestruction(); \
|
||
virtual void PerformConstruction() \
|
||
{ \
|
||
BaseClass::PerformConstruction(); \
|
||
OnConstruction(); \
|
||
} \
|
||
virtual void PerformDestruction() \
|
||
{ \
|
||
OnDestruction(); \
|
||
BaseClass::PerformDestruction(); \
|
||
} \
|
||
virtual int AllocatedSize() const { return DmeEstimateMemorySize( this ); } \
|
||
\
|
||
private: \
|
||
typedef baseClassName BaseClass; \
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Helper macro to create the class factory
|
||
//-----------------------------------------------------------------------------
|
||
#define DEFINE_ELEMENT( className, baseClassName ) \
|
||
public: \
|
||
virtual bool IsA( CUtlSymbolLarge typeSymbol ) const \
|
||
{ \
|
||
return IsA_Implementation( typeSymbol );\
|
||
} \
|
||
\
|
||
bool IsA( const char *pTypeName ) const \
|
||
{ \
|
||
CUtlSymbolLarge typeSymbol = g_pDataModel->GetSymbol( pTypeName ); \
|
||
return IsA( typeSymbol ); \
|
||
} \
|
||
\
|
||
template< class T > bool IsA() const \
|
||
{ \
|
||
return IsA( T::GetStaticTypeSymbol() ); \
|
||
} \
|
||
\
|
||
virtual int GetInheritanceDepth( CUtlSymbolLarge typeSymbol ) const \
|
||
{ \
|
||
return GetInheritanceDepth_Implementation( typeSymbol, 0 ); \
|
||
} \
|
||
\
|
||
static CUtlSymbolLarge GetStaticTypeSymbol( ) \
|
||
{ \
|
||
return m_classType; \
|
||
} \
|
||
\
|
||
className* Copy( TraversalDepth_t depth = TD_DEEP ) const \
|
||
{ \
|
||
return static_cast< className* >( CopyInternal( depth ) ); \
|
||
} \
|
||
protected: \
|
||
className( DmElementHandle_t handle, const char *pElementTypeName, const DmObjectId_t &id, const char *pElementName, DmFileId_t fileid ) : \
|
||
baseClassName( handle, pElementTypeName, id, pElementName, fileid ) \
|
||
{ \
|
||
} \
|
||
virtual ~className() \
|
||
{ \
|
||
} \
|
||
void OnConstruction(); \
|
||
void OnDestruction(); \
|
||
virtual void PerformConstruction() \
|
||
{ \
|
||
BaseClass::PerformConstruction(); \
|
||
OnConstruction(); \
|
||
} \
|
||
virtual void PerformDestruction() \
|
||
{ \
|
||
OnDestruction(); \
|
||
BaseClass::PerformDestruction(); \
|
||
} \
|
||
static void SetTypeSymbol( CUtlSymbolLarge typeSymbol ) \
|
||
{ \
|
||
m_classType = typeSymbol; \
|
||
} \
|
||
\
|
||
static bool IsA_Implementation( CUtlSymbolLarge typeSymbol ) \
|
||
{ \
|
||
if ( typeSymbol == m_classType ) \
|
||
return true; \
|
||
return BaseClass::IsA_Implementation( typeSymbol ); \
|
||
} \
|
||
\
|
||
static int GetInheritanceDepth_Implementation( CUtlSymbolLarge typeSymbol, int nCurrentDepth ) \
|
||
{ \
|
||
if ( typeSymbol == m_classType ) \
|
||
return nCurrentDepth; \
|
||
return BaseClass::GetInheritanceDepth_Implementation( typeSymbol, nCurrentDepth+1 );\
|
||
} \
|
||
virtual int AllocatedSize() const { return DmeEstimateMemorySize( this ); } \
|
||
\
|
||
private: \
|
||
DECLARE_FIXEDSIZE_ALLOCATOR( className ); \
|
||
typedef baseClassName BaseClass; \
|
||
typedef className ThisClass; \
|
||
template <class T> friend class CDmElementFactory; \
|
||
template <class T> friend class CDmAbstractElementFactory; \
|
||
static CUtlSymbolLarge m_classType
|
||
|
||
#define IMPLEMENT_ELEMENT( className ) \
|
||
CUtlSymbolLarge className::m_classType = UTL_INVAL_SYMBOL_LARGE; \
|
||
DEFINE_FIXEDSIZE_ALLOCATOR( className, 1024, CUtlMemoryPool::GROW_SLOW );
|
||
|
||
|
||
#endif // DMELEMENT_H
|