You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3265 lines
90 KiB
3265 lines
90 KiB
//========= 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( this->GetAttribute() ); |
|
if ( array.IsValid() ) |
|
{ |
|
array.Set( m_nSlot, m_OldValue ); |
|
} |
|
} |
|
|
|
virtual void Redo() |
|
{ |
|
CDmrArray<T> array( this->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( this->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( this->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( this->GetAttribute() ); |
|
if ( array.IsValid() ) |
|
{ |
|
array.RemoveMultiple( m_nIndex, m_nCount ); |
|
} |
|
} |
|
|
|
virtual void Redo() |
|
{ |
|
CDmrArray<T> array( this->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( this->GetAttribute() ); |
|
if ( array.IsValid() ) |
|
{ |
|
array.Remove( m_nIndex ); |
|
} |
|
} |
|
|
|
virtual void Redo() |
|
{ |
|
CDmrArray<T> array( this->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( this->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( this->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, this->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( this->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( this->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 this->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( this->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( this->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( this->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 = this->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 ) |
|
{ |
|
this->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 ) |
|
{ |
|
Assert( pOwner ); |
|
this->m_pAttribute = pOwner->AddExternalAttribute( pAttributeName, CDmAttributeInfo<CUtlVector<T> >::AttributeType(), &(this->Value()) ); |
|
Assert( this->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 ); |
|
this->Attach( this->m_pAttribute->GetAttributeData() ); |
|
} |
|
else |
|
{ |
|
this->m_pAttribute = NULL; |
|
this->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; |
|
this->Attach( this->m_pAttribute->GetAttributeData() ); |
|
} |
|
else |
|
{ |
|
this->m_pAttribute = NULL; |
|
this->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 > > > >;
|
|
|