source-engine/datamodel/dmattribute.cpp
FluorescentCIAAfricanAmerican 3bf9df6b27 1
2020-04-22 12:56:21 -04:00

3266 lines
90 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "dmattributeinternal.h"
#include "datamodel/dmelement.h"
#include "dmelementdictionary.h"
#include "datamodel/idatamodel.h"
#include "datamodel.h"
#include "tier1/uniqueid.h"
#include "Color.h"
#include "mathlib/vector.h"
#include "tier1/utlstring.h"
#include "tier1/utlbuffer.h"
#include "tier1/KeyValues.h"
#include "tier1/mempool.h"
#include "mathlib/vmatrix.h"
#include "datamodel/dmattributevar.h"
#include <ctype.h>
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Tests equality
//-----------------------------------------------------------------------------
template< class T >
bool IsAttributeEqual( const T& src1, const T& src2 )
{
return src1 == src2;
}
template< class T >
bool IsAttributeEqual( const CUtlVector<T> &src1, const CUtlVector<T> &src2 )
{
if ( src1.Count() != src2.Count() )
return false;
for ( int i=0; i < src1.Count(); i++ )
{
if ( !( src1[i] == src2[i] ) )
return false;
}
return true;
}
//-----------------------------------------------------------------------------
// Typesafety check for element handles
//-----------------------------------------------------------------------------
static inline bool IsA( DmElementHandle_t hElement, UtlSymId_t type )
{
// treat NULL, deleted, and unloaded elements as being of any type -
// when set, undeleted or loaded, this should be checked again
CDmElement *pElement = g_pDataModel->GetElement( hElement );
return pElement ? pElement->IsA( type ) : true;
}
//-----------------------------------------------------------------------------
// Element attributes are never directly unserialized
//-----------------------------------------------------------------------------
static bool Serialize( CUtlBuffer &buf, DmElementHandle_t src )
{
Assert( 0 );
return false;
}
static bool Unserialize( CUtlBuffer &buf, DmElementHandle_t &dest )
{
Assert( 0 );
return false;
}
static bool Serialize( CUtlBuffer &buf, const DmUnknownAttribute_t& src )
{
Assert( 0 );
return false;
}
static bool Unserialize( CUtlBuffer &buf, DmUnknownAttribute_t &dest )
{
Assert( 0 );
return false;
}
#include "tier1/utlbufferutil.h"
//-----------------------------------------------------------------------------
// Internal interface for dealing with generic attribute operations
//-----------------------------------------------------------------------------
abstract_class IDmAttributeOp
{
public:
virtual void* CreateAttributeData() = 0;
virtual void DestroyAttributeData( void *pData ) = 0;
virtual void SetDefaultValue( void *pData ) = 0;
virtual int DataSize() = 0;
virtual int ValueSize() = 0;
virtual bool SerializesOnMultipleLines() = 0;
virtual bool SkipUnserialize( CUtlBuffer& buf ) = 0;
virtual const char *AttributeTypeName() = 0;
virtual void SetValue( CDmAttribute *pAttribute, DmAttributeType_t valueType, const void *pValue ) = 0;
virtual void SetMultiple( CDmAttribute *pAttribute, int i, int nCount, DmAttributeType_t valueType, const void *pValue ) = 0;
virtual void Set( CDmAttribute *pAttribute, int i, DmAttributeType_t valueType, const void *pValue ) = 0;
virtual void SetToDefaultValue( CDmAttribute *pAttribute ) = 0;
virtual bool Serialize( const CDmAttribute *pAttribute, CUtlBuffer &buf ) = 0;
virtual bool Unserialize( CDmAttribute *pAttribute, CUtlBuffer &buf ) = 0;
virtual bool SerializeElement( const CDmAttribute *pAttribute, int nElement, CUtlBuffer &buf ) = 0;
virtual bool UnserializeElement( CDmAttribute *pAttribute, CUtlBuffer &buf ) = 0;
virtual bool UnserializeElement( CDmAttribute *pAttribute, int nElement, CUtlBuffer &buf ) = 0;
virtual void OnUnserializationFinished( CDmAttribute *pAttribute ) = 0;
};
//-----------------------------------------------------------------------------
// Global table of generic attribute operations looked up by type
//-----------------------------------------------------------------------------
static IDmAttributeOp* s_pAttrInfo[ AT_TYPE_COUNT ];
//-----------------------------------------------------------------------------
//
// Implementation of IDmAttributeOp for single-valued attributes
//
//-----------------------------------------------------------------------------
template< class T >
class CDmAttributeOp : public IDmAttributeOp
{
public:
virtual void* CreateAttributeData();
virtual void DestroyAttributeData( void *pData );
virtual void SetDefaultValue( void *pData );
virtual int DataSize();
virtual int ValueSize();
virtual bool SerializesOnMultipleLines();
virtual bool SkipUnserialize( CUtlBuffer& buf );
virtual const char *AttributeTypeName();
virtual void SetValue( CDmAttribute *pAttribute, DmAttributeType_t valueType, const void *pValue );
virtual void SetMultiple( CDmAttribute *pAttribute, int i, int nCount, DmAttributeType_t valueType, const void *pValue );
virtual void Set( CDmAttribute *pAttribute, int i, DmAttributeType_t valueType, const void *pValue );
virtual void SetToDefaultValue( CDmAttribute *pAttribute );
virtual bool Serialize( const CDmAttribute *pData, CUtlBuffer &buf );
virtual bool Unserialize( CDmAttribute *pAttribute, CUtlBuffer &buf );
virtual bool SerializeElement( const CDmAttribute *pAttribute, int nElement, CUtlBuffer &buf );
virtual bool UnserializeElement( CDmAttribute *pAttribute, CUtlBuffer &buf );
virtual bool UnserializeElement( CDmAttribute *pAttribute, int nElement, CUtlBuffer &buf );
virtual void OnUnserializationFinished( CDmAttribute *pAttribute );
};
//-----------------------------------------------------------------------------
// Memory pool useds for CDmAttribute data
// Over 8 bytes, use the small-block allocator (it aligns to 16 bytes)
//-----------------------------------------------------------------------------
CUtlMemoryPool g_DataAlloc4( sizeof( CDmAttribute ), 4, CUtlMemoryPool::GROW_SLOW, "4-byte data pool" );
CUtlMemoryPool g_DataAlloc8( sizeof( CDmAttribute ), 8, CUtlMemoryPool::GROW_SLOW, "8-byte data pool" );
template< class T > void* NewData()
{
return new typename CDmAttributeInfo< T >::StorageType_t;
}
template< class T > void DeleteData( void *pData )
{
delete reinterpret_cast< typename CDmAttributeInfo< T >::StorageType_t * >( pData );
}
#define USE_SPECIAL_ALLOCATOR( _className, _allocator ) \
template<> void* NewData< _className >() \
{ \
void* pData = _allocator.Alloc( sizeof( CDmAttributeInfo< _className >::StorageType_t ) ); \
return ::new( pData ) CDmAttributeInfo< _className >::StorageType_t(); \
} \
template<> void DeleteData<_className>( void *pData ) \
{ \
typedef CDmAttributeInfo< _className >::StorageType_t D; \
( ( D * )pData )->~D(); \
_allocator.Free( pData ); \
}
// make sure that the attribute data type sizes are what we think they are to choose the right allocator
struct CSizeTest
{
CSizeTest()
{
// test internal value attribute sizes
COMPILE_TIME_ASSERT( sizeof( int ) == 4 );
COMPILE_TIME_ASSERT( sizeof( float ) == 4 );
COMPILE_TIME_ASSERT( sizeof( bool ) <= 4 );
COMPILE_TIME_ASSERT( sizeof( Color ) == 4 );
COMPILE_TIME_ASSERT( sizeof( DmElementAttribute_t ) <= 8 );
COMPILE_TIME_ASSERT( sizeof( Vector2D ) == 8 );
}
};
static CSizeTest g_sizeTest;
// turn memdbg off temporarily so we can get at placement new
#include "tier0/memdbgoff.h"
USE_SPECIAL_ALLOCATOR( bool, g_DataAlloc4 )
USE_SPECIAL_ALLOCATOR( int, g_DataAlloc4 )
USE_SPECIAL_ALLOCATOR( float, g_DataAlloc4 )
USE_SPECIAL_ALLOCATOR( DmElementHandle_t, g_DataAlloc4 )
USE_SPECIAL_ALLOCATOR( Color, g_DataAlloc4 )
USE_SPECIAL_ALLOCATOR( Vector2D, g_DataAlloc8 )
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Create, destroy attribute data
//-----------------------------------------------------------------------------
template< class T >
void* CDmAttributeOp<T>::CreateAttributeData()
{
void *pData = NewData< T >();
CDmAttributeInfo< T >::SetDefaultValue( *reinterpret_cast<T*>( pData ) );
return pData;
}
template<> void* CDmAttributeOp< DmUnknownAttribute_t >::CreateAttributeData()
{
// Fail if someone tries to create an AT_UNKNOWN attribute
Assert(0);
return NULL;
}
template< class T >
void CDmAttributeOp<T>::DestroyAttributeData( void *pData )
{
DeleteData< T >( pData );
}
//-----------------------------------------------------------------------------
// Sets the data to a default value, no undo (used for construction)
//-----------------------------------------------------------------------------
template< class T >
void CDmAttributeOp<T>::SetDefaultValue( void *pData )
{
CDmAttributeInfo< T >::SetDefaultValue( *reinterpret_cast<T*>( pData ) );
}
//-----------------------------------------------------------------------------
// Attribute type name, data size, value size
//-----------------------------------------------------------------------------
template< class T >
const char *CDmAttributeOp<T>::AttributeTypeName()
{
return CDmAttributeInfo<T>::AttributeTypeName();
}
template< class T >
int CDmAttributeOp<T>::DataSize()
{
return sizeof( typename CDmAttributeInfo< T >::StorageType_t );
}
template< class T >
int CDmAttributeOp<T>::ValueSize()
{
return sizeof( T );
}
//-----------------------------------------------------------------------------
// Value-setting methods
//-----------------------------------------------------------------------------
template< class T >
void CDmAttributeOp<T>::SetToDefaultValue( CDmAttribute *pAttribute )
{
T newValue;
CDmAttributeInfo< T >::SetDefaultValue( newValue );
pAttribute->SetValue( newValue );
}
template< class T >
void CDmAttributeOp<T>::SetMultiple( CDmAttribute *pAttribute, int i, int nCount, DmAttributeType_t valueType, const void *pValue )
{
Assert(0);
}
template< class T >
void CDmAttributeOp<T>::Set( CDmAttribute *pAttribute, int i, DmAttributeType_t valueType, const void *pValue )
{
Assert(0);
}
template< class T >
void CDmAttributeOp<T>::SetValue( CDmAttribute *pAttribute, DmAttributeType_t valueType, const void *pValue )
{
Assert( pAttribute->GetType() == valueType );
if ( pAttribute->GetType() == valueType )
{
pAttribute->SetValue( *reinterpret_cast< const T* >( pValue ) );
}
}
#define SET_VALUE_TYPE( _srcType ) \
case CDmAttributeInfo< _srcType >::ATTRIBUTE_TYPE: \
pAttribute->SetValue( *reinterpret_cast< const _srcType* >( pValue ) ); \
break;
template<>
void CDmAttributeOp<int>::SetValue( CDmAttribute *pAttribute, DmAttributeType_t valueType, const void *pValue )
{
switch( valueType )
{
SET_VALUE_TYPE( int );
SET_VALUE_TYPE( float );
SET_VALUE_TYPE( bool );
default:
Assert(0);
break;
}
}
template<>
void CDmAttributeOp<float>::SetValue( CDmAttribute *pAttribute, DmAttributeType_t valueType, const void *pValue )
{
switch( valueType )
{
SET_VALUE_TYPE( int );
SET_VALUE_TYPE( float );
SET_VALUE_TYPE( bool );
default:
Assert(0);
break;
}
}
template<>
void CDmAttributeOp<bool>::SetValue( CDmAttribute *pAttribute, DmAttributeType_t valueType, const void *pValue )
{
switch( valueType )
{
SET_VALUE_TYPE( int );
SET_VALUE_TYPE( float );
SET_VALUE_TYPE( bool );
default:
Assert(0);
break;
}
}
template<>
void CDmAttributeOp<QAngle>::SetValue( CDmAttribute *pAttribute, DmAttributeType_t valueType, const void *pValue )
{
switch( valueType )
{
SET_VALUE_TYPE( QAngle );
SET_VALUE_TYPE( Quaternion );
default:
Assert(0);
break;
}
}
template<>
void CDmAttributeOp<Quaternion>::SetValue( CDmAttribute *pAttribute, DmAttributeType_t valueType, const void *pValue )
{
switch( valueType )
{
SET_VALUE_TYPE( QAngle );
SET_VALUE_TYPE( Quaternion );
default:
Assert(0);
break;
}
}
//-----------------------------------------------------------------------------
// Methods related to serialization
//-----------------------------------------------------------------------------
template< class T >
bool CDmAttributeOp<T>::SerializesOnMultipleLines()
{
return ::SerializesOnMultipleLines< T >();
}
template< class T >
bool CDmAttributeOp<T>::SkipUnserialize( CUtlBuffer& buf )
{
T dummy;
::Unserialize( buf, dummy );
return buf.IsValid();
}
template< class T >
bool CDmAttributeOp<T>::Serialize( const CDmAttribute *pAttribute, CUtlBuffer &buf )
{
// NOTE: For this to work, the class must have a function defined of type
// bool Serialize( CUtlBuffer &buf, T &src )
return ::Serialize( buf, pAttribute->GetValue<T>() );
}
template< class T >
bool CDmAttributeOp<T>::Unserialize( CDmAttribute *pAttribute, CUtlBuffer &buf )
{
// NOTE: For this to work, the class must have a function defined of type
// bool Unserialize( CUtlBuffer &buf, T &src )
T tempVal;
bool bRet = ::Unserialize( buf, tempVal );
// Don't need undo hook since this goes through SetValue route
pAttribute->SetValue( tempVal );
return bRet;
}
template< class T >
bool CDmAttributeOp<T>::SerializeElement( const CDmAttribute *pData, int nElement, CUtlBuffer &buf )
{
Assert( 0 );
return false;
}
template< class T >
bool CDmAttributeOp<T>::UnserializeElement( CDmAttribute *pData, CUtlBuffer &buf )
{
Assert( 0 );
return false;
}
template< class T >
bool CDmAttributeOp<T>::UnserializeElement( CDmAttribute *pData, int nElement, CUtlBuffer &buf )
{
Assert( 0 );
return false;
}
template< class T >
void CDmAttributeOp<T>::OnUnserializationFinished( CDmAttribute *pAttribute )
{
CDmAttributeAccessor::OnChanged( pAttribute, false, true );
}
//-----------------------------------------------------------------------------
//
// Implementation of IDmAttributeOp for array attributes
//
//-----------------------------------------------------------------------------
template< class T >
class CDmArrayAttributeOp : public CDmAttributeOp< CUtlVector< T > >
{
typedef typename CDmAttributeInfo< CUtlVector< T > >::StorageType_t D;
public:
// Inherited from IDmAttributeOp
virtual void SetValue( CDmAttribute *pAttribute, DmAttributeType_t valueType, const void *pValue );
virtual void SetMultiple( CDmAttribute *pAttribute, int i, int nCount, DmAttributeType_t valueType, const void *pValue );
virtual void Set( CDmAttribute *pAttribute, int i, DmAttributeType_t valueType, const void *pValue );
virtual bool Unserialize( CDmAttribute *pAttribute, CUtlBuffer &buf );
virtual bool SerializeElement( const CDmAttribute *pData, int nElement, CUtlBuffer &buf );
virtual bool UnserializeElement( CDmAttribute *pData, CUtlBuffer &buf );
virtual bool UnserializeElement( CDmAttribute *pData, int nElement, CUtlBuffer &buf );
virtual void OnUnserializationFinished( CDmAttribute *pAttribute );
// Other methods used by CDmaArrayBase
CDmArrayAttributeOp() : m_pAttribute( NULL ), m_pData( NULL ) {}
CDmArrayAttributeOp( CDmAttribute *pAttribute ) : m_pAttribute( pAttribute ), m_pData( (D*)m_pAttribute->GetAttributeData() ) {}
// Count
int Count() const;
// Insertion
int AddToTail( const T& src );
int InsertBefore( int elem, const T& src );
int InsertMultipleBefore( int elem, int num );
// Removal
void FastRemove( int elem );
void Remove( int elem );
void RemoveAll();
void RemoveMultiple( int elem, int num );
void Purge();
// Element Modification
void Set( int i, const T& value );
void SetMultiple( int i, int nCount, const T* pValue );
void Swap( int i, int j );
// Copy related methods
void CopyArray( const T *pArray, int size );
void SwapArray( CUtlVector< T >& src ); // Performs a pointer swap
void OnAttributeArrayElementAdded( int nFirstElem, int nLastElem, bool bUpdateElementReferences = true );
void OnAttributeArrayElementRemoved( int nFirstElem, int nLastElem );
private:
bool ShouldInsertElement( const T& src );
bool ShouldInsert( const T& src );
void PerformCopyArray( const T *pArray, int nCount );
D& Data() { return *m_pData; }
const D& Data() const { return *m_pData; }
CDmAttribute *m_pAttribute;
D* m_pData;
};
//-----------------------------------------------------------------------------
//
// Undo-related classes
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Undo attribute name change
//-----------------------------------------------------------------------------
class CUndoAttributeRenameElement : public CUndoElement
{
typedef CUndoElement BaseClass;
public:
CUndoAttributeRenameElement( CDmAttribute *pAttribute, const char *newName )
: BaseClass( "CUndoAttributeRenameElement" )
{
Assert( pAttribute->GetOwner() && pAttribute->GetOwner()->GetFileId() != DMFILEID_INVALID );
m_hOwner = pAttribute->GetOwner()->GetHandle();
m_symAttributeOld = pAttribute->GetName();
m_symAttributeNew = newName;
}
virtual void Undo()
{
CDmElement *pOwner = GetOwner();
if ( pOwner )
{
pOwner->RenameAttribute( m_symAttributeNew.String(), m_symAttributeOld.String() );
}
}
virtual void Redo()
{
CDmElement *pOwner = GetOwner();
if ( pOwner )
{
pOwner->RenameAttribute( m_symAttributeOld.String(), m_symAttributeNew.String() );
}
}
virtual const char *GetDesc()
{
static char buf[ 128 ];
const char *base = BaseClass::GetDesc();
Q_snprintf( buf, sizeof( buf ), "%s (%s -> %s)", base, m_symAttributeOld.String(), m_symAttributeNew.String() );
return buf;
}
private:
CDmElement *GetOwner()
{
return g_pDataModel->GetElement( m_hOwner );
}
CUtlSymbol m_symAttributeOld;
CUtlSymbol m_symAttributeNew;
DmElementHandle_t m_hOwner;
};
//-----------------------------------------------------------------------------
// Undo single-valued attribute value changed
//-----------------------------------------------------------------------------
template< class T >
class CUndoAttributeSetValueElement : public CUndoElement
{
typedef CUndoElement BaseClass;
public:
CUndoAttributeSetValueElement( CDmAttribute *pAttribute, const T &newValue )
: BaseClass( "CUndoAttributeSetValueElement" )
{
Assert( pAttribute->GetOwner() && pAttribute->GetOwner()->GetFileId() != DMFILEID_INVALID );
m_hOwner = pAttribute->GetOwner()->GetHandle();
m_OldValue = pAttribute->GetValue<T>();
m_Value = newValue;
m_symAttribute = pAttribute->GetNameSymbol( );
}
CDmElement *GetOwner()
{
return g_pDataModel->GetElement( m_hOwner );
}
virtual void Undo()
{
CDmAttribute *pAttribute = GetAttribute();
if ( pAttribute && !pAttribute->IsFlagSet( FATTRIB_READONLY ) )
{
pAttribute->SetValue<T>( m_OldValue );
}
}
virtual void Redo()
{
CDmAttribute *pAttribute = GetAttribute();
if ( pAttribute && !pAttribute->IsFlagSet( FATTRIB_READONLY ) )
{
pAttribute->SetValue<T>( m_Value );
}
}
virtual const char *GetDesc()
{
static char buf[ 128 ];
const char *base = BaseClass::GetDesc();
CDmAttribute *pAtt = GetAttribute();
CUtlBuffer serialized( 0, 0, CUtlBuffer::TEXT_BUFFER );
if ( pAtt && pAtt->GetType() != AT_ELEMENT )
{
::Serialize( serialized, m_Value );
}
Q_snprintf( buf, sizeof( buf ), "%s(%s) = %s", base, g_pDataModel->GetString( m_symAttribute ), serialized.Base() ? (const char*)serialized.Base() : "\"\"" );
return buf;
}
private:
CDmAttribute *GetAttribute()
{
CDmElement *pOwner = GetOwner();
if ( pOwner )
{
const char *pAttributeName = g_pDataModel->GetString( m_symAttribute );
return pOwner->GetAttribute( pAttributeName );
}
return NULL;
}
typedef T StorageType_t;
CUtlSymbol m_symAttribute;
DmElementHandle_t m_hOwner;
StorageType_t m_OldValue;
StorageType_t m_Value;
};
//-----------------------------------------------------------------------------
// Base undo for array attributes
//-----------------------------------------------------------------------------
template< class T >
class CUndoAttributeArrayBase : public CUndoElement
{
typedef CUndoElement BaseClass;
public:
CUndoAttributeArrayBase( CDmAttribute *pAttribute, const char *pUndoName ) : BaseClass( pUndoName )
{
m_hOwner = pAttribute->GetOwner()->GetHandle();
m_symAttribute = pAttribute->GetNameSymbol( );
}
protected:
typedef typename CDmAttributeUndoStorageType< T >::UndoStorageType StorageType_t;
CDmElement *GetOwner()
{
return g_pDataModel->GetElement( m_hOwner );
}
const char *GetAttributeName()
{
return g_pDataModel->GetString( m_symAttribute );
}
CDmAttribute *GetAttribute()
{
const char *pAttributeName = GetAttributeName();
CDmElement *pOwner = GetOwner();
if ( pOwner )
return pOwner->GetAttribute( pAttributeName );
Assert( 0 );
return NULL;
}
private:
CUtlSymbol m_symAttribute;
DmElementHandle_t m_hOwner;
};
//-----------------------------------------------------------------------------
// Undo for setting a single element
//-----------------------------------------------------------------------------
template< class T >
class CUndoArrayAttributeSetValueElement : public CUndoAttributeArrayBase<T>
{
typedef CUndoAttributeArrayBase<T> BaseClass;
public:
CUndoArrayAttributeSetValueElement( CDmAttribute *pAttribute, int slot, const T &newValue ) :
BaseClass( pAttribute, "CUndoArrayAttributeSetValueElement" ),
m_nSlot( slot )
{
Assert( pAttribute->GetOwner() && pAttribute->GetOwner()->GetFileId() != DMFILEID_INVALID );
CDmrArray<T> array( pAttribute );
m_OldValue = array[ slot ];
m_Value = newValue;
}
virtual void Undo()
{
CDmrArray<T> array( GetAttribute() );
if ( array.IsValid() )
{
array.Set( m_nSlot, m_OldValue );
}
}
virtual void Redo()
{
CDmrArray<T> array( GetAttribute() );
if ( array.IsValid() )
{
array.Set( m_nSlot, m_Value );
}
}
private:
int m_nSlot;
typename CUndoAttributeArrayBase<T>::StorageType_t m_OldValue;
typename CUndoAttributeArrayBase<T>::StorageType_t m_Value;
};
//-----------------------------------------------------------------------------
// Undo for setting a multiple elements
//-----------------------------------------------------------------------------
template< class T >
class CUndoArrayAttributeSetMultipleValueElement : public CUndoAttributeArrayBase<T>
{
typedef CUndoAttributeArrayBase<T> BaseClass;
public:
CUndoArrayAttributeSetMultipleValueElement( CDmAttribute *pAttribute, int nSlot, int nCount, const T *pNewValue ) :
BaseClass( pAttribute, "CUndoArrayAttributeSetMultipleValueElement" ),
m_nSlot( nSlot ), m_nCount( nCount )
{
Assert( pAttribute->GetOwner() && pAttribute->GetOwner()->GetFileId() != DMFILEID_INVALID );
m_pOldValue = new typename CUndoAttributeArrayBase<T>::StorageType_t[nCount];
m_pValue = new typename CUndoAttributeArrayBase<T>::StorageType_t[nCount];
CDmrArray<T> array( pAttribute );
for ( int i = 0; i < nCount; ++i )
{
m_pOldValue[i] = array[ nSlot+i ];
m_pValue[i] = pNewValue[ i ];
}
}
~CUndoArrayAttributeSetMultipleValueElement()
{
// this is a hack necessitated by MSVC's lack of partially specialized member template support
// (ie otherwise I'd just create a CUndoArrayAttributeSetMultipleValueElement< DmElementHandle_t,BaseClass> version with this code)
// anyways, the casting hackiness only happens when the value is actually a DmElementHandle_t, so it's completely safe
if ( CDmAttributeInfo< T >::AttributeType() == AT_ELEMENT )
{
DmElementHandle_t value = DMELEMENT_HANDLE_INVALID;
for ( int i = 0; i < m_nCount; ++i )
{
m_pOldValue[ i ] = m_pValue[ i ] = *( T* )&value;
}
}
delete[] m_pOldValue;
delete[] m_pValue;
}
virtual void Undo()
{
CDmrArray<T> array( GetAttribute() );
if ( array.IsValid() )
{
for ( int i = 0; i < m_nCount; ++i )
{
array.Set( m_nSlot+i, m_pOldValue[i] );
}
}
}
virtual void Redo()
{
CDmrArray<T> array( GetAttribute() );
if ( array.IsValid() )
{
for ( int i = 0; i < m_nCount; ++i )
{
array.Set( m_nSlot+i, m_pValue[i] );
}
}
}
private:
int m_nSlot;
int m_nCount;
typename CUndoAttributeArrayBase<T>::StorageType_t *m_pOldValue;
typename CUndoAttributeArrayBase<T>::StorageType_t *m_pValue;
};
//-----------------------------------------------------------------------------
//
// Implementation Undo for CDmAttributeTyped
//
//-----------------------------------------------------------------------------
template< class T >
class CUndoAttributeArrayInsertBefore : public CUndoAttributeArrayBase<T>
{
typedef CUndoAttributeArrayBase<T> BaseClass;
public:
CUndoAttributeArrayInsertBefore( CDmAttribute *pAttribute, int slot, int count = 1 ) :
BaseClass( pAttribute, "CUndoAttributeArrayInsertBefore" ),
m_nIndex( slot ), m_nCount( count )
{
Assert( pAttribute->GetOwner() && pAttribute->GetOwner()->GetFileId() != DMFILEID_INVALID );
}
virtual void Undo()
{
CDmrArray<T> array( GetAttribute() );
if ( array.IsValid() )
{
array.RemoveMultiple( m_nIndex, m_nCount );
}
}
virtual void Redo()
{
CDmrArray<T> array( GetAttribute() );
if ( array.IsValid() )
{
T defaultVal;
CDmAttributeInfo<T>::SetDefaultValue( defaultVal );
array.InsertMultipleBefore( m_nIndex, m_nCount );
for( int i = 0; i < m_nCount; ++i )
{
array.Set( m_nIndex + i, defaultVal );
}
}
}
private:
int m_nIndex;
int m_nCount;
};
//-----------------------------------------------------------------------------
//
// Implementation Undo for inserting a copy
//
//-----------------------------------------------------------------------------
template< class T >
class CUndoAttributeArrayInsertCopyBefore : public CUndoAttributeArrayBase<T>
{
typedef CUndoAttributeArrayBase<T> BaseClass;
public:
CUndoAttributeArrayInsertCopyBefore( CDmAttribute *pAttribute, int slot, const T& newValue ) :
BaseClass( pAttribute, "CUndoAttributeArrayInsertCopyBefore" ),
m_nIndex( slot ),
m_newValue( newValue )
{
Assert( pAttribute->GetOwner() && pAttribute->GetOwner()->GetFileId() != DMFILEID_INVALID );
}
virtual void Undo()
{
CDmrArray<T> array( GetAttribute() );
if ( array.IsValid() )
{
array.Remove( m_nIndex );
}
}
virtual void Redo()
{
CDmrArray<T> array( GetAttribute() );
if ( array.IsValid() )
{
array.InsertBefore( m_nIndex, m_newValue );
}
}
private:
int m_nIndex;
typename CUndoAttributeArrayBase<T>::StorageType_t m_newValue;
};
//-----------------------------------------------------------------------------
//
// Implementation Undo for remove
//
//-----------------------------------------------------------------------------
template< class T >
class CUndoAttributeArrayRemoveElement : public CUndoAttributeArrayBase<T>
{
typedef CUndoAttributeArrayBase<T> BaseClass;
public:
CUndoAttributeArrayRemoveElement( CDmAttribute *pAttribute, bool fastRemove, int elem, int count ) :
BaseClass( pAttribute, "CUndoAttributeArrayRemoveElement" ),
m_bFastRemove( fastRemove ), m_nIndex( elem ), m_nCount( count )
{
Assert( pAttribute->GetOwner() && pAttribute->GetOwner()->GetFileId() != DMFILEID_INVALID );
Assert( m_nCount >= 1 );
// If it's fastremove, count must == 1
Assert( !m_bFastRemove || m_nCount == 1 );
CDmrArray< T > array( pAttribute );
Assert( array.IsValid() );
for ( int i = 0 ; i < m_nCount; ++i )
{
m_OldValues.AddToTail( array[ elem + i ] );
}
}
~CUndoAttributeArrayRemoveElement()
{
// this is a hack necessitated by MSVC's lack of partially specialized member template support
// (ie otherwise I'd just create a CUndoArrayAttributeSetMultipleValueElement< DmElementHandle_t,BaseClass> version with this code)
// anyways, the casting hackiness only happens when the value is actually a DmElementHandle_t, so it's completely safe
if ( CDmAttributeInfo< T >::AttributeType() == AT_ELEMENT )
{
DmElementHandle_t value = DMELEMENT_HANDLE_INVALID;
for ( int i = 0; i < m_nCount; ++i )
{
m_OldValues[ i ] = *( T* )&value;
}
m_OldValues.RemoveAll();
}
}
virtual void Undo()
{
CDmrArray<T> array( GetAttribute() );
if ( array.IsValid() )
{
if ( m_bFastRemove )
{
Assert( m_nCount == 1 );
Assert( m_OldValues.Count() == 1 );
if ( array.Count() > m_nIndex )
{
// Get value at previous index (it was moved down from the "end" before
T m_EndValue = array.Get( m_nIndex );
// Restore previous value
array.Set( m_nIndex, m_OldValues[ 0 ] );
// Put old value back to end of array
array.AddToTail( m_EndValue );
}
else
{
Assert( array.Count() == m_nIndex );
array.AddToTail( m_OldValues[ 0 ] );
}
}
else
{
int insertPos = m_nIndex;
for ( int i = 0; i < m_nCount; ++i )
{
array.InsertBefore( insertPos++, m_OldValues[ i ] );
}
}
}
}
virtual void Redo()
{
CDmrArray<T> array( GetAttribute() );
if ( array.IsValid() )
{
if ( m_bFastRemove )
{
Assert( m_nCount == 1 );
Assert( m_OldValues.Count() == 1 );
array.FastRemove( m_nIndex );
}
else
{
array.RemoveMultiple( m_nIndex, m_nCount );
}
}
}
virtual const char *GetDesc()
{
static char buf[ 128 ];
const char *base = BaseClass::GetDesc();
Q_snprintf( buf, sizeof( buf ), "%s (%s) = remove( pos %i, count %i )", base, GetAttributeName(), m_nIndex, m_nCount );
return buf;
}
private:
bool m_bFastRemove;
int m_nIndex;
int m_nCount;
CUtlVector< typename CUndoAttributeArrayBase<T>::StorageType_t > m_OldValues;
};
template< class T >
class CUndoAttributeArrayCopyAllElement : public CUndoAttributeArrayBase<T>
{
typedef CUndoAttributeArrayBase<T> BaseClass;
public:
CUndoAttributeArrayCopyAllElement( CDmAttribute *pAttribute, const T *pNewValues, int nNewSize, bool purgeOnRemove = false )
: BaseClass( pAttribute, "CUndoAttributeArrayCopyAllElement" ),
m_bPurge( purgeOnRemove )
{
Assert( pAttribute->GetOwner() && pAttribute->GetOwner()->GetFileId() != DMFILEID_INVALID );
CDmrArray< T > att( pAttribute );
Assert( att.IsValid() );
if ( pNewValues != NULL && nNewSize > 0 )
{
m_pNewValues = new typename CUndoAttributeArrayBase<T>::StorageType_t[ nNewSize ];
for ( int i = 0; i < nNewSize; ++i )
{
m_pNewValues[ i ] = pNewValues[ i ];
}
m_nNewSize = nNewSize;
}
else
{
m_pNewValues = NULL;
m_nNewSize = 0;
}
int nOldSize = att.Count();
const T *pOldValues = att.Base();
if ( pOldValues != NULL && nOldSize > 0 )
{
m_pOldValues = new typename CUndoAttributeArrayBase<T>::StorageType_t[ nOldSize ];
for ( int i = 0; i < nOldSize; ++i )
{
m_pOldValues[ i ] = pOldValues[ i ];
}
m_nOldSize = nOldSize;
}
else
{
m_pOldValues = NULL;
m_nOldSize = 0;
}
}
~CUndoAttributeArrayCopyAllElement()
{
// this is a hack necessitated by MSVC's lack of partially specialized member template support
// (ie otherwise I'd just create a CUndoArrayAttributeSetMultipleValueElement< DmElementHandle_t,BaseClass> version with this code)
// anyways, the casting hackiness only happens when the value is actually a DmElementHandle_t, so it's completely safe
if ( CDmAttributeInfo< T >::AttributeType() == AT_ELEMENT )
{
DmElementHandle_t value = DMELEMENT_HANDLE_INVALID;
for ( int i = 0; i < m_nOldSize; ++i )
{
m_pOldValues[ i ] = *( T* )&value;
}
for ( int i = 0; i < m_nNewSize; ++i )
{
m_pNewValues[ i ] = *( T* )&value;
}
}
delete[] m_pOldValues;
delete[] m_pNewValues;
}
virtual void Undo()
{
CDmrArray<T> array( GetAttribute() );
if ( array.IsValid() )
{
array.RemoveAll();
for ( int i = 0; i < m_nOldSize; ++i )
{
array.AddToTail( m_pOldValues[ i ] );
}
}
}
virtual void Redo()
{
CDmrArray<T> array( GetAttribute() );
if ( array.IsValid() )
{
array.RemoveAll();
for ( int i = 0; i < m_nNewSize; ++i )
{
array.AddToTail( m_pNewValues[ i ] );
}
if ( m_bPurge )
{
Assert( array.Count() == 0 );
array.Purge();
}
}
}
private:
typename CUndoAttributeArrayBase<T>::StorageType_t *m_pOldValues;
int m_nOldSize;
typename CUndoAttributeArrayBase<T>::StorageType_t *m_pNewValues;
int m_nNewSize;
bool m_bPurge;
};
//-----------------------------------------------------------------------------
// CDmArrayAttributeOp implementation.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Callbacks when elements are added + removed
//-----------------------------------------------------------------------------
template< class T >
void CDmArrayAttributeOp<T>::OnAttributeArrayElementAdded( int nFirstElem, int nLastElem, bool bUpdateElementReferences )
{
CDmElement *pOwner = m_pAttribute->GetOwner();
if ( m_pAttribute->IsFlagSet( FATTRIB_HAS_ARRAY_CALLBACK ) && !CDmeElementAccessor::IsBeingUnserialized( pOwner ) )
{
pOwner->OnAttributeArrayElementAdded( m_pAttribute, nFirstElem, nLastElem );
}
}
template< > inline void CDmArrayAttributeOp< DmElementHandle_t >::OnAttributeArrayElementAdded( int nFirstElem, int nLastElem, bool bUpdateElementReferences )
{
CDmElement *pOwner = m_pAttribute->GetOwner();
if ( m_pAttribute->IsFlagSet( FATTRIB_HAS_ARRAY_CALLBACK ) && !CDmeElementAccessor::IsBeingUnserialized( pOwner ) )
{
pOwner->OnAttributeArrayElementAdded( m_pAttribute, nFirstElem, nLastElem );
}
if ( bUpdateElementReferences )
{
for ( int i = nFirstElem; i <= nLastElem; ++i )
{
g_pDataModelImp->OnElementReferenceAdded( Data()[ i ], m_pAttribute );
}
}
}
template< class T >
void CDmArrayAttributeOp<T>::OnAttributeArrayElementRemoved( int nFirstElem, int nLastElem )
{
CDmElement *pOwner = m_pAttribute->GetOwner();
if ( m_pAttribute->IsFlagSet( FATTRIB_HAS_ARRAY_CALLBACK ) && !CDmeElementAccessor::IsBeingUnserialized( pOwner ) )
{
pOwner->OnAttributeArrayElementRemoved( m_pAttribute, nFirstElem, nLastElem );
}
}
template< > void CDmArrayAttributeOp< DmElementHandle_t >::OnAttributeArrayElementRemoved( int nFirstElem, int nLastElem )
{
CDmElement *pOwner = m_pAttribute->GetOwner();
if ( m_pAttribute->IsFlagSet( FATTRIB_HAS_ARRAY_CALLBACK ) && !CDmeElementAccessor::IsBeingUnserialized( pOwner ) )
{
pOwner->OnAttributeArrayElementRemoved( m_pAttribute, nFirstElem, nLastElem );
}
for ( int i = nFirstElem; i <= nLastElem; ++i )
{
g_pDataModelImp->OnElementReferenceRemoved( Data()[ i ], m_pAttribute );
}
}
//-----------------------------------------------------------------------------
// Count
//-----------------------------------------------------------------------------
template< class T >
int CDmArrayAttributeOp<T>::Count() const
{
return Data().Count();
}
//-----------------------------------------------------------------------------
// Should we insert this element into the list?
//-----------------------------------------------------------------------------
template< class T >
inline bool CDmArrayAttributeOp<T>::ShouldInsertElement( const T& src )
{
return true;
}
template<> inline bool CDmArrayAttributeOp<DmElementHandle_t>::ShouldInsertElement( const DmElementHandle_t& src )
{
// For element, we need to check that the type matches
if ( !IsA( src, Data().m_ElementType ) )
return false;
if ( m_pAttribute->IsFlagSet( FATTRIB_NODUPLICATES ) )
{
// See if value exists
int idx = Data().Find( src );
if ( idx != Data().InvalidIndex() )
return false;
}
return true;
}
template< class T >
inline bool CDmArrayAttributeOp<T>::ShouldInsert( const T& src )
{
if ( !ShouldInsertElement( src ) )
return false;
return m_pAttribute->MarkDirty();
}
//-----------------------------------------------------------------------------
// Insert Before
//-----------------------------------------------------------------------------
template< class T >
int CDmArrayAttributeOp<T>::InsertBefore( int elem, const T& src )
{
if ( !ShouldInsert( src ) )
return Data().InvalidIndex();
if ( g_pDataModel->UndoEnabledForElement( m_pAttribute->GetOwner() ) )
{
CUndoAttributeArrayInsertCopyBefore<T> *pUndo = new CUndoAttributeArrayInsertCopyBefore<T>( m_pAttribute, elem, src );
g_pDataModel->AddUndoElement( pUndo );
}
m_pAttribute->PreChanged();
int nIndex = Data().InsertBefore( elem, src );
OnAttributeArrayElementAdded( nIndex, nIndex );
m_pAttribute->OnChanged( true );
return nIndex;
}
template< class T >
inline int CDmArrayAttributeOp<T>::AddToTail( const T& src )
{
return InsertBefore( Data().Count(), src );
}
//-----------------------------------------------------------------------------
// Insert Multiple Before
//-----------------------------------------------------------------------------
template< class T >
int CDmArrayAttributeOp<T>::InsertMultipleBefore( int elem, int num )
{
if ( !m_pAttribute->MarkDirty() )
return Data().InvalidIndex();
// UNDO HOOK
if ( g_pDataModel->UndoEnabledForElement( m_pAttribute->GetOwner() ) )
{
CUndoAttributeArrayInsertBefore<T> *pUndo = new CUndoAttributeArrayInsertBefore<T>( m_pAttribute, elem, num );
g_pDataModel->AddUndoElement( pUndo );
}
m_pAttribute->PreChanged();
int index = Data().InsertMultipleBefore( elem, num );
for ( int i = 0; i < num; ++i )
{
CDmAttributeInfo<T>::SetDefaultValue( Data()[ index + i ] );
}
OnAttributeArrayElementAdded( index, index + num - 1 );
m_pAttribute->OnChanged( true );
return index;
}
//-----------------------------------------------------------------------------
// Removal
//-----------------------------------------------------------------------------
template< class T >
void CDmArrayAttributeOp<T>::FastRemove( int elem )
{
if ( !m_pAttribute->MarkDirty() )
return;
// UNDO HOOK
if ( g_pDataModel->UndoEnabledForElement( m_pAttribute->GetOwner() ) )
{
CUndoAttributeArrayRemoveElement<T> *pUndo = new CUndoAttributeArrayRemoveElement<T>( m_pAttribute, true, elem, 1 );
g_pDataModel->AddUndoElement( pUndo );
}
m_pAttribute->PreChanged();
OnAttributeArrayElementRemoved( elem, elem );
Data().FastRemove( elem );
m_pAttribute->OnChanged( true );
}
template< class T >
void CDmArrayAttributeOp<T>::Remove( int elem )
{
if ( !Data().IsValidIndex( elem ) )
return;
if ( !m_pAttribute->MarkDirty() )
return;
// UNDO HOOK
if ( g_pDataModel->UndoEnabledForElement( m_pAttribute->GetOwner() ) )
{
CUndoAttributeArrayRemoveElement<T> *pUndo = new CUndoAttributeArrayRemoveElement<T>( m_pAttribute, false, elem, 1 );
g_pDataModel->AddUndoElement( pUndo );
}
m_pAttribute->PreChanged();
OnAttributeArrayElementRemoved( elem, elem );
Data().Remove( elem );
m_pAttribute->OnChanged( true );
}
template< class T >
void CDmArrayAttributeOp<T>::RemoveAll()
{
if ( !m_pAttribute->MarkDirty() )
return;
// UNDO HOOK
if ( g_pDataModel->UndoEnabledForElement( m_pAttribute->GetOwner() ) )
{
CUndoAttributeArrayCopyAllElement<T> *pUndo = new CUndoAttributeArrayCopyAllElement<T>( m_pAttribute, NULL, 0 );
g_pDataModel->AddUndoElement( pUndo );
}
m_pAttribute->PreChanged();
OnAttributeArrayElementRemoved( 0, Data().Count() - 1 );
Data().RemoveAll();
m_pAttribute->OnChanged( true );
}
template< class T >
void CDmArrayAttributeOp<T>::RemoveMultiple( int elem, int num )
{
if ( !m_pAttribute->MarkDirty() )
return;
// UNDO HOOK
if ( g_pDataModel->UndoEnabledForElement( m_pAttribute->GetOwner() ) )
{
CUndoAttributeArrayRemoveElement<T> *pUndo = new CUndoAttributeArrayRemoveElement<T>( m_pAttribute, false, elem, num );
g_pDataModel->AddUndoElement( pUndo );
}
m_pAttribute->PreChanged();
OnAttributeArrayElementRemoved( elem, elem + num - 1 );
Data().RemoveMultiple( elem, num );
m_pAttribute->OnChanged( true );
}
// Memory deallocation
template< class T >
void CDmArrayAttributeOp<T>::Purge()
{
if ( !m_pAttribute->MarkDirty() )
return;
// UNDO HOOK
if ( g_pDataModel->UndoEnabledForElement( m_pAttribute->GetOwner() ) )
{
CUndoAttributeArrayCopyAllElement<T> *pUndo = new CUndoAttributeArrayCopyAllElement<T>( m_pAttribute, NULL, true );
g_pDataModel->AddUndoElement( pUndo );
}
m_pAttribute->PreChanged();
OnAttributeArrayElementRemoved( 0, Data().Count() - 1 );
Data().Purge();
m_pAttribute->OnChanged( true );
}
//-----------------------------------------------------------------------------
// Copy Array
//-----------------------------------------------------------------------------
template< class T >
void CDmArrayAttributeOp<T>::PerformCopyArray( const T *pArray, int nCount )
{
Data().CopyArray( pArray, nCount );
}
template<> void CDmArrayAttributeOp<DmElementHandle_t>::PerformCopyArray( const DmElementHandle_t *pArray, int nCount )
{
Data().RemoveAll();
for ( int i = 0; i < nCount; ++i )
{
if ( ShouldInsertElement( pArray[ i ] ) )
{
Data().AddToTail( pArray[ i ] );
}
}
}
template< class T >
void CDmArrayAttributeOp<T>::CopyArray( const T *pArray, int nCount )
{
if ( Data().Base() == pArray )
{
int nCurrentCount = Data().Count();
if ( nCurrentCount > nCount )
{
RemoveMultiple( nCount, nCurrentCount - nCount );
}
else if ( nCurrentCount < nCount )
{
InsertMultipleBefore( nCurrentCount, nCount - nCurrentCount );
}
return;
}
if ( !m_pAttribute->MarkDirty() )
return;
// UNDO HOOK
if ( g_pDataModel->UndoEnabledForElement( m_pAttribute->GetOwner() ) )
{
CUndoAttributeArrayCopyAllElement<T> *pUndo = new CUndoAttributeArrayCopyAllElement<T>( m_pAttribute, pArray, nCount );
g_pDataModel->AddUndoElement( pUndo );
}
m_pAttribute->PreChanged();
OnAttributeArrayElementRemoved( 0, Data().Count() - 1 );
PerformCopyArray( pArray, nCount );
OnAttributeArrayElementAdded( 0, Data().Count() - 1 );
m_pAttribute->OnChanged( true );
}
//-----------------------------------------------------------------------------
// Swap Array
//-----------------------------------------------------------------------------
template< class T >
void CDmArrayAttributeOp<T>::SwapArray( CUtlVector< T >& src )
{
// this is basically just a faster version of CopyArray
// the end result (for purposes of undo) are the same
// but there's no copy - just a pointer/etc swap
if ( !m_pAttribute->MarkDirty() )
return;
// UNDO HOOK
if ( g_pDataModel->UndoEnabledForElement( m_pAttribute->GetOwner() ) )
{
CUndoAttributeArrayCopyAllElement<T> *pUndo = new CUndoAttributeArrayCopyAllElement<T>( m_pAttribute, src.Base(), src.Count() );
g_pDataModel->AddUndoElement( pUndo );
}
m_pAttribute->PreChanged();
OnAttributeArrayElementRemoved( 0, Data().Count() - 1 );
Data().Swap( src );
OnAttributeArrayElementAdded( 0, Data().Count() - 1 );
m_pAttribute->OnChanged( true );
}
template< > void CDmArrayAttributeOp<DmElementHandle_t>::SwapArray( CUtlVector< DmElementHandle_t >& src )
{
// This feature doesn't work for elements..
// Can't do it owing to typesafety reasons as well as supporting the NODUPLICATES feature.
Assert( 0 );
}
//-----------------------------------------------------------------------------
// Set value
//-----------------------------------------------------------------------------
template< class T >
void CDmArrayAttributeOp<T>::Set( int i, const T& value )
{
if ( i < 0 || i >= Data().Count() )
{
Assert( !"CDmAttributeArray<T>::Set out of range value!\n" );
return;
}
// Don't bother doing anything if the attribute is equal
if ( IsAttributeEqual( Data()[i], value ) )
return;
if ( !ShouldInsert( value ) )
return;
if ( g_pDataModel->UndoEnabledForElement( m_pAttribute->GetOwner() ) )
{
CUndoArrayAttributeSetValueElement<T> *pUndo = new CUndoArrayAttributeSetValueElement<T>( m_pAttribute, i, value );
g_pDataModel->AddUndoElement( pUndo );
}
m_pAttribute->PreChanged();
OnAttributeArrayElementRemoved( i, i );
Data()[i] = value;
OnAttributeArrayElementAdded( i, i );
m_pAttribute->OnChanged( false );
}
template< class T >
void CDmArrayAttributeOp<T>::Set( CDmAttribute *pAttribute, int i, DmAttributeType_t valueType, const void *pValue )
{
if ( valueType == ArrayTypeToValueType( pAttribute->GetType() ) )
{
// This version is in IDmAttributeOp
CDmArrayAttributeOp< T > array( pAttribute );
array.Set( i, *(const T*)pValue );
}
}
//-----------------------------------------------------------------------------
// Set multiple values
//-----------------------------------------------------------------------------
template< class T >
void CDmArrayAttributeOp<T>::SetMultiple( int i, int nCount, const T* pValue )
{
if ( i < 0 || ( i+nCount ) > Data().Count() )
{
AssertMsg( 0, "CDmAttributeArray<T>::SetMultiple out of range value!\n" );
return;
}
// Test for equality
bool bEqual = true;
for ( int j = 0; j < nCount; ++j )
{
if ( !IsAttributeEqual( Data()[i+j], pValue[j] ) )
{
bEqual = false;
break;
}
}
if ( bEqual )
return;
if ( !m_pAttribute->MarkDirty() )
return;
if ( g_pDataModel->UndoEnabledForElement( m_pAttribute->GetOwner() ) )
{
CUndoArrayAttributeSetMultipleValueElement<T> *pUndo = new CUndoArrayAttributeSetMultipleValueElement<T>( m_pAttribute, i, nCount, pValue );
g_pDataModel->AddUndoElement( pUndo );
}
m_pAttribute->PreChanged();
OnAttributeArrayElementRemoved( i, i+nCount-1 );
for ( int j = 0; j < nCount; ++j )
{
if ( ShouldInsertElement( pValue[j] ) )
{
Data()[i+j] = pValue[j];
}
}
OnAttributeArrayElementAdded( i, i+nCount-1 );
m_pAttribute->OnChanged( false );
}
template< class T >
void CDmArrayAttributeOp<T>::SetMultiple( CDmAttribute *pAttribute, int i, int nCount, DmAttributeType_t valueType, const void *pValue )
{
if ( valueType == ArrayTypeToValueType( pAttribute->GetType() ) )
{
// This version is in IDmAttributeOp
CDmArrayAttributeOp< T > array( pAttribute );
array.SetMultiple( i, nCount, (const T*)pValue );
}
}
//-----------------------------------------------------------------------------
// Version of SetValue that's in IDmAttributeOp
//-----------------------------------------------------------------------------
template< class T >
void CDmArrayAttributeOp<T>::SetValue( CDmAttribute *pAttribute, DmAttributeType_t valueType, const void *pValue )
{
Assert( pAttribute->GetType() == valueType );
if ( pAttribute->GetType() == valueType )
{
CDmArrayAttributeOp<T> accessor( pAttribute );
const CUtlVector<T>* pArray = reinterpret_cast< const CUtlVector<T>* >( pValue );
accessor.CopyArray( pArray->Base(), pArray->Count() );
}
}
//-----------------------------------------------------------------------------
// Swap
//-----------------------------------------------------------------------------
template< class T >
void CDmArrayAttributeOp<T>::Swap( int i, int j )
{
if ( i == j )
return;
// TODO - define Swap<T> for all attribute types to make swapping strings
// and voids fast (via pointer swaps, rather than 3 copies!)
T vk = Data()[ i ];
if ( IsAttributeEqual( vk, Data()[j] ) )
return;
if ( !m_pAttribute->MarkDirty() )
return;
if ( g_pDataModel->UndoEnabledForElement( m_pAttribute->GetOwner() ) )
{
CUndoArrayAttributeSetValueElement<T> *pUndo = new CUndoArrayAttributeSetValueElement<T>( m_pAttribute, i, Data()[ j ] );
g_pDataModel->AddUndoElement( pUndo );
pUndo = new CUndoArrayAttributeSetValueElement<T>( m_pAttribute, j, vk );
g_pDataModel->AddUndoElement( pUndo );
}
m_pAttribute->PreChanged();
OnAttributeArrayElementRemoved( i, i );
Data()[i] = Data()[j];
OnAttributeArrayElementAdded( i, i );
OnAttributeArrayElementRemoved( j, j );
Data()[j] = vk;
OnAttributeArrayElementAdded( j, j );
m_pAttribute->OnChanged( false );
}
//-----------------------------------------------------------------------------
// Methods related to serialization
//-----------------------------------------------------------------------------
template< class T >
bool CDmArrayAttributeOp<T>::Unserialize( CDmAttribute *pAttribute, CUtlBuffer &buf )
{
if ( !pAttribute->MarkDirty() )
return false;
MEM_ALLOC_CREDIT_CLASS();
CUtlVector< T > tempVal;
bool bRet = ::Unserialize( buf, tempVal );
// Don't need undo hook since this goes through Swap route
CDmArrayAttributeOp<T> accessor( pAttribute );
accessor.SwapArray( tempVal );
return bRet;
}
template<> bool CDmArrayAttributeOp<DmElementHandle_t>::Unserialize( CDmAttribute *pAttribute, CUtlBuffer &buf )
{
// Need to specialize this because element handles can't use SwapArray
// because it's incapable of doing type safety checks or looking for FATTRIB_NODUPLICATES
if ( !CDmAttributeAccessor::MarkDirty( pAttribute ) )
return false;
MEM_ALLOC_CREDIT_CLASS();
CUtlVector< DmElementHandle_t > tempVal;
bool bRet = ::Unserialize( buf, tempVal );
// Don't need undo hook since this goes through copy route
CDmArrayAttributeOp<DmElementHandle_t> accessor( pAttribute );
accessor.CopyArray( tempVal.Base(), tempVal.Count() );
return bRet;
}
// Serialization of a single element
template< class T >
bool CDmArrayAttributeOp<T>::SerializeElement( const CDmAttribute *pAttribute, int nElement, CUtlBuffer &buf )
{
CDmrArrayConst<T> array( pAttribute );
return ::Serialize( buf, array[ nElement ] );
}
template< class T >
bool CDmArrayAttributeOp<T>::UnserializeElement( CDmAttribute *pAttribute, CUtlBuffer &buf )
{
if ( !CDmAttributeAccessor::MarkDirty( pAttribute ) )
return false;
MEM_ALLOC_CREDIT_CLASS();
T temp;
bool bReadElement = ::Unserialize( buf, temp );
if ( bReadElement )
{
pAttribute->PreChanged();
CDmArrayAttributeOp<T> accessor( pAttribute );
accessor.AddToTail( temp );
pAttribute->OnChanged( true );
}
return bReadElement;
}
template< class T >
bool CDmArrayAttributeOp<T>::UnserializeElement( CDmAttribute *pAttribute, int nElement, CUtlBuffer &buf )
{
if ( !CDmAttributeAccessor::MarkDirty( pAttribute ) )
return false;
CDmrArray<T> array( pAttribute );
if ( array.Count() <= nElement )
return false;
MEM_ALLOC_CREDIT_CLASS();
pAttribute->PreChanged();
bool bReadElement = ::Unserialize( buf, *const_cast<T*>( &array[nElement] ) );
if ( bReadElement )
{
pAttribute->OnChanged();
}
return bReadElement;
}
template< class T >
void CDmArrayAttributeOp<T>::OnUnserializationFinished( CDmAttribute *pAttribute )
{
CDmArrayAttributeOp<T> ref( pAttribute );
int nCount = ref.Count();
if ( nCount > 0 )
{
ref.OnAttributeArrayElementAdded( 0, nCount - 1, false );
}
CDmAttributeAccessor::OnChanged( pAttribute, true, true );
}
//-----------------------------------------------------------------------------
//
// CDmAttribute begins here
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Memory pool used for CDmAttribute
//-----------------------------------------------------------------------------
CUtlMemoryPool g_AttrAlloc( sizeof( CDmAttribute ), 32, CUtlMemoryPool::GROW_SLOW, "CDmAttribute pool" );
//-----------------------------------------------------------------------------
// Class factory
//-----------------------------------------------------------------------------
// turn memdbg off temporarily so we can get at placement new
#include "tier0/memdbgoff.h"
CDmAttribute *CDmAttribute::CreateAttribute( CDmElement *pOwner, DmAttributeType_t type, const char *pAttributeName )
{
switch( type )
{
case AT_UNKNOWN:
Assert( 0 );
return NULL;
default:
{
void *pMem = g_AttrAlloc.Alloc( sizeof( CDmAttribute ) );
return ::new( pMem ) CDmAttribute( pOwner, type, pAttributeName );
}
}
}
CDmAttribute *CDmAttribute::CreateExternalAttribute( CDmElement *pOwner, DmAttributeType_t type, const char *pAttributeName, void *pExternalMemory )
{
switch( type )
{
case AT_UNKNOWN:
Assert( 0 );
return NULL;
default:
{
void *pMem = g_AttrAlloc.Alloc( sizeof( CDmAttribute ) );
return ::new( pMem ) CDmAttribute( pOwner, type, pAttributeName, pExternalMemory );
}
}
}
void CDmAttribute::DestroyAttribute( CDmAttribute *pAttribute )
{
if ( !pAttribute )
return;
switch( pAttribute->GetType() )
{
case AT_UNKNOWN:
break;
default:
pAttribute->~CDmAttribute();
#ifdef _DEBUG
memset( pAttribute, 0xDD, sizeof(CDmAttribute) );
#endif
g_AttrAlloc.Free( pAttribute );
break;
}
}
// turn memdbg back on after using placement new
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Constructor, destructor
//-----------------------------------------------------------------------------
CDmAttribute::CDmAttribute( CDmElement *pOwner, DmAttributeType_t type, const char *pAttributeName ) :
m_pData( NULL )
{
Init( pOwner, type, pAttributeName );
CreateAttributeData();
}
CDmAttribute::CDmAttribute( CDmElement *pOwner, DmAttributeType_t type, const char *pAttributeName, void *pMemory ) :
m_pData( pMemory )
{
Init( pOwner, type, pAttributeName );
s_pAttrInfo[ GetType() ]->SetDefaultValue( m_pData );
AddFlag( FATTRIB_EXTERNAL );
}
void CDmAttribute::Init( CDmElement *pOwner, DmAttributeType_t type, const char *pAttributeName )
{
// FIXME - this is just here temporarily to catch old code trying to create type and id attributes
// this shouldn't actually be illegal, since users should be able to create attributes of whatever name they want
Assert( V_strcmp( pAttributeName, "type" ) && V_strcmp( pAttributeName, "id" ) );
m_pOwner = pOwner;
m_Name = g_pDataModel->GetSymbol( pAttributeName );
m_nFlags = type;
m_Handle = DMATTRIBUTE_HANDLE_INVALID;
m_pNext = NULL;
m_hMailingList = DMMAILINGLIST_INVALID;
switch ( type )
{
case AT_ELEMENT:
case AT_ELEMENT_ARRAY:
case AT_OBJECTID:
case AT_OBJECTID_ARRAY:
m_nFlags |= FATTRIB_TOPOLOGICAL;
break;
}
}
CDmAttribute::~CDmAttribute()
{
switch( GetType() )
{
case AT_ELEMENT:
g_pDataModelImp->OnElementReferenceRemoved( GetValue<DmElementHandle_t>(), this );
break;
case AT_ELEMENT_ARRAY:
{
CDmrElementArray<> array( this );
int nElements = array.Count();
for ( int i = 0; i < nElements; ++i )
{
g_pDataModelImp->OnElementReferenceRemoved( array.GetHandle( i ), this );
}
}
break;
}
CleanupMailingList();
InvalidateHandle();
DeleteAttributeData();
}
//-----------------------------------------------------------------------------
// Creates the attribute data
//-----------------------------------------------------------------------------
void CDmAttribute::CreateAttributeData()
{
// Free the attribute memory
if ( !IsFlagSet( FATTRIB_EXTERNAL ) )
{
Assert( !m_pData );
m_pData = s_pAttrInfo[ GetType() ]->CreateAttributeData( );
}
}
//-----------------------------------------------------------------------------
// Deletes the attribute data
//-----------------------------------------------------------------------------
void CDmAttribute::DeleteAttributeData()
{
// Free the attribute memory
if ( m_pData && !IsFlagSet( FATTRIB_EXTERNAL ) )
{
s_pAttrInfo[ GetType() ]->DestroyAttributeData( m_pData );
m_pData = NULL;
}
}
//-----------------------------------------------------------------------------
// Used only in attribute element arrays
//-----------------------------------------------------------------------------
void CDmAttribute::SetElementTypeSymbol( UtlSymId_t typeSymbol )
{
switch ( GetType() )
{
case AT_ELEMENT:
{
DmElementAttribute_t *pData = GetData< DmElementHandle_t >();
Assert( pData->m_Handle == DMELEMENT_HANDLE_INVALID || ::IsA( pData->m_Handle, typeSymbol ) );
pData->m_ElementType = typeSymbol;
}
break;
case AT_ELEMENT_ARRAY:
{
#ifdef _DEBUG
CDmrElementArray<> array( this );
if ( array.GetElementType() != UTL_INVAL_SYMBOL )
{
int i;
int c = array.Count();
for ( i = 0; i < c; ++i )
{
Assert( array.GetHandle( i ) == DMELEMENT_HANDLE_INVALID || ::IsA( array.GetHandle( i ), typeSymbol ) );
}
}
#endif
DmElementArray_t *pData = GetArrayData< DmElementHandle_t >();
pData->m_ElementType = typeSymbol;
}
break;
default:
Assert(0);
break;
}
}
UtlSymId_t CDmAttribute::GetElementTypeSymbol() const
{
switch ( GetType() )
{
case AT_ELEMENT:
return GetData< DmElementHandle_t >()->m_ElementType;
case AT_ELEMENT_ARRAY:
return GetArrayData< DmElementHandle_t >()->m_ElementType;
default:
Assert(0);
break;
}
return UTL_INVAL_SYMBOL;
}
//-----------------------------------------------------------------------------
// Is modification allowed in this phase?
//-----------------------------------------------------------------------------
bool CDmAttribute::ModificationAllowed() const
{
if ( IsFlagSet( FATTRIB_READONLY ) )
return false;
DmPhase_t phase = g_pDmElementFramework->GetPhase();
if ( phase == PH_EDIT )
return true;
if ( ( phase == PH_OPERATE ) && !IsFlagSet( FATTRIB_TOPOLOGICAL ) )
return true;
return false;
}
bool CDmAttribute::MarkDirty()
{
if ( !ModificationAllowed() )
{
Assert( 0 );
return false;
}
AddFlag( FATTRIB_DIRTY | FATTRIB_OPERATOR_DIRTY );
CDmeElementAccessor::MarkDirty( m_pOwner );
return true;
}
//-----------------------------------------------------------------------------
// Called before and after the attribute has changed
//-----------------------------------------------------------------------------
void CDmAttribute::PreChanged()
{
if ( IsFlagSet( FATTRIB_HAS_PRE_CALLBACK ) && !CDmeElementAccessor::IsBeingUnserialized( m_pOwner ) )
{
m_pOwner->PreAttributeChanged( this );
}
// FIXME: What about mailing lists?
}
void CDmAttribute::OnChanged( bool bArrayCountChanged, bool bIsTopological )
{
if ( IsFlagSet( FATTRIB_HAS_CALLBACK ) && !CDmeElementAccessor::IsBeingUnserialized( m_pOwner ) )
{
m_pOwner->OnAttributeChanged( this );
}
if ( ( m_hMailingList != DMMAILINGLIST_INVALID ) && !CDmeElementAccessor::IsBeingUnserialized( m_pOwner ) )
{
if ( !g_pDataModelImp->PostAttributeChanged( m_hMailingList, this ) )
{
CleanupMailingList();
}
}
if ( bIsTopological || IsTopological( GetType() ) )
{
g_pDataModelImp->NotifyState( NOTIFY_CHANGE_TOPOLOGICAL );
}
else
{
g_pDataModelImp->NotifyState( bArrayCountChanged ? NOTIFY_CHANGE_ATTRIBUTE_ARRAY_SIZE : NOTIFY_CHANGE_ATTRIBUTE_VALUE );
}
}
//-----------------------------------------------------------------------------
// Type conversion related methods
//-----------------------------------------------------------------------------
template< class T > bool CDmAttribute::IsTypeConvertable() const
{
return ( CDmAttributeInfo< T >::ATTRIBUTE_TYPE == GetType() );
}
template<> bool CDmAttribute::IsTypeConvertable<bool>() const
{
DmAttributeType_t type = GetType();
return ( type == AT_BOOL || type == AT_INT || type == AT_FLOAT );
}
template<> bool CDmAttribute::IsTypeConvertable<int>() const
{
DmAttributeType_t type = GetType();
return ( type == AT_INT || type == AT_BOOL || type == AT_FLOAT );
}
template<> bool CDmAttribute::IsTypeConvertable<float>() const
{
DmAttributeType_t type = GetType();
return ( type == AT_FLOAT || type == AT_INT || type == AT_BOOL );
}
template<> bool CDmAttribute::IsTypeConvertable<QAngle>() const
{
DmAttributeType_t type = GetType();
return ( type == AT_QANGLE || type == AT_QUATERNION );
}
template<> bool CDmAttribute::IsTypeConvertable<Quaternion>() const
{
DmAttributeType_t type = GetType();
return ( type == AT_QUATERNION || type == AT_QANGLE);
}
template< class T > void CDmAttribute::CopyData( const T& value )
{
*reinterpret_cast< T* >( m_pData ) = value;
}
template< class T > void CDmAttribute::CopyDataOut( T& value ) const
{
value = *reinterpret_cast< const T* >( m_pData );
}
template<> void CDmAttribute::CopyData( const bool& value )
{
switch( GetType() )
{
case AT_BOOL:
*reinterpret_cast< bool* >( m_pData ) = value;
break;
case AT_INT:
*reinterpret_cast< int* >( m_pData ) = value ? 1 : 0;
break;
case AT_FLOAT:
*reinterpret_cast< float* >( m_pData ) = value ? 1.0f : 0.0f;
break;
}
}
template<> void CDmAttribute::CopyDataOut( bool& value ) const
{
switch( GetType() )
{
case AT_BOOL:
value = *reinterpret_cast< bool* >( m_pData );
break;
case AT_INT:
value = *reinterpret_cast< int* >( m_pData ) != 0;
break;
case AT_FLOAT:
value = *reinterpret_cast< float* >( m_pData ) != 0.0f;
break;
}
}
template<> void CDmAttribute::CopyData( const int& value )
{
switch( GetType() )
{
case AT_BOOL:
*reinterpret_cast< bool* >( m_pData ) = value != 0;
break;
case AT_INT:
*reinterpret_cast< int* >( m_pData ) = value;
break;
case AT_FLOAT:
*reinterpret_cast< float* >( m_pData ) = value;
break;
}
}
template<> void CDmAttribute::CopyDataOut( int& value ) const
{
switch( GetType() )
{
case AT_BOOL:
value = *reinterpret_cast< bool* >( m_pData ) ? 1 : 0;
break;
case AT_INT:
value = *reinterpret_cast< int* >( m_pData );
break;
case AT_FLOAT:
value = *reinterpret_cast< float* >( m_pData );
break;
}
}
template<> void CDmAttribute::CopyData( const float& value )
{
switch( GetType() )
{
case AT_BOOL:
*reinterpret_cast< bool* >( m_pData ) = value != 0.0f;
break;
case AT_INT:
*reinterpret_cast< int* >( m_pData ) = value;
break;
case AT_FLOAT:
*reinterpret_cast< float* >( m_pData ) = value;
break;
}
}
template<> void CDmAttribute::CopyDataOut( float& value ) const
{
switch( GetType() )
{
case AT_BOOL:
value = *reinterpret_cast< bool* >( m_pData ) ? 1.0f : 0.0f;
break;
case AT_INT:
value = *reinterpret_cast< int* >( m_pData );
break;
case AT_FLOAT:
value = *reinterpret_cast< float* >( m_pData );
break;
}
}
template<> void CDmAttribute::CopyData( const QAngle& value )
{
switch( GetType() )
{
case AT_QANGLE:
*reinterpret_cast< QAngle* >( m_pData ) = value;
break;
case AT_QUATERNION:
{
Quaternion qValue;
AngleQuaternion( value, qValue );
*reinterpret_cast< Quaternion* >( m_pData ) = qValue;
}
break;
}
}
template<> void CDmAttribute::CopyDataOut( QAngle& value ) const
{
switch( GetType() )
{
case AT_QANGLE:
value = *reinterpret_cast< QAngle* >( m_pData );
break;
case AT_QUATERNION:
QuaternionAngles( *reinterpret_cast< Quaternion* >( m_pData ), value );
break;
}
}
template<> void CDmAttribute::CopyData( const Quaternion& value )
{
switch( GetType() )
{
case AT_QANGLE:
{
QAngle aValue;
QuaternionAngles( value, aValue );
*reinterpret_cast< QAngle* >( m_pData ) = aValue;
}
break;
case AT_QUATERNION:
*reinterpret_cast< Quaternion* >( m_pData ) = value;
break;
}
}
template<> void CDmAttribute::CopyDataOut( Quaternion& value ) const
{
switch( GetType() )
{
case AT_QANGLE:
AngleQuaternion( *reinterpret_cast< QAngle* >( m_pData ), value );
break;
case AT_QUATERNION:
value = *reinterpret_cast< Quaternion* >( m_pData );
break;
}
}
template<> void CDmAttribute::CopyData( const DmElementHandle_t& value )
{
g_pDataModelImp->OnElementReferenceRemoved( GetValue<DmElementHandle_t>(), this );
*reinterpret_cast< DmElementHandle_t* >( m_pData ) = value;
g_pDataModelImp->OnElementReferenceAdded( value, this );
}
//-----------------------------------------------------------------------------
// Should we be allowed to modify the attribute data?
//-----------------------------------------------------------------------------
template< class T >
bool CDmAttribute::ShouldModify( const T& value )
{
if ( !IsTypeConvertable<T>() )
return false;
if ( ( GetType() == CDmAttributeInfo<T>::ATTRIBUTE_TYPE ) && IsAttributeEqual( GetValue<T>(), value ) )
return false;
return MarkDirty();
}
template<> bool CDmAttribute::ShouldModify( const DmElementHandle_t& value )
{
if ( !IsTypeConvertable<DmElementHandle_t>() )
return false;
if ( IsAttributeEqual( GetValue<DmElementHandle_t>(), value ) )
return false;
DmElementAttribute_t *pData = GetData<DmElementHandle_t>();
if ( pData->m_ElementType != UTL_INVAL_SYMBOL && !::IsA( value, pData->m_ElementType ) )
return false;
return MarkDirty();
}
//-----------------------------------------------------------------------------
// Main entry point for single-valued SetValue
//-----------------------------------------------------------------------------
template< class T >
void CDmAttribute::SetValue( const T &value )
{
if ( !ShouldModify( value ) )
return;
// UNDO Hook
if ( g_pDataModel->UndoEnabledForElement( m_pOwner ) )
{
CUndoAttributeSetValueElement<T> *pUndo = new CUndoAttributeSetValueElement<T>( this, value );
g_pDataModel->AddUndoElement( pUndo );
}
bool bIsBeingUnserialized = CDmeElementAccessor::IsBeingUnserialized( m_pOwner );
if ( IsFlagSet( FATTRIB_HAS_PRE_CALLBACK ) && !bIsBeingUnserialized )
{
m_pOwner->PreAttributeChanged( this );
}
CopyData< T >( value );
if ( !bIsBeingUnserialized )
{
if ( IsFlagSet( FATTRIB_HAS_CALLBACK ) )
{
m_pOwner->OnAttributeChanged( this );
}
if ( m_hMailingList != DMMAILINGLIST_INVALID )
{
if ( !g_pDataModelImp->PostAttributeChanged( m_hMailingList, this ) )
{
CleanupMailingList();
}
}
}
g_pDataModelImp->NotifyState( IsTopological( GetType() ) ? NOTIFY_CHANGE_TOPOLOGICAL : NOTIFY_CHANGE_ATTRIBUTE_VALUE );
}
//-----------------------------------------------------------------------------
// Versions that work on arrays
//-----------------------------------------------------------------------------
#define ATTRIBUTE_SET_VALUE_ARRAY( _type ) \
template<> void CDmAttribute::SetValue( const CUtlVector< _type >& value ) \
{ \
CDmArrayAttributeOp< _type > accessor( this ); \
accessor.CopyArray( value.Base(), value.Count() ); \
}
void CDmAttribute::SetValue( const CDmAttribute *pAttribute )
{
s_pAttrInfo[ GetType() ]->SetValue( this, pAttribute->GetType(), pAttribute->GetAttributeData() );
}
void CDmAttribute::SetValue( CDmAttribute *pAttribute )
{
s_pAttrInfo[ GetType() ]->SetValue( this, pAttribute->GetType(), pAttribute->GetAttributeData() );
}
void CDmAttribute::SetValue( DmAttributeType_t valueType, const void *pValue )
{
s_pAttrInfo[ GetType() ]->SetValue( this, valueType, pValue );
}
//-----------------------------------------------------------------------------
// Sets the attribute to its default value based on its type
//-----------------------------------------------------------------------------
void CDmAttribute::SetToDefaultValue()
{
s_pAttrInfo[ GetType() ]->SetToDefaultValue( this );
}
//-----------------------------------------------------------------------------
// Convert to and from string
//-----------------------------------------------------------------------------
void CDmAttribute::SetValueFromString( const char *pValue )
{
switch ( GetType() )
{
case AT_STRING:
SetValue( pValue );
break;
default:
{
int nLen = pValue ? Q_strlen( pValue ) : 0;
if ( nLen == 0 )
{
SetToDefaultValue();
break;
}
CUtlBuffer buf( pValue, nLen, CUtlBuffer::TEXT_BUFFER | CUtlBuffer::READ_ONLY );
if ( !Unserialize( buf ) )
{
SetToDefaultValue();
}
}
break;
}
}
const char *CDmAttribute::GetValueAsString( char *pBuffer, size_t nBufLen ) const
{
Assert( pBuffer );
CUtlBuffer buf( pBuffer, nBufLen, CUtlBuffer::TEXT_BUFFER );
Serialize( buf );
return pBuffer;
}
//-----------------------------------------------------------------------------
// Name, type
//-----------------------------------------------------------------------------
const char* CDmAttribute::GetTypeString() const
{
return ::GetTypeString( GetType() );
}
const char *GetTypeString( DmAttributeType_t type )
{
if ( ( type >= 0 ) && ( type < AT_TYPE_COUNT ) )
return s_pAttrInfo[ type ]->AttributeTypeName();
return "unknown";
}
void CDmAttribute::SetName( const char *pNewName )
{
if ( m_pOwner->HasAttribute( pNewName ) && Q_stricmp( GetName(), pNewName ) )
{
Warning( "Tried to rename from '%s' to '%s', but '%s' already exists\n",
GetName(), pNewName, pNewName );
return;
}
if ( !MarkDirty() )
return;
// UNDO Hook
if ( g_pDataModel->UndoEnabledForElement( m_pOwner ) )
{
CUndoAttributeRenameElement *pUndo = new CUndoAttributeRenameElement( this, pNewName );
g_pDataModel->AddUndoElement( pUndo );
}
m_Name = g_pDataModel->GetSymbol( pNewName );
g_pDataModelImp->NotifyState( NOTIFY_CHANGE_TOPOLOGICAL );
}
//-----------------------------------------------------------------------------
// Serialization
//-----------------------------------------------------------------------------
bool CDmAttribute::SerializesOnMultipleLines() const
{
return s_pAttrInfo[ GetType() ]->SerializesOnMultipleLines();
}
bool CDmAttribute::Serialize( CUtlBuffer &buf ) const
{
return s_pAttrInfo[ GetType() ]->Serialize( this, buf );
}
bool CDmAttribute::Unserialize( CUtlBuffer &buf )
{
return s_pAttrInfo[ GetType() ]->Unserialize( this, buf );
}
bool CDmAttribute::SerializeElement( int nElement, CUtlBuffer &buf ) const
{
return s_pAttrInfo[ GetType() ]->SerializeElement( this, nElement, buf );
}
bool CDmAttribute::UnserializeElement( CUtlBuffer &buf )
{
return s_pAttrInfo[ GetType() ]->UnserializeElement( this, buf );
}
bool CDmAttribute::UnserializeElement( int nElement, CUtlBuffer &buf )
{
return s_pAttrInfo[ GetType() ]->UnserializeElement( this, nElement, buf );
}
// Called by elements after unserialization of their attributes is complete
void CDmAttribute::OnUnserializationFinished()
{
return s_pAttrInfo[ GetType() ]->OnUnserializationFinished( this );
}
//-----------------------------------------------------------------------------
// Methods related to attribute change notification
//-----------------------------------------------------------------------------
void CDmAttribute::CleanupMailingList()
{
if ( m_hMailingList != DMMAILINGLIST_INVALID )
{
g_pDataModelImp->DestroyMailingList( m_hMailingList );
m_hMailingList = DMMAILINGLIST_INVALID;
}
}
void CDmAttribute::NotifyWhenChanged( DmElementHandle_t h, bool bNotify )
{
if ( bNotify )
{
if ( m_hMailingList == DMMAILINGLIST_INVALID )
{
m_hMailingList = g_pDataModelImp->CreateMailingList();
}
g_pDataModelImp->AddElementToMailingList( m_hMailingList, h );
return;
}
if ( m_hMailingList != DMMAILINGLIST_INVALID )
{
if ( !g_pDataModelImp->RemoveElementFromMailingList( m_hMailingList, h ) )
{
CleanupMailingList();
}
}
}
//-----------------------------------------------------------------------------
// Get the attribute/create an attribute handle
//-----------------------------------------------------------------------------
DmAttributeHandle_t CDmAttribute::GetHandle( bool bCreate )
{
if ( (m_Handle == DMATTRIBUTE_HANDLE_INVALID) && bCreate )
{
m_Handle = g_pDataModelImp->AcquireAttributeHandle( this );
}
Assert( (m_Handle == DMATTRIBUTE_HANDLE_INVALID) || g_pDataModel->IsAttributeHandleValid( m_Handle ) );
return m_Handle;
}
void CDmAttribute::InvalidateHandle()
{
g_pDataModelImp->ReleaseAttributeHandle( m_Handle );
m_Handle = DMATTRIBUTE_HANDLE_INVALID;
}
//-----------------------------------------------------------------------------
// Memory usage estimations
//-----------------------------------------------------------------------------
bool HandleCompare( const DmElementHandle_t &a, const DmElementHandle_t &b )
{
return a == b;
}
unsigned int HandleHash( const DmElementHandle_t &h )
{
return (unsigned int)h;
}
int CDmAttribute::EstimateMemoryUsage( TraversalDepth_t depth ) const
{
CUtlHash< DmElementHandle_t > visited( 1024, 0, 0, HandleCompare, HandleHash );
return EstimateMemoryUsageInternal( visited, depth, 0 ) ;
}
int CDmAttribute::EstimateMemoryUsageInternal( CUtlHash< DmElementHandle_t > &visited, TraversalDepth_t depth, int *pCategories ) const
{
int nOverhead = sizeof( *this );
int nAttributeDataSize = s_pAttrInfo[ GetType() ]->DataSize();
int nTotalMemory = nOverhead + nAttributeDataSize;
int nAttributeExtraDataSize = 0;
if ( IsArrayType( GetType() ) )
{
CDmrGenericArrayConst array( this );
int nCount = array.Count();
nAttributeExtraDataSize = nCount * s_pAttrInfo[ GetType() ]->ValueSize(); // Data in the UtlVector
int nMallocOverhead = ( array.Count() == 0 ) ? 0 : 8; // malloc overhead inside the vector
nOverhead += nMallocOverhead;
nTotalMemory += nAttributeExtraDataSize + nMallocOverhead;
}
if ( pCategories )
{
++pCategories[MEMORY_CATEGORY_ATTRIBUTE_COUNT];
pCategories[MEMORY_CATEGORY_ATTRIBUTE_DATA] += nAttributeDataSize + nAttributeExtraDataSize;
pCategories[MEMORY_CATEGORY_ATTRIBUTE_OVERHEAD] += nOverhead;
if ( !IsDataInline() )
{
pCategories[MEMORY_CATEGORY_OUTER] -= nAttributeDataSize;
Assert( pCategories[MEMORY_CATEGORY_OUTER] >= 0 );
nTotalMemory -= nAttributeDataSize;
}
}
switch ( GetType() )
{
case AT_STRING:
{
const CUtlString &value = GetValue<CUtlString>();
if ( pCategories )
{
pCategories[MEMORY_CATEGORY_ATTRIBUTE_DATA] += value.Length() + 1;
pCategories[MEMORY_CATEGORY_ATTRIBUTE_OVERHEAD] += 8;
}
return nTotalMemory + value.Length() + 1 + 8; // string's length skips trailing null
}
case AT_STRING_ARRAY:
{
const CUtlVector< CUtlString > &array = GetValue< CUtlVector< CUtlString > >( );
for ( int i = 0; i < array.Count(); ++i )
{
int nStrLen = array[ i ].Length() + 1;
if ( pCategories )
{
pCategories[MEMORY_CATEGORY_ATTRIBUTE_DATA] += nStrLen;
pCategories[MEMORY_CATEGORY_ATTRIBUTE_OVERHEAD] += 8;
}
nTotalMemory += nStrLen + 8; // string's length skips trailing null
}
return nTotalMemory;
}
case AT_VOID:
{
const CUtlBinaryBlock &value = GetValue< CUtlBinaryBlock >();
if ( pCategories )
{
pCategories[MEMORY_CATEGORY_ATTRIBUTE_DATA] += value.Length();
pCategories[MEMORY_CATEGORY_ATTRIBUTE_OVERHEAD] += 8;
}
return nTotalMemory + value.Length() + 8;
}
case AT_VOID_ARRAY:
{
const CUtlVector< CUtlBinaryBlock > &array = GetValue< CUtlVector< CUtlBinaryBlock > >();
for ( int i = 0; i < array.Count(); ++i )
{
if ( pCategories )
{
pCategories[MEMORY_CATEGORY_ATTRIBUTE_DATA] += array[ i ].Length();
pCategories[MEMORY_CATEGORY_ATTRIBUTE_OVERHEAD] += 8;
}
nTotalMemory += array[ i ].Length() + 8;
}
return nTotalMemory;
}
case AT_ELEMENT:
if ( ShouldTraverse( this, depth ) )
{
CDmElement *pElement = GetValueElement<CDmElement>();
if ( pElement )
{
nTotalMemory += CDmeElementAccessor::EstimateMemoryUsage( pElement, visited, depth, pCategories );
}
}
return nTotalMemory;
case AT_ELEMENT_ARRAY:
if ( ShouldTraverse( this, depth ) )
{
CDmrElementArrayConst<> array( this );
for ( int i = 0; i < array.Count(); ++i )
{
CDmElement *pElement = array[ i ];
if ( pElement )
{
nTotalMemory += CDmeElementAccessor::EstimateMemoryUsage( pElement, visited, depth, pCategories );
}
}
}
return nTotalMemory;
}
return nTotalMemory;
}
//-----------------------------------------------------------------------------
//
// CDmaArrayBase starts here
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
template< class T, class B >
CDmaArrayConstBase<T,B>::CDmaArrayConstBase( )
{
m_pAttribute = NULL;
}
//-----------------------------------------------------------------------------
// Search
//-----------------------------------------------------------------------------
template< class T, class B >
int CDmaArrayConstBase<T,B>::Find( const T &value ) const
{
return Value().Find( value );
}
//-----------------------------------------------------------------------------
// Insertion
//-----------------------------------------------------------------------------
template< class T, class B >
int CDmaArrayBase<T,B>::AddToTail()
{
T defaultVal;
CDmAttributeInfo<T>::SetDefaultValue( defaultVal );
CDmArrayAttributeOp<T> accessor( this->m_pAttribute );
return accessor.InsertBefore( Value().Count(), defaultVal );
}
template< class T, class B >
int CDmaArrayBase<T,B>::InsertBefore( int elem )
{
T defaultVal;
CDmAttributeInfo<T>::SetDefaultValue( defaultVal );
CDmArrayAttributeOp<T> accessor( this->m_pAttribute );
return accessor.InsertBefore( elem, defaultVal );
}
template< class T, class B >
int CDmaArrayBase<T,B>::AddToTail( const T& src )
{
CDmArrayAttributeOp<T> accessor( this->m_pAttribute );
return accessor.InsertBefore( Value().Count(), src );
}
template< class T, class B >
int CDmaArrayBase<T,B>::InsertBefore( int elem, const T& src )
{
CDmArrayAttributeOp<T> accessor( this->m_pAttribute );
return accessor.InsertBefore( elem, src );
}
template< class T, class B >
int CDmaArrayBase<T,B>::AddMultipleToTail( int num )
{
CDmArrayAttributeOp<T> accessor( this->m_pAttribute );
return accessor.InsertMultipleBefore( Value().Count(), num );
}
template< class T, class B >
int CDmaArrayBase<T,B>::InsertMultipleBefore( int elem, int num )
{
CDmArrayAttributeOp<T> accessor( this->m_pAttribute );
return accessor.InsertMultipleBefore( elem, num );
}
template< class T, class B >
void CDmaArrayBase<T,B>::EnsureCount( int num )
{
int nCurrentCount = Value().Count();
if ( nCurrentCount < num )
{
AddMultipleToTail( num - nCurrentCount );
}
}
//-----------------------------------------------------------------------------
// Element modification
//-----------------------------------------------------------------------------
template< class T, class B >
void CDmaArrayBase<T,B>::Set( int i, const T& value )
{
CDmArrayAttributeOp<T> accessor( this->m_pAttribute );
return accessor.Set( i, value );
}
template< class T, class B >
void CDmaArrayBase<T,B>::SetMultiple( int i, int nCount, const T* pValue )
{
CDmArrayAttributeOp<T> accessor( this->m_pAttribute );
accessor.SetMultiple( i, nCount, pValue );
}
template< class T, class B >
void CDmaArrayBase<T,B>::Swap( int i, int j )
{
CDmArrayAttributeOp<T> accessor( this->m_pAttribute );
accessor.Swap( i, j );
}
template< class T, class B >
void CDmaArrayBase<T,B>::SwapArray( CUtlVector< T > &array )
{
CDmArrayAttributeOp<T> accessor( this->m_pAttribute );
accessor.SwapArray( array );
}
//-----------------------------------------------------------------------------
// Copy
//-----------------------------------------------------------------------------
template< class T, class B >
void CDmaArrayBase<T,B>::CopyArray( const T *pArray, int nCount )
{
CDmArrayAttributeOp<T> accessor( this->m_pAttribute );
accessor.CopyArray( pArray, nCount );
}
//-----------------------------------------------------------------------------
// Removal
//-----------------------------------------------------------------------------
template< class T, class B >
void CDmaArrayBase<T,B>::FastRemove( int elem )
{
CDmArrayAttributeOp<T> accessor( this->m_pAttribute );
accessor.FastRemove( elem );
}
template< class T, class B >
void CDmaArrayBase<T,B>::Remove( int elem )
{
CDmArrayAttributeOp<T> accessor( this->m_pAttribute );
accessor.Remove( elem );
}
template< class T, class B >
void CDmaArrayBase<T,B>::RemoveAll()
{
CDmArrayAttributeOp<T> accessor( this->m_pAttribute );
accessor.RemoveAll();
}
template< class T, class B >
void CDmaArrayBase<T,B>::RemoveMultiple( int elem, int num )
{
CDmArrayAttributeOp<T> accessor( this->m_pAttribute );
accessor.RemoveMultiple( elem, num );
}
//-----------------------------------------------------------------------------
// Memory management
//-----------------------------------------------------------------------------
template< class T, class B >
void CDmaArrayBase<T,B>::EnsureCapacity( int num )
{
Value().EnsureCapacity( num );
}
template< class T, class B >
void CDmaArrayBase<T,B>::Purge()
{
CDmArrayAttributeOp<T> accessor( this->m_pAttribute );
accessor.Purge();
}
//-----------------------------------------------------------------------------
// Attribute initialization
//-----------------------------------------------------------------------------
template< class T, class B >
void CDmaDecorator<T,B>::Init( CDmElement *pOwner, const char *pAttributeName, int nFlags = 0 )
{
Assert( pOwner );
this->m_pAttribute = pOwner->AddExternalAttribute( pAttributeName, CDmAttributeInfo<CUtlVector<T> >::AttributeType(), &Value() );
Assert( m_pAttribute );
if ( nFlags )
{
this->m_pAttribute->AddFlag( nFlags );
}
}
//-----------------------------------------------------------------------------
// Attribute attribute reference
//-----------------------------------------------------------------------------
template< class T, class BaseClass >
void CDmrDecoratorConst<T,BaseClass>::Init( const CDmAttribute* pAttribute )
{
if ( pAttribute && pAttribute->GetType() == CDmAttributeInfo< CUtlVector< T > >::AttributeType() )
{
this->m_pAttribute = const_cast<CDmAttribute*>( pAttribute );
Attach( this->m_pAttribute->GetAttributeData() );
}
else
{
this->m_pAttribute = NULL;
Attach( NULL );
}
}
template< class T, class BaseClass >
void CDmrDecoratorConst<T,BaseClass>::Init( const CDmElement *pElement, const char *pAttributeName )
{
const CDmAttribute *pAttribute = NULL;
if ( pElement && pAttributeName && pAttributeName[0] )
{
pAttribute = pElement->GetAttribute( pAttributeName );
}
Init( pAttribute );
}
template< class T, class BaseClass >
bool CDmrDecoratorConst<T,BaseClass>::IsValid() const
{
return this->m_pAttribute != NULL;
}
template< class T, class BaseClass >
void CDmrDecorator<T,BaseClass>::Init( CDmAttribute* pAttribute )
{
if ( pAttribute && pAttribute->GetType() == CDmAttributeInfo< CUtlVector< T > >::AttributeType() )
{
this->m_pAttribute = pAttribute;
Attach( this->m_pAttribute->GetAttributeData() );
}
else
{
this->m_pAttribute = NULL;
Attach( NULL );
}
}
template< class T, class BaseClass >
void CDmrDecorator<T,BaseClass>::Init( CDmElement *pElement, const char *pAttributeName, bool bAddAttribute )
{
CDmAttribute *pAttribute = NULL;
if ( pElement && pAttributeName && pAttributeName[0] )
{
if ( bAddAttribute )
{
pAttribute = pElement->AddAttribute( pAttributeName, CDmAttributeInfo< CUtlVector< T > >::AttributeType() );
}
else
{
pAttribute = pElement->GetAttribute( pAttributeName );
}
}
Init( pAttribute );
}
template< class T, class BaseClass >
bool CDmrDecorator<T,BaseClass>::IsValid() const
{
return this->m_pAttribute != NULL;
}
//-----------------------------------------------------------------------------
//
// Generic array access
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Helper macros to make switch statements based on type
//-----------------------------------------------------------------------------
#define ARRAY_METHOD_VOID( _type, _func ) \
case CDmAttributeInfo< CUtlVector< _type > >::ATTRIBUTE_TYPE: \
{ \
CDmrArray< _type > &array = *reinterpret_cast< CDmrArray< _type > * >( &arrayShared ); \
array.Init( m_pAttribute ); \
array._func; \
} \
break;
#define APPLY_ARRAY_METHOD_VOID( _func ) \
CDmrArray<int> arrayShared; \
switch( m_pAttribute->GetType() ) \
{ \
ARRAY_METHOD_VOID( bool, _func ) \
ARRAY_METHOD_VOID( int, _func ) \
ARRAY_METHOD_VOID( float, _func ) \
ARRAY_METHOD_VOID( Color, _func ) \
ARRAY_METHOD_VOID( Vector2D, _func ) \
ARRAY_METHOD_VOID( Vector, _func ) \
ARRAY_METHOD_VOID( Vector4D, _func ) \
ARRAY_METHOD_VOID( QAngle, _func ) \
ARRAY_METHOD_VOID( Quaternion, _func ) \
ARRAY_METHOD_VOID( VMatrix, _func ) \
ARRAY_METHOD_VOID( CUtlString, _func ) \
ARRAY_METHOD_VOID( CUtlBinaryBlock, _func ) \
ARRAY_METHOD_VOID( DmObjectId_t, _func ) \
ARRAY_METHOD_VOID( DmElementHandle_t, _func ) \
default: \
break; \
}
#define ARRAY_METHOD_RET( _type, _func ) \
case CDmAttributeInfo< CUtlVector< _type > >::ATTRIBUTE_TYPE: \
{ \
CDmrArray< _type > &array = *reinterpret_cast< CDmrArray< _type > * >( &arrayShared ); \
array.Init( m_pAttribute ); \
return array._func; \
}
#define APPLY_ARRAY_METHOD_RET( _func ) \
CDmrArray<int> arrayShared; \
switch( m_pAttribute->GetType() ) \
{ \
ARRAY_METHOD_RET( bool, _func ); \
ARRAY_METHOD_RET( int, _func ); \
ARRAY_METHOD_RET( float, _func ); \
ARRAY_METHOD_RET( Color, _func ); \
ARRAY_METHOD_RET( Vector2D, _func ); \
ARRAY_METHOD_RET( Vector, _func ); \
ARRAY_METHOD_RET( Vector4D, _func ); \
ARRAY_METHOD_RET( QAngle, _func ); \
ARRAY_METHOD_RET( Quaternion, _func ); \
ARRAY_METHOD_RET( VMatrix, _func ); \
ARRAY_METHOD_RET( CUtlString, _func ); \
ARRAY_METHOD_RET( CUtlBinaryBlock, _func ); \
ARRAY_METHOD_RET( DmObjectId_t, _func ); \
ARRAY_METHOD_RET( DmElementHandle_t, _func ); \
default: \
break; \
}
CDmrGenericArrayConst::CDmrGenericArrayConst() : m_pAttribute( NULL )
{
}
CDmrGenericArrayConst::CDmrGenericArrayConst( const CDmAttribute* pAttribute )
{
Init( pAttribute );
}
CDmrGenericArrayConst::CDmrGenericArrayConst( const CDmElement *pElement, const char *pAttributeName )
{
Init( pElement, pAttributeName );
}
void CDmrGenericArrayConst::Init( const CDmAttribute *pAttribute )
{
if ( pAttribute && IsArrayType( pAttribute->GetType() ) )
{
m_pAttribute = const_cast<CDmAttribute*>( pAttribute );
}
else
{
m_pAttribute = NULL;
}
}
void CDmrGenericArrayConst::Init( const CDmElement *pElement, const char *pAttributeName )
{
const CDmAttribute *pAttribute = ( pElement && pAttributeName && pAttributeName[0] ) ? pElement->GetAttribute( pAttributeName ) : NULL;
Init( pAttribute );
}
int CDmrGenericArrayConst::Count() const
{
APPLY_ARRAY_METHOD_RET( Count() );
return 0;
}
const void* CDmrGenericArrayConst::GetUntyped( int i ) const
{
APPLY_ARRAY_METHOD_RET( GetUntyped( i ) );
return NULL;
}
const char* CDmrGenericArrayConst::GetAsString( int i, char *pBuffer, size_t nBufLen ) const
{
if ( ( Count() > i ) && ( i >= 0 ) )
{
CUtlBuffer buf( pBuffer, nBufLen, CUtlBuffer::TEXT_BUFFER );
m_pAttribute->SerializeElement( i, buf );
}
else
{
pBuffer[0] = 0;
}
return pBuffer;
}
CDmrGenericArray::CDmrGenericArray( CDmAttribute* pAttribute )
{
Init( pAttribute );
}
CDmrGenericArray::CDmrGenericArray( CDmElement *pElement, const char *pAttributeName )
{
Init( pElement, pAttributeName );
}
void CDmrGenericArray::EnsureCount( int num )
{
APPLY_ARRAY_METHOD_VOID( EnsureCount(num) );
}
int CDmrGenericArray::AddToTail()
{
APPLY_ARRAY_METHOD_RET( AddToTail() );
return -1;
}
void CDmrGenericArray::Remove( int elem )
{
APPLY_ARRAY_METHOD_VOID( Remove(elem) );
}
void CDmrGenericArray::RemoveAll()
{
APPLY_ARRAY_METHOD_VOID( RemoveAll() );
}
void CDmrGenericArray::SetMultiple( int i, int nCount, DmAttributeType_t valueType, const void *pValue )
{
s_pAttrInfo[ m_pAttribute->GetType() ]->SetMultiple( m_pAttribute, i, nCount, valueType, pValue );
}
void CDmrGenericArray::Set( int i, DmAttributeType_t valueType, const void *pValue )
{
s_pAttrInfo[ m_pAttribute->GetType() ]->Set( m_pAttribute, i, valueType, pValue );
}
void CDmrGenericArray::SetFromString( int i, const char *pValue )
{
if ( ( Count() > i ) && ( i >= 0 ) )
{
int nLen = pValue ? Q_strlen( pValue ) : 0;
CUtlBuffer buf( pValue, nLen, CUtlBuffer::TEXT_BUFFER | CUtlBuffer::READ_ONLY );
m_pAttribute->UnserializeElement( i, buf );
}
}
//-----------------------------------------------------------------------------
// Skip unserialization for an attribute type (unserialize into a dummy variable)
//-----------------------------------------------------------------------------
bool SkipUnserialize( CUtlBuffer &buf, DmAttributeType_t type )
{
if ( type == AT_UNKNOWN )
return false;
return s_pAttrInfo[ type ]->SkipUnserialize( buf );
}
//-----------------------------------------------------------------------------
// returns the number of attributes currently allocated
//-----------------------------------------------------------------------------
int GetAllocatedAttributeCount()
{
return g_AttrAlloc.Count();
}
//-----------------------------------------------------------------------------
// Attribute type->name and name->attribute type
//-----------------------------------------------------------------------------
const char *AttributeTypeName( DmAttributeType_t type )
{
if ( ( type >= 0 ) && ( type < AT_TYPE_COUNT ) )
return s_pAttrInfo[ type ]->AttributeTypeName();
return "unknown";
}
DmAttributeType_t AttributeType( const char *pName )
{
for ( int i = 0; i < AT_TYPE_COUNT; ++i )
{
if ( !Q_stricmp( s_pAttrInfo[ i ]->AttributeTypeName(), pName ) )
return (DmAttributeType_t)i;
}
return AT_UNKNOWN;
}
//-----------------------------------------------------------------------------
// Explicit template instantiation for the known attribute types
//-----------------------------------------------------------------------------
template <class T>
class CInstantiateOp
{
public:
CInstantiateOp()
{
s_pAttrInfo[ CDmAttributeInfo<T>::ATTRIBUTE_TYPE ] = new CDmAttributeOp< T >;
}
};
static CInstantiateOp<DmUnknownAttribute_t> __s_AttrDmUnknownAttribute_t;
#define INSTANTIATE_GENERIC_OPS( _className ) \
template< > class CInstantiateOp< CUtlVector< _className > > \
{ \
public: \
CInstantiateOp() \
{ \
s_pAttrInfo[ CDmAttributeInfo< CUtlVector< _className > >::ATTRIBUTE_TYPE ] = new CDmArrayAttributeOp< _className >; \
} \
}; \
static CInstantiateOp< _className > __s_Attr ## _className; \
static CInstantiateOp< CUtlVector< _className > > __s_AttrArray ## _className;
#define DEFINE_ATTRIBUTE_TYPE( _type ) \
INSTANTIATE_GENERIC_OPS( _type ) \
ATTRIBUTE_SET_VALUE_ARRAY( _type ) \
template void CDmAttribute::SetValue< _type >( const _type& value ); \
template class CDmArrayAttributeOp< _type >; \
template class CDmaArrayBase< _type, CDmaDataInternal< CUtlVector< _type > > >; \
template class CDmaArrayBase< _type, CDmaDataExternal< CUtlVector< _type > > >; \
template class CDmaArrayConstBase< _type, CDmaDataInternal< CUtlVector< _type > > >; \
template class CDmaArrayConstBase< _type, CDmaDataExternal< CUtlVector< _type > > >; \
template class CDmaDecorator< _type, CDmaArrayBase< _type, CDmaDataInternal< CUtlVector< _type > > > >; \
template class CDmrDecorator< _type, CDmaArrayBase< _type, CDmaDataExternal< CUtlVector< _type > > > >; \
template class CDmrDecoratorConst< _type, CDmaArrayConstBase< _type, CDmaDataExternal< CUtlVector< _type > > > >;
DEFINE_ATTRIBUTE_TYPE( int )
DEFINE_ATTRIBUTE_TYPE( float )
DEFINE_ATTRIBUTE_TYPE( bool )
DEFINE_ATTRIBUTE_TYPE( Color )
DEFINE_ATTRIBUTE_TYPE( Vector2D )
DEFINE_ATTRIBUTE_TYPE( Vector )
DEFINE_ATTRIBUTE_TYPE( Vector4D )
DEFINE_ATTRIBUTE_TYPE( QAngle )
DEFINE_ATTRIBUTE_TYPE( Quaternion )
DEFINE_ATTRIBUTE_TYPE( VMatrix )
DEFINE_ATTRIBUTE_TYPE( CUtlString )
DEFINE_ATTRIBUTE_TYPE( CUtlBinaryBlock )
DEFINE_ATTRIBUTE_TYPE( DmObjectId_t )
DEFINE_ATTRIBUTE_TYPE( DmElementHandle_t )
template class CDmaDecorator< CUtlString, CDmaStringArrayBase< CDmaDataInternal< CUtlVector< CUtlString > > > >;
template class CDmrDecorator< CUtlString, CDmaStringArrayBase< CDmaDataExternal< CUtlVector< CUtlString > > > >;