mirror of
https://github.com/nillerusr/source-engine.git
synced 2024-12-22 22:27:05 +00:00
3266 lines
90 KiB
C++
3266 lines
90 KiB
C++
//========= Copyright Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose:
|
|
//
|
|
//=============================================================================
|
|
|
|
#include "dmattributeinternal.h"
|
|
#include "datamodel/dmelement.h"
|
|
#include "dmelementdictionary.h"
|
|
#include "datamodel/idatamodel.h"
|
|
#include "datamodel.h"
|
|
#include "tier1/uniqueid.h"
|
|
#include "Color.h"
|
|
#include "mathlib/vector.h"
|
|
#include "tier1/utlstring.h"
|
|
#include "tier1/utlbuffer.h"
|
|
#include "tier1/KeyValues.h"
|
|
#include "tier1/mempool.h"
|
|
#include "mathlib/vmatrix.h"
|
|
#include "datamodel/dmattributevar.h"
|
|
#include <ctype.h>
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Tests equality
|
|
//-----------------------------------------------------------------------------
|
|
template< class T >
|
|
bool IsAttributeEqual( const T& src1, const T& src2 )
|
|
{
|
|
return src1 == src2;
|
|
}
|
|
|
|
template< class T >
|
|
bool IsAttributeEqual( const CUtlVector<T> &src1, const CUtlVector<T> &src2 )
|
|
{
|
|
if ( src1.Count() != src2.Count() )
|
|
return false;
|
|
|
|
for ( int i=0; i < src1.Count(); i++ )
|
|
{
|
|
if ( !( src1[i] == src2[i] ) )
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Typesafety check for element handles
|
|
//-----------------------------------------------------------------------------
|
|
static inline bool IsA( DmElementHandle_t hElement, UtlSymId_t type )
|
|
{
|
|
// treat NULL, deleted, and unloaded elements as being of any type -
|
|
// when set, undeleted or loaded, this should be checked again
|
|
CDmElement *pElement = g_pDataModel->GetElement( hElement );
|
|
return pElement ? pElement->IsA( type ) : true;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Element attributes are never directly unserialized
|
|
//-----------------------------------------------------------------------------
|
|
static bool Serialize( CUtlBuffer &buf, DmElementHandle_t src )
|
|
{
|
|
Assert( 0 );
|
|
return false;
|
|
}
|
|
|
|
static bool Unserialize( CUtlBuffer &buf, DmElementHandle_t &dest )
|
|
{
|
|
Assert( 0 );
|
|
return false;
|
|
}
|
|
|
|
static bool Serialize( CUtlBuffer &buf, const DmUnknownAttribute_t& src )
|
|
{
|
|
Assert( 0 );
|
|
return false;
|
|
}
|
|
|
|
static bool Unserialize( CUtlBuffer &buf, DmUnknownAttribute_t &dest )
|
|
{
|
|
Assert( 0 );
|
|
return false;
|
|
}
|
|
|
|
#include "tier1/utlbufferutil.h"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Internal interface for dealing with generic attribute operations
|
|
//-----------------------------------------------------------------------------
|
|
abstract_class IDmAttributeOp
|
|
{
|
|
public:
|
|
virtual void* CreateAttributeData() = 0;
|
|
virtual void DestroyAttributeData( void *pData ) = 0;
|
|
virtual void SetDefaultValue( void *pData ) = 0;
|
|
virtual int DataSize() = 0;
|
|
virtual int ValueSize() = 0;
|
|
virtual bool SerializesOnMultipleLines() = 0;
|
|
virtual bool SkipUnserialize( CUtlBuffer& buf ) = 0;
|
|
virtual const char *AttributeTypeName() = 0;
|
|
|
|
virtual void SetValue( CDmAttribute *pAttribute, DmAttributeType_t valueType, const void *pValue ) = 0;
|
|
virtual void SetMultiple( CDmAttribute *pAttribute, int i, int nCount, DmAttributeType_t valueType, const void *pValue ) = 0;
|
|
virtual void Set( CDmAttribute *pAttribute, int i, DmAttributeType_t valueType, const void *pValue ) = 0;
|
|
virtual void SetToDefaultValue( CDmAttribute *pAttribute ) = 0;
|
|
virtual bool Serialize( const CDmAttribute *pAttribute, CUtlBuffer &buf ) = 0;
|
|
virtual bool Unserialize( CDmAttribute *pAttribute, CUtlBuffer &buf ) = 0;
|
|
virtual bool SerializeElement( const CDmAttribute *pAttribute, int nElement, CUtlBuffer &buf ) = 0;
|
|
virtual bool UnserializeElement( CDmAttribute *pAttribute, CUtlBuffer &buf ) = 0;
|
|
virtual bool UnserializeElement( CDmAttribute *pAttribute, int nElement, CUtlBuffer &buf ) = 0;
|
|
virtual void OnUnserializationFinished( CDmAttribute *pAttribute ) = 0;
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Global table of generic attribute operations looked up by type
|
|
//-----------------------------------------------------------------------------
|
|
static IDmAttributeOp* s_pAttrInfo[ AT_TYPE_COUNT ];
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Implementation of IDmAttributeOp for single-valued attributes
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
template< class T >
|
|
class CDmAttributeOp : public IDmAttributeOp
|
|
{
|
|
public:
|
|
virtual void* CreateAttributeData();
|
|
virtual void DestroyAttributeData( void *pData );
|
|
virtual void SetDefaultValue( void *pData );
|
|
virtual int DataSize();
|
|
virtual int ValueSize();
|
|
virtual bool SerializesOnMultipleLines();
|
|
virtual bool SkipUnserialize( CUtlBuffer& buf );
|
|
virtual const char *AttributeTypeName();
|
|
|
|
virtual void SetValue( CDmAttribute *pAttribute, DmAttributeType_t valueType, const void *pValue );
|
|
virtual void SetMultiple( CDmAttribute *pAttribute, int i, int nCount, DmAttributeType_t valueType, const void *pValue );
|
|
virtual void Set( CDmAttribute *pAttribute, int i, DmAttributeType_t valueType, const void *pValue );
|
|
virtual void SetToDefaultValue( CDmAttribute *pAttribute );
|
|
virtual bool Serialize( const CDmAttribute *pData, CUtlBuffer &buf );
|
|
virtual bool Unserialize( CDmAttribute *pAttribute, CUtlBuffer &buf );
|
|
virtual bool SerializeElement( const CDmAttribute *pAttribute, int nElement, CUtlBuffer &buf );
|
|
virtual bool UnserializeElement( CDmAttribute *pAttribute, CUtlBuffer &buf );
|
|
virtual bool UnserializeElement( CDmAttribute *pAttribute, int nElement, CUtlBuffer &buf );
|
|
virtual void OnUnserializationFinished( CDmAttribute *pAttribute );
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Memory pool useds for CDmAttribute data
|
|
// Over 8 bytes, use the small-block allocator (it aligns to 16 bytes)
|
|
//-----------------------------------------------------------------------------
|
|
CUtlMemoryPool g_DataAlloc4( sizeof( CDmAttribute ), 4, CUtlMemoryPool::GROW_SLOW, "4-byte data pool" );
|
|
CUtlMemoryPool g_DataAlloc8( sizeof( CDmAttribute ), 8, CUtlMemoryPool::GROW_SLOW, "8-byte data pool" );
|
|
|
|
template< class T > void* NewData()
|
|
{
|
|
return new typename CDmAttributeInfo< T >::StorageType_t;
|
|
}
|
|
|
|
template< class T > void DeleteData( void *pData )
|
|
{
|
|
delete reinterpret_cast< typename CDmAttributeInfo< T >::StorageType_t * >( pData );
|
|
}
|
|
|
|
#define USE_SPECIAL_ALLOCATOR( _className, _allocator ) \
|
|
template<> void* NewData< _className >() \
|
|
{ \
|
|
void* pData = _allocator.Alloc( sizeof( CDmAttributeInfo< _className >::StorageType_t ) ); \
|
|
return ::new( pData ) CDmAttributeInfo< _className >::StorageType_t(); \
|
|
} \
|
|
template<> void DeleteData<_className>( void *pData ) \
|
|
{ \
|
|
typedef CDmAttributeInfo< _className >::StorageType_t D; \
|
|
( ( D * )pData )->~D(); \
|
|
_allocator.Free( pData ); \
|
|
}
|
|
|
|
// make sure that the attribute data type sizes are what we think they are to choose the right allocator
|
|
struct CSizeTest
|
|
{
|
|
CSizeTest()
|
|
{
|
|
// test internal value attribute sizes
|
|
COMPILE_TIME_ASSERT( sizeof( int ) == 4 );
|
|
COMPILE_TIME_ASSERT( sizeof( float ) == 4 );
|
|
COMPILE_TIME_ASSERT( sizeof( bool ) <= 4 );
|
|
COMPILE_TIME_ASSERT( sizeof( Color ) == 4 );
|
|
COMPILE_TIME_ASSERT( sizeof( DmElementAttribute_t ) <= 8 );
|
|
COMPILE_TIME_ASSERT( sizeof( Vector2D ) == 8 );
|
|
}
|
|
};
|
|
static CSizeTest g_sizeTest;
|
|
|
|
// turn memdbg off temporarily so we can get at placement new
|
|
#include "tier0/memdbgoff.h"
|
|
|
|
USE_SPECIAL_ALLOCATOR( bool, g_DataAlloc4 )
|
|
USE_SPECIAL_ALLOCATOR( int, g_DataAlloc4 )
|
|
USE_SPECIAL_ALLOCATOR( float, g_DataAlloc4 )
|
|
USE_SPECIAL_ALLOCATOR( DmElementHandle_t, g_DataAlloc4 )
|
|
USE_SPECIAL_ALLOCATOR( Color, g_DataAlloc4 )
|
|
USE_SPECIAL_ALLOCATOR( Vector2D, g_DataAlloc8 )
|
|
|
|
#include "tier0/memdbgon.h"
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Create, destroy attribute data
|
|
//-----------------------------------------------------------------------------
|
|
template< class T >
|
|
void* CDmAttributeOp<T>::CreateAttributeData()
|
|
{
|
|
void *pData = NewData< T >();
|
|
CDmAttributeInfo< T >::SetDefaultValue( *reinterpret_cast<T*>( pData ) );
|
|
return pData;
|
|
}
|
|
|
|
template<> void* CDmAttributeOp< DmUnknownAttribute_t >::CreateAttributeData()
|
|
{
|
|
// Fail if someone tries to create an AT_UNKNOWN attribute
|
|
Assert(0);
|
|
return NULL;
|
|
}
|
|
|
|
template< class T >
|
|
void CDmAttributeOp<T>::DestroyAttributeData( void *pData )
|
|
{
|
|
DeleteData< T >( pData );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Sets the data to a default value, no undo (used for construction)
|
|
//-----------------------------------------------------------------------------
|
|
template< class T >
|
|
void CDmAttributeOp<T>::SetDefaultValue( void *pData )
|
|
{
|
|
CDmAttributeInfo< T >::SetDefaultValue( *reinterpret_cast<T*>( pData ) );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Attribute type name, data size, value size
|
|
//-----------------------------------------------------------------------------
|
|
template< class T >
|
|
const char *CDmAttributeOp<T>::AttributeTypeName()
|
|
{
|
|
return CDmAttributeInfo<T>::AttributeTypeName();
|
|
}
|
|
|
|
template< class T >
|
|
int CDmAttributeOp<T>::DataSize()
|
|
{
|
|
return sizeof( typename CDmAttributeInfo< T >::StorageType_t );
|
|
}
|
|
|
|
template< class T >
|
|
int CDmAttributeOp<T>::ValueSize()
|
|
{
|
|
return sizeof( T );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Value-setting methods
|
|
//-----------------------------------------------------------------------------
|
|
template< class T >
|
|
void CDmAttributeOp<T>::SetToDefaultValue( CDmAttribute *pAttribute )
|
|
{
|
|
T newValue;
|
|
CDmAttributeInfo< T >::SetDefaultValue( newValue );
|
|
pAttribute->SetValue( newValue );
|
|
}
|
|
|
|
template< class T >
|
|
void CDmAttributeOp<T>::SetMultiple( CDmAttribute *pAttribute, int i, int nCount, DmAttributeType_t valueType, const void *pValue )
|
|
{
|
|
Assert(0);
|
|
}
|
|
|
|
template< class T >
|
|
void CDmAttributeOp<T>::Set( CDmAttribute *pAttribute, int i, DmAttributeType_t valueType, const void *pValue )
|
|
{
|
|
Assert(0);
|
|
}
|
|
|
|
template< class T >
|
|
void CDmAttributeOp<T>::SetValue( CDmAttribute *pAttribute, DmAttributeType_t valueType, const void *pValue )
|
|
{
|
|
Assert( pAttribute->GetType() == valueType );
|
|
if ( pAttribute->GetType() == valueType )
|
|
{
|
|
pAttribute->SetValue( *reinterpret_cast< const T* >( pValue ) );
|
|
}
|
|
}
|
|
|
|
#define SET_VALUE_TYPE( _srcType ) \
|
|
case CDmAttributeInfo< _srcType >::ATTRIBUTE_TYPE: \
|
|
pAttribute->SetValue( *reinterpret_cast< const _srcType* >( pValue ) ); \
|
|
break;
|
|
|
|
template<>
|
|
void CDmAttributeOp<int>::SetValue( CDmAttribute *pAttribute, DmAttributeType_t valueType, const void *pValue )
|
|
{
|
|
switch( valueType )
|
|
{
|
|
SET_VALUE_TYPE( int );
|
|
SET_VALUE_TYPE( float );
|
|
SET_VALUE_TYPE( bool );
|
|
|
|
default:
|
|
Assert(0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
template<>
|
|
void CDmAttributeOp<float>::SetValue( CDmAttribute *pAttribute, DmAttributeType_t valueType, const void *pValue )
|
|
{
|
|
switch( valueType )
|
|
{
|
|
SET_VALUE_TYPE( int );
|
|
SET_VALUE_TYPE( float );
|
|
SET_VALUE_TYPE( bool );
|
|
|
|
default:
|
|
Assert(0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
template<>
|
|
void CDmAttributeOp<bool>::SetValue( CDmAttribute *pAttribute, DmAttributeType_t valueType, const void *pValue )
|
|
{
|
|
switch( valueType )
|
|
{
|
|
SET_VALUE_TYPE( int );
|
|
SET_VALUE_TYPE( float );
|
|
SET_VALUE_TYPE( bool );
|
|
|
|
default:
|
|
Assert(0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
template<>
|
|
void CDmAttributeOp<QAngle>::SetValue( CDmAttribute *pAttribute, DmAttributeType_t valueType, const void *pValue )
|
|
{
|
|
switch( valueType )
|
|
{
|
|
SET_VALUE_TYPE( QAngle );
|
|
SET_VALUE_TYPE( Quaternion );
|
|
|
|
default:
|
|
Assert(0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
template<>
|
|
void CDmAttributeOp<Quaternion>::SetValue( CDmAttribute *pAttribute, DmAttributeType_t valueType, const void *pValue )
|
|
{
|
|
switch( valueType )
|
|
{
|
|
SET_VALUE_TYPE( QAngle );
|
|
SET_VALUE_TYPE( Quaternion );
|
|
|
|
default:
|
|
Assert(0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Methods related to serialization
|
|
//-----------------------------------------------------------------------------
|
|
template< class T >
|
|
bool CDmAttributeOp<T>::SerializesOnMultipleLines()
|
|
{
|
|
return ::SerializesOnMultipleLines< T >();
|
|
}
|
|
|
|
template< class T >
|
|
bool CDmAttributeOp<T>::SkipUnserialize( CUtlBuffer& buf )
|
|
{
|
|
T dummy;
|
|
::Unserialize( buf, dummy );
|
|
return buf.IsValid();
|
|
}
|
|
|
|
template< class T >
|
|
bool CDmAttributeOp<T>::Serialize( const CDmAttribute *pAttribute, CUtlBuffer &buf )
|
|
{
|
|
// NOTE: For this to work, the class must have a function defined of type
|
|
// bool Serialize( CUtlBuffer &buf, T &src )
|
|
return ::Serialize( buf, pAttribute->GetValue<T>() );
|
|
}
|
|
|
|
template< class T >
|
|
bool CDmAttributeOp<T>::Unserialize( CDmAttribute *pAttribute, CUtlBuffer &buf )
|
|
{
|
|
// NOTE: For this to work, the class must have a function defined of type
|
|
// bool Unserialize( CUtlBuffer &buf, T &src )
|
|
|
|
T tempVal;
|
|
bool bRet = ::Unserialize( buf, tempVal );
|
|
|
|
// Don't need undo hook since this goes through SetValue route
|
|
pAttribute->SetValue( tempVal );
|
|
|
|
return bRet;
|
|
}
|
|
|
|
template< class T >
|
|
bool CDmAttributeOp<T>::SerializeElement( const CDmAttribute *pData, int nElement, CUtlBuffer &buf )
|
|
{
|
|
Assert( 0 );
|
|
return false;
|
|
}
|
|
|
|
template< class T >
|
|
bool CDmAttributeOp<T>::UnserializeElement( CDmAttribute *pData, CUtlBuffer &buf )
|
|
{
|
|
Assert( 0 );
|
|
return false;
|
|
}
|
|
|
|
template< class T >
|
|
bool CDmAttributeOp<T>::UnserializeElement( CDmAttribute *pData, int nElement, CUtlBuffer &buf )
|
|
{
|
|
Assert( 0 );
|
|
return false;
|
|
}
|
|
|
|
template< class T >
|
|
void CDmAttributeOp<T>::OnUnserializationFinished( CDmAttribute *pAttribute )
|
|
{
|
|
CDmAttributeAccessor::OnChanged( pAttribute, false, true );
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Implementation of IDmAttributeOp for array attributes
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
template< class T >
|
|
class CDmArrayAttributeOp : public CDmAttributeOp< CUtlVector< T > >
|
|
{
|
|
typedef typename CDmAttributeInfo< CUtlVector< T > >::StorageType_t D;
|
|
|
|
public:
|
|
// Inherited from IDmAttributeOp
|
|
virtual void SetValue( CDmAttribute *pAttribute, DmAttributeType_t valueType, const void *pValue );
|
|
virtual void SetMultiple( CDmAttribute *pAttribute, int i, int nCount, DmAttributeType_t valueType, const void *pValue );
|
|
virtual void Set( CDmAttribute *pAttribute, int i, DmAttributeType_t valueType, const void *pValue );
|
|
virtual bool Unserialize( CDmAttribute *pAttribute, CUtlBuffer &buf );
|
|
virtual bool SerializeElement( const CDmAttribute *pData, int nElement, CUtlBuffer &buf );
|
|
virtual bool UnserializeElement( CDmAttribute *pData, CUtlBuffer &buf );
|
|
virtual bool UnserializeElement( CDmAttribute *pData, int nElement, CUtlBuffer &buf );
|
|
virtual void OnUnserializationFinished( CDmAttribute *pAttribute );
|
|
|
|
// Other methods used by CDmaArrayBase
|
|
CDmArrayAttributeOp() : m_pAttribute( NULL ), m_pData( NULL ) {}
|
|
CDmArrayAttributeOp( CDmAttribute *pAttribute ) : m_pAttribute( pAttribute ), m_pData( (D*)m_pAttribute->GetAttributeData() ) {}
|
|
|
|
// Count
|
|
int Count() const;
|
|
|
|
// Insertion
|
|
int AddToTail( const T& src );
|
|
int InsertBefore( int elem, const T& src );
|
|
int InsertMultipleBefore( int elem, int num );
|
|
|
|
// Removal
|
|
void FastRemove( int elem );
|
|
void Remove( int elem );
|
|
void RemoveAll();
|
|
void RemoveMultiple( int elem, int num );
|
|
void Purge();
|
|
|
|
// Element Modification
|
|
void Set( int i, const T& value );
|
|
void SetMultiple( int i, int nCount, const T* pValue );
|
|
void Swap( int i, int j );
|
|
|
|
// Copy related methods
|
|
void CopyArray( const T *pArray, int size );
|
|
void SwapArray( CUtlVector< T >& src ); // Performs a pointer swap
|
|
|
|
void OnAttributeArrayElementAdded( int nFirstElem, int nLastElem, bool bUpdateElementReferences = true );
|
|
void OnAttributeArrayElementRemoved( int nFirstElem, int nLastElem );
|
|
|
|
private:
|
|
bool ShouldInsertElement( const T& src );
|
|
bool ShouldInsert( const T& src );
|
|
void PerformCopyArray( const T *pArray, int nCount );
|
|
D& Data() { return *m_pData; }
|
|
const D& Data() const { return *m_pData; }
|
|
|
|
CDmAttribute *m_pAttribute;
|
|
D* m_pData;
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Undo-related classes
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Undo attribute name change
|
|
//-----------------------------------------------------------------------------
|
|
class CUndoAttributeRenameElement : public CUndoElement
|
|
{
|
|
typedef CUndoElement BaseClass;
|
|
|
|
public:
|
|
CUndoAttributeRenameElement( CDmAttribute *pAttribute, const char *newName )
|
|
: BaseClass( "CUndoAttributeRenameElement" )
|
|
{
|
|
Assert( pAttribute->GetOwner() && pAttribute->GetOwner()->GetFileId() != DMFILEID_INVALID );
|
|
m_hOwner = pAttribute->GetOwner()->GetHandle();
|
|
m_symAttributeOld = pAttribute->GetName();
|
|
m_symAttributeNew = newName;
|
|
}
|
|
|
|
virtual void Undo()
|
|
{
|
|
CDmElement *pOwner = GetOwner();
|
|
if ( pOwner )
|
|
{
|
|
pOwner->RenameAttribute( m_symAttributeNew.String(), m_symAttributeOld.String() );
|
|
}
|
|
}
|
|
|
|
virtual void Redo()
|
|
{
|
|
CDmElement *pOwner = GetOwner();
|
|
if ( pOwner )
|
|
{
|
|
pOwner->RenameAttribute( m_symAttributeOld.String(), m_symAttributeNew.String() );
|
|
}
|
|
}
|
|
|
|
virtual const char *GetDesc()
|
|
{
|
|
static char buf[ 128 ];
|
|
|
|
const char *base = BaseClass::GetDesc();
|
|
Q_snprintf( buf, sizeof( buf ), "%s (%s -> %s)", base, m_symAttributeOld.String(), m_symAttributeNew.String() );
|
|
return buf;
|
|
}
|
|
|
|
private:
|
|
CDmElement *GetOwner()
|
|
{
|
|
return g_pDataModel->GetElement( m_hOwner );
|
|
}
|
|
|
|
CUtlSymbol m_symAttributeOld;
|
|
CUtlSymbol m_symAttributeNew;
|
|
DmElementHandle_t m_hOwner;
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Undo single-valued attribute value changed
|
|
//-----------------------------------------------------------------------------
|
|
template< class T >
|
|
class CUndoAttributeSetValueElement : public CUndoElement
|
|
{
|
|
typedef CUndoElement BaseClass;
|
|
public:
|
|
CUndoAttributeSetValueElement( CDmAttribute *pAttribute, const T &newValue )
|
|
: BaseClass( "CUndoAttributeSetValueElement" )
|
|
{
|
|
Assert( pAttribute->GetOwner() && pAttribute->GetOwner()->GetFileId() != DMFILEID_INVALID );
|
|
m_hOwner = pAttribute->GetOwner()->GetHandle();
|
|
m_OldValue = pAttribute->GetValue<T>();
|
|
m_Value = newValue;
|
|
m_symAttribute = pAttribute->GetNameSymbol( );
|
|
}
|
|
|
|
CDmElement *GetOwner()
|
|
{
|
|
return g_pDataModel->GetElement( m_hOwner );
|
|
}
|
|
|
|
virtual void Undo()
|
|
{
|
|
CDmAttribute *pAttribute = GetAttribute();
|
|
if ( pAttribute && !pAttribute->IsFlagSet( FATTRIB_READONLY ) )
|
|
{
|
|
pAttribute->SetValue<T>( m_OldValue );
|
|
}
|
|
}
|
|
virtual void Redo()
|
|
{
|
|
CDmAttribute *pAttribute = GetAttribute();
|
|
if ( pAttribute && !pAttribute->IsFlagSet( FATTRIB_READONLY ) )
|
|
{
|
|
pAttribute->SetValue<T>( m_Value );
|
|
}
|
|
}
|
|
|
|
virtual const char *GetDesc()
|
|
{
|
|
static char buf[ 128 ];
|
|
|
|
const char *base = BaseClass::GetDesc();
|
|
CDmAttribute *pAtt = GetAttribute();
|
|
CUtlBuffer serialized( 0, 0, CUtlBuffer::TEXT_BUFFER );
|
|
if ( pAtt && pAtt->GetType() != AT_ELEMENT )
|
|
{
|
|
::Serialize( serialized, m_Value );
|
|
}
|
|
Q_snprintf( buf, sizeof( buf ), "%s(%s) = %s", base, g_pDataModel->GetString( m_symAttribute ), serialized.Base() ? (const char*)serialized.Base() : "\"\"" );
|
|
return buf;
|
|
}
|
|
|
|
private:
|
|
CDmAttribute *GetAttribute()
|
|
{
|
|
CDmElement *pOwner = GetOwner();
|
|
if ( pOwner )
|
|
{
|
|
const char *pAttributeName = g_pDataModel->GetString( m_symAttribute );
|
|
return pOwner->GetAttribute( pAttributeName );
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
typedef T StorageType_t;
|
|
|
|
CUtlSymbol m_symAttribute;
|
|
DmElementHandle_t m_hOwner;
|
|
StorageType_t m_OldValue;
|
|
StorageType_t m_Value;
|
|
};
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Base undo for array attributes
|
|
//-----------------------------------------------------------------------------
|
|
template< class T >
|
|
class CUndoAttributeArrayBase : public CUndoElement
|
|
{
|
|
typedef CUndoElement BaseClass;
|
|
|
|
public:
|
|
CUndoAttributeArrayBase( CDmAttribute *pAttribute, const char *pUndoName ) : BaseClass( pUndoName )
|
|
{
|
|
m_hOwner = pAttribute->GetOwner()->GetHandle();
|
|
m_symAttribute = pAttribute->GetNameSymbol( );
|
|
}
|
|
|
|
protected:
|
|
typedef typename CDmAttributeUndoStorageType< T >::UndoStorageType StorageType_t;
|
|
|
|
CDmElement *GetOwner()
|
|
{
|
|
return g_pDataModel->GetElement( m_hOwner );
|
|
}
|
|
|
|
const char *GetAttributeName()
|
|
{
|
|
return g_pDataModel->GetString( m_symAttribute );
|
|
}
|
|
|
|
CDmAttribute *GetAttribute()
|
|
{
|
|
const char *pAttributeName = GetAttributeName();
|
|
CDmElement *pOwner = GetOwner();
|
|
if ( pOwner )
|
|
return pOwner->GetAttribute( pAttributeName );
|
|
Assert( 0 );
|
|
return NULL;
|
|
}
|
|
|
|
private:
|
|
CUtlSymbol m_symAttribute;
|
|
DmElementHandle_t m_hOwner;
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Undo for setting a single element
|
|
//-----------------------------------------------------------------------------
|
|
template< class T >
|
|
class CUndoArrayAttributeSetValueElement : public CUndoAttributeArrayBase<T>
|
|
{
|
|
typedef CUndoAttributeArrayBase<T> BaseClass;
|
|
|
|
public:
|
|
CUndoArrayAttributeSetValueElement( CDmAttribute *pAttribute, int slot, const T &newValue ) :
|
|
BaseClass( pAttribute, "CUndoArrayAttributeSetValueElement" ),
|
|
m_nSlot( slot )
|
|
{
|
|
Assert( pAttribute->GetOwner() && pAttribute->GetOwner()->GetFileId() != DMFILEID_INVALID );
|
|
|
|
CDmrArray<T> array( pAttribute );
|
|
m_OldValue = array[ slot ];
|
|
m_Value = newValue;
|
|
}
|
|
|
|
virtual void Undo()
|
|
{
|
|
CDmrArray<T> array( 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 > > > >;
|