Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3265 lines
90 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "dmattributeinternal.h"
  7. #include "datamodel/dmelement.h"
  8. #include "dmelementdictionary.h"
  9. #include "datamodel/idatamodel.h"
  10. #include "datamodel.h"
  11. #include "tier1/uniqueid.h"
  12. #include "Color.h"
  13. #include "mathlib/vector.h"
  14. #include "tier1/utlstring.h"
  15. #include "tier1/utlbuffer.h"
  16. #include "tier1/KeyValues.h"
  17. #include "tier1/mempool.h"
  18. #include "mathlib/vmatrix.h"
  19. #include "datamodel/dmattributevar.h"
  20. #include <ctype.h>
  21. // memdbgon must be the last include file in a .cpp file!!!
  22. #include "tier0/memdbgon.h"
  23. //-----------------------------------------------------------------------------
  24. // Tests equality
  25. //-----------------------------------------------------------------------------
  26. template< class T >
  27. bool IsAttributeEqual( const T& src1, const T& src2 )
  28. {
  29. return src1 == src2;
  30. }
  31. template< class T >
  32. bool IsAttributeEqual( const CUtlVector<T> &src1, const CUtlVector<T> &src2 )
  33. {
  34. if ( src1.Count() != src2.Count() )
  35. return false;
  36. for ( int i=0; i < src1.Count(); i++ )
  37. {
  38. if ( !( src1[i] == src2[i] ) )
  39. return false;
  40. }
  41. return true;
  42. }
  43. //-----------------------------------------------------------------------------
  44. // Typesafety check for element handles
  45. //-----------------------------------------------------------------------------
  46. static inline bool IsA( DmElementHandle_t hElement, UtlSymId_t type )
  47. {
  48. // treat NULL, deleted, and unloaded elements as being of any type -
  49. // when set, undeleted or loaded, this should be checked again
  50. CDmElement *pElement = g_pDataModel->GetElement( hElement );
  51. return pElement ? pElement->IsA( type ) : true;
  52. }
  53. //-----------------------------------------------------------------------------
  54. // Element attributes are never directly unserialized
  55. //-----------------------------------------------------------------------------
  56. static bool Serialize( CUtlBuffer &buf, DmElementHandle_t src )
  57. {
  58. Assert( 0 );
  59. return false;
  60. }
  61. static bool Unserialize( CUtlBuffer &buf, DmElementHandle_t &dest )
  62. {
  63. Assert( 0 );
  64. return false;
  65. }
  66. static bool Serialize( CUtlBuffer &buf, const DmUnknownAttribute_t& src )
  67. {
  68. Assert( 0 );
  69. return false;
  70. }
  71. static bool Unserialize( CUtlBuffer &buf, DmUnknownAttribute_t &dest )
  72. {
  73. Assert( 0 );
  74. return false;
  75. }
  76. #include "tier1/utlbufferutil.h"
  77. //-----------------------------------------------------------------------------
  78. // Internal interface for dealing with generic attribute operations
  79. //-----------------------------------------------------------------------------
  80. abstract_class IDmAttributeOp
  81. {
  82. public:
  83. virtual void* CreateAttributeData() = 0;
  84. virtual void DestroyAttributeData( void *pData ) = 0;
  85. virtual void SetDefaultValue( void *pData ) = 0;
  86. virtual int DataSize() = 0;
  87. virtual int ValueSize() = 0;
  88. virtual bool SerializesOnMultipleLines() = 0;
  89. virtual bool SkipUnserialize( CUtlBuffer& buf ) = 0;
  90. virtual const char *AttributeTypeName() = 0;
  91. virtual void SetValue( CDmAttribute *pAttribute, DmAttributeType_t valueType, const void *pValue ) = 0;
  92. virtual void SetMultiple( CDmAttribute *pAttribute, int i, int nCount, DmAttributeType_t valueType, const void *pValue ) = 0;
  93. virtual void Set( CDmAttribute *pAttribute, int i, DmAttributeType_t valueType, const void *pValue ) = 0;
  94. virtual void SetToDefaultValue( CDmAttribute *pAttribute ) = 0;
  95. virtual bool Serialize( const CDmAttribute *pAttribute, CUtlBuffer &buf ) = 0;
  96. virtual bool Unserialize( CDmAttribute *pAttribute, CUtlBuffer &buf ) = 0;
  97. virtual bool SerializeElement( const CDmAttribute *pAttribute, int nElement, CUtlBuffer &buf ) = 0;
  98. virtual bool UnserializeElement( CDmAttribute *pAttribute, CUtlBuffer &buf ) = 0;
  99. virtual bool UnserializeElement( CDmAttribute *pAttribute, int nElement, CUtlBuffer &buf ) = 0;
  100. virtual void OnUnserializationFinished( CDmAttribute *pAttribute ) = 0;
  101. };
  102. //-----------------------------------------------------------------------------
  103. // Global table of generic attribute operations looked up by type
  104. //-----------------------------------------------------------------------------
  105. static IDmAttributeOp* s_pAttrInfo[ AT_TYPE_COUNT ];
  106. //-----------------------------------------------------------------------------
  107. //
  108. // Implementation of IDmAttributeOp for single-valued attributes
  109. //
  110. //-----------------------------------------------------------------------------
  111. template< class T >
  112. class CDmAttributeOp : public IDmAttributeOp
  113. {
  114. public:
  115. virtual void* CreateAttributeData();
  116. virtual void DestroyAttributeData( void *pData );
  117. virtual void SetDefaultValue( void *pData );
  118. virtual int DataSize();
  119. virtual int ValueSize();
  120. virtual bool SerializesOnMultipleLines();
  121. virtual bool SkipUnserialize( CUtlBuffer& buf );
  122. virtual const char *AttributeTypeName();
  123. virtual void SetValue( CDmAttribute *pAttribute, DmAttributeType_t valueType, const void *pValue );
  124. virtual void SetMultiple( CDmAttribute *pAttribute, int i, int nCount, DmAttributeType_t valueType, const void *pValue );
  125. virtual void Set( CDmAttribute *pAttribute, int i, DmAttributeType_t valueType, const void *pValue );
  126. virtual void SetToDefaultValue( CDmAttribute *pAttribute );
  127. virtual bool Serialize( const CDmAttribute *pData, CUtlBuffer &buf );
  128. virtual bool Unserialize( CDmAttribute *pAttribute, CUtlBuffer &buf );
  129. virtual bool SerializeElement( const CDmAttribute *pAttribute, int nElement, CUtlBuffer &buf );
  130. virtual bool UnserializeElement( CDmAttribute *pAttribute, CUtlBuffer &buf );
  131. virtual bool UnserializeElement( CDmAttribute *pAttribute, int nElement, CUtlBuffer &buf );
  132. virtual void OnUnserializationFinished( CDmAttribute *pAttribute );
  133. };
  134. //-----------------------------------------------------------------------------
  135. // Memory pool useds for CDmAttribute data
  136. // Over 8 bytes, use the small-block allocator (it aligns to 16 bytes)
  137. //-----------------------------------------------------------------------------
  138. CUtlMemoryPool g_DataAlloc4( sizeof( CDmAttribute ), 4, CUtlMemoryPool::GROW_SLOW, "4-byte data pool" );
  139. CUtlMemoryPool g_DataAlloc8( sizeof( CDmAttribute ), 8, CUtlMemoryPool::GROW_SLOW, "8-byte data pool" );
  140. template< class T > void* NewData()
  141. {
  142. return new typename CDmAttributeInfo< T >::StorageType_t;
  143. }
  144. template< class T > void DeleteData( void *pData )
  145. {
  146. delete reinterpret_cast< typename CDmAttributeInfo< T >::StorageType_t * >( pData );
  147. }
  148. #define USE_SPECIAL_ALLOCATOR( _className, _allocator ) \
  149. template<> void* NewData< _className >() \
  150. { \
  151. void* pData = _allocator.Alloc( sizeof( CDmAttributeInfo< _className >::StorageType_t ) ); \
  152. return ::new( pData ) CDmAttributeInfo< _className >::StorageType_t(); \
  153. } \
  154. template<> void DeleteData<_className>( void *pData ) \
  155. { \
  156. typedef CDmAttributeInfo< _className >::StorageType_t D; \
  157. ( ( D * )pData )->~D(); \
  158. _allocator.Free( pData ); \
  159. }
  160. // make sure that the attribute data type sizes are what we think they are to choose the right allocator
  161. struct CSizeTest
  162. {
  163. CSizeTest()
  164. {
  165. // test internal value attribute sizes
  166. COMPILE_TIME_ASSERT( sizeof( int ) == 4 );
  167. COMPILE_TIME_ASSERT( sizeof( float ) == 4 );
  168. COMPILE_TIME_ASSERT( sizeof( bool ) <= 4 );
  169. COMPILE_TIME_ASSERT( sizeof( Color ) == 4 );
  170. COMPILE_TIME_ASSERT( sizeof( DmElementAttribute_t ) <= 8 );
  171. COMPILE_TIME_ASSERT( sizeof( Vector2D ) == 8 );
  172. }
  173. };
  174. static CSizeTest g_sizeTest;
  175. // turn memdbg off temporarily so we can get at placement new
  176. #include "tier0/memdbgoff.h"
  177. USE_SPECIAL_ALLOCATOR( bool, g_DataAlloc4 )
  178. USE_SPECIAL_ALLOCATOR( int, g_DataAlloc4 )
  179. USE_SPECIAL_ALLOCATOR( float, g_DataAlloc4 )
  180. USE_SPECIAL_ALLOCATOR( DmElementHandle_t, g_DataAlloc4 )
  181. USE_SPECIAL_ALLOCATOR( Color, g_DataAlloc4 )
  182. USE_SPECIAL_ALLOCATOR( Vector2D, g_DataAlloc8 )
  183. #include "tier0/memdbgon.h"
  184. //-----------------------------------------------------------------------------
  185. // Create, destroy attribute data
  186. //-----------------------------------------------------------------------------
  187. template< class T >
  188. void* CDmAttributeOp<T>::CreateAttributeData()
  189. {
  190. void *pData = NewData< T >();
  191. CDmAttributeInfo< T >::SetDefaultValue( *reinterpret_cast<T*>( pData ) );
  192. return pData;
  193. }
  194. template<> void* CDmAttributeOp< DmUnknownAttribute_t >::CreateAttributeData()
  195. {
  196. // Fail if someone tries to create an AT_UNKNOWN attribute
  197. Assert(0);
  198. return NULL;
  199. }
  200. template< class T >
  201. void CDmAttributeOp<T>::DestroyAttributeData( void *pData )
  202. {
  203. DeleteData< T >( pData );
  204. }
  205. //-----------------------------------------------------------------------------
  206. // Sets the data to a default value, no undo (used for construction)
  207. //-----------------------------------------------------------------------------
  208. template< class T >
  209. void CDmAttributeOp<T>::SetDefaultValue( void *pData )
  210. {
  211. CDmAttributeInfo< T >::SetDefaultValue( *reinterpret_cast<T*>( pData ) );
  212. }
  213. //-----------------------------------------------------------------------------
  214. // Attribute type name, data size, value size
  215. //-----------------------------------------------------------------------------
  216. template< class T >
  217. const char *CDmAttributeOp<T>::AttributeTypeName()
  218. {
  219. return CDmAttributeInfo<T>::AttributeTypeName();
  220. }
  221. template< class T >
  222. int CDmAttributeOp<T>::DataSize()
  223. {
  224. return sizeof( typename CDmAttributeInfo< T >::StorageType_t );
  225. }
  226. template< class T >
  227. int CDmAttributeOp<T>::ValueSize()
  228. {
  229. return sizeof( T );
  230. }
  231. //-----------------------------------------------------------------------------
  232. // Value-setting methods
  233. //-----------------------------------------------------------------------------
  234. template< class T >
  235. void CDmAttributeOp<T>::SetToDefaultValue( CDmAttribute *pAttribute )
  236. {
  237. T newValue;
  238. CDmAttributeInfo< T >::SetDefaultValue( newValue );
  239. pAttribute->SetValue( newValue );
  240. }
  241. template< class T >
  242. void CDmAttributeOp<T>::SetMultiple( CDmAttribute *pAttribute, int i, int nCount, DmAttributeType_t valueType, const void *pValue )
  243. {
  244. Assert(0);
  245. }
  246. template< class T >
  247. void CDmAttributeOp<T>::Set( CDmAttribute *pAttribute, int i, DmAttributeType_t valueType, const void *pValue )
  248. {
  249. Assert(0);
  250. }
  251. template< class T >
  252. void CDmAttributeOp<T>::SetValue( CDmAttribute *pAttribute, DmAttributeType_t valueType, const void *pValue )
  253. {
  254. Assert( pAttribute->GetType() == valueType );
  255. if ( pAttribute->GetType() == valueType )
  256. {
  257. pAttribute->SetValue( *reinterpret_cast< const T* >( pValue ) );
  258. }
  259. }
  260. #define SET_VALUE_TYPE( _srcType ) \
  261. case CDmAttributeInfo< _srcType >::ATTRIBUTE_TYPE: \
  262. pAttribute->SetValue( *reinterpret_cast< const _srcType* >( pValue ) ); \
  263. break;
  264. template<>
  265. void CDmAttributeOp<int>::SetValue( CDmAttribute *pAttribute, DmAttributeType_t valueType, const void *pValue )
  266. {
  267. switch( valueType )
  268. {
  269. SET_VALUE_TYPE( int );
  270. SET_VALUE_TYPE( float );
  271. SET_VALUE_TYPE( bool );
  272. default:
  273. Assert(0);
  274. break;
  275. }
  276. }
  277. template<>
  278. void CDmAttributeOp<float>::SetValue( CDmAttribute *pAttribute, DmAttributeType_t valueType, const void *pValue )
  279. {
  280. switch( valueType )
  281. {
  282. SET_VALUE_TYPE( int );
  283. SET_VALUE_TYPE( float );
  284. SET_VALUE_TYPE( bool );
  285. default:
  286. Assert(0);
  287. break;
  288. }
  289. }
  290. template<>
  291. void CDmAttributeOp<bool>::SetValue( CDmAttribute *pAttribute, DmAttributeType_t valueType, const void *pValue )
  292. {
  293. switch( valueType )
  294. {
  295. SET_VALUE_TYPE( int );
  296. SET_VALUE_TYPE( float );
  297. SET_VALUE_TYPE( bool );
  298. default:
  299. Assert(0);
  300. break;
  301. }
  302. }
  303. template<>
  304. void CDmAttributeOp<QAngle>::SetValue( CDmAttribute *pAttribute, DmAttributeType_t valueType, const void *pValue )
  305. {
  306. switch( valueType )
  307. {
  308. SET_VALUE_TYPE( QAngle );
  309. SET_VALUE_TYPE( Quaternion );
  310. default:
  311. Assert(0);
  312. break;
  313. }
  314. }
  315. template<>
  316. void CDmAttributeOp<Quaternion>::SetValue( CDmAttribute *pAttribute, DmAttributeType_t valueType, const void *pValue )
  317. {
  318. switch( valueType )
  319. {
  320. SET_VALUE_TYPE( QAngle );
  321. SET_VALUE_TYPE( Quaternion );
  322. default:
  323. Assert(0);
  324. break;
  325. }
  326. }
  327. //-----------------------------------------------------------------------------
  328. // Methods related to serialization
  329. //-----------------------------------------------------------------------------
  330. template< class T >
  331. bool CDmAttributeOp<T>::SerializesOnMultipleLines()
  332. {
  333. return ::SerializesOnMultipleLines< T >();
  334. }
  335. template< class T >
  336. bool CDmAttributeOp<T>::SkipUnserialize( CUtlBuffer& buf )
  337. {
  338. T dummy;
  339. ::Unserialize( buf, dummy );
  340. return buf.IsValid();
  341. }
  342. template< class T >
  343. bool CDmAttributeOp<T>::Serialize( const CDmAttribute *pAttribute, CUtlBuffer &buf )
  344. {
  345. // NOTE: For this to work, the class must have a function defined of type
  346. // bool Serialize( CUtlBuffer &buf, T &src )
  347. return ::Serialize( buf, pAttribute->GetValue<T>() );
  348. }
  349. template< class T >
  350. bool CDmAttributeOp<T>::Unserialize( CDmAttribute *pAttribute, CUtlBuffer &buf )
  351. {
  352. // NOTE: For this to work, the class must have a function defined of type
  353. // bool Unserialize( CUtlBuffer &buf, T &src )
  354. T tempVal;
  355. bool bRet = ::Unserialize( buf, tempVal );
  356. // Don't need undo hook since this goes through SetValue route
  357. pAttribute->SetValue( tempVal );
  358. return bRet;
  359. }
  360. template< class T >
  361. bool CDmAttributeOp<T>::SerializeElement( const CDmAttribute *pData, int nElement, CUtlBuffer &buf )
  362. {
  363. Assert( 0 );
  364. return false;
  365. }
  366. template< class T >
  367. bool CDmAttributeOp<T>::UnserializeElement( CDmAttribute *pData, CUtlBuffer &buf )
  368. {
  369. Assert( 0 );
  370. return false;
  371. }
  372. template< class T >
  373. bool CDmAttributeOp<T>::UnserializeElement( CDmAttribute *pData, int nElement, CUtlBuffer &buf )
  374. {
  375. Assert( 0 );
  376. return false;
  377. }
  378. template< class T >
  379. void CDmAttributeOp<T>::OnUnserializationFinished( CDmAttribute *pAttribute )
  380. {
  381. CDmAttributeAccessor::OnChanged( pAttribute, false, true );
  382. }
  383. //-----------------------------------------------------------------------------
  384. //
  385. // Implementation of IDmAttributeOp for array attributes
  386. //
  387. //-----------------------------------------------------------------------------
  388. template< class T >
  389. class CDmArrayAttributeOp : public CDmAttributeOp< CUtlVector< T > >
  390. {
  391. typedef typename CDmAttributeInfo< CUtlVector< T > >::StorageType_t D;
  392. public:
  393. // Inherited from IDmAttributeOp
  394. virtual void SetValue( CDmAttribute *pAttribute, DmAttributeType_t valueType, const void *pValue );
  395. virtual void SetMultiple( CDmAttribute *pAttribute, int i, int nCount, DmAttributeType_t valueType, const void *pValue );
  396. virtual void Set( CDmAttribute *pAttribute, int i, DmAttributeType_t valueType, const void *pValue );
  397. virtual bool Unserialize( CDmAttribute *pAttribute, CUtlBuffer &buf );
  398. virtual bool SerializeElement( const CDmAttribute *pData, int nElement, CUtlBuffer &buf );
  399. virtual bool UnserializeElement( CDmAttribute *pData, CUtlBuffer &buf );
  400. virtual bool UnserializeElement( CDmAttribute *pData, int nElement, CUtlBuffer &buf );
  401. virtual void OnUnserializationFinished( CDmAttribute *pAttribute );
  402. // Other methods used by CDmaArrayBase
  403. CDmArrayAttributeOp() : m_pAttribute( NULL ), m_pData( NULL ) {}
  404. CDmArrayAttributeOp( CDmAttribute *pAttribute ) : m_pAttribute( pAttribute ), m_pData( (D*)m_pAttribute->GetAttributeData() ) {}
  405. // Count
  406. int Count() const;
  407. // Insertion
  408. int AddToTail( const T& src );
  409. int InsertBefore( int elem, const T& src );
  410. int InsertMultipleBefore( int elem, int num );
  411. // Removal
  412. void FastRemove( int elem );
  413. void Remove( int elem );
  414. void RemoveAll();
  415. void RemoveMultiple( int elem, int num );
  416. void Purge();
  417. // Element Modification
  418. void Set( int i, const T& value );
  419. void SetMultiple( int i, int nCount, const T* pValue );
  420. void Swap( int i, int j );
  421. // Copy related methods
  422. void CopyArray( const T *pArray, int size );
  423. void SwapArray( CUtlVector< T >& src ); // Performs a pointer swap
  424. void OnAttributeArrayElementAdded( int nFirstElem, int nLastElem, bool bUpdateElementReferences = true );
  425. void OnAttributeArrayElementRemoved( int nFirstElem, int nLastElem );
  426. private:
  427. bool ShouldInsertElement( const T& src );
  428. bool ShouldInsert( const T& src );
  429. void PerformCopyArray( const T *pArray, int nCount );
  430. D& Data() { return *m_pData; }
  431. const D& Data() const { return *m_pData; }
  432. CDmAttribute *m_pAttribute;
  433. D* m_pData;
  434. };
  435. //-----------------------------------------------------------------------------
  436. //
  437. // Undo-related classes
  438. //
  439. //-----------------------------------------------------------------------------
  440. //-----------------------------------------------------------------------------
  441. // Undo attribute name change
  442. //-----------------------------------------------------------------------------
  443. class CUndoAttributeRenameElement : public CUndoElement
  444. {
  445. typedef CUndoElement BaseClass;
  446. public:
  447. CUndoAttributeRenameElement( CDmAttribute *pAttribute, const char *newName )
  448. : BaseClass( "CUndoAttributeRenameElement" )
  449. {
  450. Assert( pAttribute->GetOwner() && pAttribute->GetOwner()->GetFileId() != DMFILEID_INVALID );
  451. m_hOwner = pAttribute->GetOwner()->GetHandle();
  452. m_symAttributeOld = pAttribute->GetName();
  453. m_symAttributeNew = newName;
  454. }
  455. virtual void Undo()
  456. {
  457. CDmElement *pOwner = GetOwner();
  458. if ( pOwner )
  459. {
  460. pOwner->RenameAttribute( m_symAttributeNew.String(), m_symAttributeOld.String() );
  461. }
  462. }
  463. virtual void Redo()
  464. {
  465. CDmElement *pOwner = GetOwner();
  466. if ( pOwner )
  467. {
  468. pOwner->RenameAttribute( m_symAttributeOld.String(), m_symAttributeNew.String() );
  469. }
  470. }
  471. virtual const char *GetDesc()
  472. {
  473. static char buf[ 128 ];
  474. const char *base = BaseClass::GetDesc();
  475. Q_snprintf( buf, sizeof( buf ), "%s (%s -> %s)", base, m_symAttributeOld.String(), m_symAttributeNew.String() );
  476. return buf;
  477. }
  478. private:
  479. CDmElement *GetOwner()
  480. {
  481. return g_pDataModel->GetElement( m_hOwner );
  482. }
  483. CUtlSymbol m_symAttributeOld;
  484. CUtlSymbol m_symAttributeNew;
  485. DmElementHandle_t m_hOwner;
  486. };
  487. //-----------------------------------------------------------------------------
  488. // Undo single-valued attribute value changed
  489. //-----------------------------------------------------------------------------
  490. template< class T >
  491. class CUndoAttributeSetValueElement : public CUndoElement
  492. {
  493. typedef CUndoElement BaseClass;
  494. public:
  495. CUndoAttributeSetValueElement( CDmAttribute *pAttribute, const T &newValue )
  496. : BaseClass( "CUndoAttributeSetValueElement" )
  497. {
  498. Assert( pAttribute->GetOwner() && pAttribute->GetOwner()->GetFileId() != DMFILEID_INVALID );
  499. m_hOwner = pAttribute->GetOwner()->GetHandle();
  500. m_OldValue = pAttribute->GetValue<T>();
  501. m_Value = newValue;
  502. m_symAttribute = pAttribute->GetNameSymbol( );
  503. }
  504. CDmElement *GetOwner()
  505. {
  506. return g_pDataModel->GetElement( m_hOwner );
  507. }
  508. virtual void Undo()
  509. {
  510. CDmAttribute *pAttribute = GetAttribute();
  511. if ( pAttribute && !pAttribute->IsFlagSet( FATTRIB_READONLY ) )
  512. {
  513. pAttribute->SetValue<T>( m_OldValue );
  514. }
  515. }
  516. virtual void Redo()
  517. {
  518. CDmAttribute *pAttribute = GetAttribute();
  519. if ( pAttribute && !pAttribute->IsFlagSet( FATTRIB_READONLY ) )
  520. {
  521. pAttribute->SetValue<T>( m_Value );
  522. }
  523. }
  524. virtual const char *GetDesc()
  525. {
  526. static char buf[ 128 ];
  527. const char *base = BaseClass::GetDesc();
  528. CDmAttribute *pAtt = GetAttribute();
  529. CUtlBuffer serialized( 0, 0, CUtlBuffer::TEXT_BUFFER );
  530. if ( pAtt && pAtt->GetType() != AT_ELEMENT )
  531. {
  532. ::Serialize( serialized, m_Value );
  533. }
  534. Q_snprintf( buf, sizeof( buf ), "%s(%s) = %s", base, g_pDataModel->GetString( m_symAttribute ), serialized.Base() ? (const char*)serialized.Base() : "\"\"" );
  535. return buf;
  536. }
  537. private:
  538. CDmAttribute *GetAttribute()
  539. {
  540. CDmElement *pOwner = GetOwner();
  541. if ( pOwner )
  542. {
  543. const char *pAttributeName = g_pDataModel->GetString( m_symAttribute );
  544. return pOwner->GetAttribute( pAttributeName );
  545. }
  546. return NULL;
  547. }
  548. typedef T StorageType_t;
  549. CUtlSymbol m_symAttribute;
  550. DmElementHandle_t m_hOwner;
  551. StorageType_t m_OldValue;
  552. StorageType_t m_Value;
  553. };
  554. //-----------------------------------------------------------------------------
  555. // Base undo for array attributes
  556. //-----------------------------------------------------------------------------
  557. template< class T >
  558. class CUndoAttributeArrayBase : public CUndoElement
  559. {
  560. typedef CUndoElement BaseClass;
  561. public:
  562. CUndoAttributeArrayBase( CDmAttribute *pAttribute, const char *pUndoName ) : BaseClass( pUndoName )
  563. {
  564. m_hOwner = pAttribute->GetOwner()->GetHandle();
  565. m_symAttribute = pAttribute->GetNameSymbol( );
  566. }
  567. protected:
  568. typedef typename CDmAttributeUndoStorageType< T >::UndoStorageType StorageType_t;
  569. CDmElement *GetOwner()
  570. {
  571. return g_pDataModel->GetElement( m_hOwner );
  572. }
  573. const char *GetAttributeName()
  574. {
  575. return g_pDataModel->GetString( m_symAttribute );
  576. }
  577. CDmAttribute *GetAttribute()
  578. {
  579. const char *pAttributeName = GetAttributeName();
  580. CDmElement *pOwner = GetOwner();
  581. if ( pOwner )
  582. return pOwner->GetAttribute( pAttributeName );
  583. Assert( 0 );
  584. return NULL;
  585. }
  586. private:
  587. CUtlSymbol m_symAttribute;
  588. DmElementHandle_t m_hOwner;
  589. };
  590. //-----------------------------------------------------------------------------
  591. // Undo for setting a single element
  592. //-----------------------------------------------------------------------------
  593. template< class T >
  594. class CUndoArrayAttributeSetValueElement : public CUndoAttributeArrayBase<T>
  595. {
  596. typedef CUndoAttributeArrayBase<T> BaseClass;
  597. public:
  598. CUndoArrayAttributeSetValueElement( CDmAttribute *pAttribute, int slot, const T &newValue ) :
  599. BaseClass( pAttribute, "CUndoArrayAttributeSetValueElement" ),
  600. m_nSlot( slot )
  601. {
  602. Assert( pAttribute->GetOwner() && pAttribute->GetOwner()->GetFileId() != DMFILEID_INVALID );
  603. CDmrArray<T> array( pAttribute );
  604. m_OldValue = array[ slot ];
  605. m_Value = newValue;
  606. }
  607. virtual void Undo()
  608. {
  609. CDmrArray<T> array( GetAttribute() );
  610. if ( array.IsValid() )
  611. {
  612. array.Set( m_nSlot, m_OldValue );
  613. }
  614. }
  615. virtual void Redo()
  616. {
  617. CDmrArray<T> array( GetAttribute() );
  618. if ( array.IsValid() )
  619. {
  620. array.Set( m_nSlot, m_Value );
  621. }
  622. }
  623. private:
  624. int m_nSlot;
  625. typename CUndoAttributeArrayBase<T>::StorageType_t m_OldValue;
  626. typename CUndoAttributeArrayBase<T>::StorageType_t m_Value;
  627. };
  628. //-----------------------------------------------------------------------------
  629. // Undo for setting a multiple elements
  630. //-----------------------------------------------------------------------------
  631. template< class T >
  632. class CUndoArrayAttributeSetMultipleValueElement : public CUndoAttributeArrayBase<T>
  633. {
  634. typedef CUndoAttributeArrayBase<T> BaseClass;
  635. public:
  636. CUndoArrayAttributeSetMultipleValueElement( CDmAttribute *pAttribute, int nSlot, int nCount, const T *pNewValue ) :
  637. BaseClass( pAttribute, "CUndoArrayAttributeSetMultipleValueElement" ),
  638. m_nSlot( nSlot ), m_nCount( nCount )
  639. {
  640. Assert( pAttribute->GetOwner() && pAttribute->GetOwner()->GetFileId() != DMFILEID_INVALID );
  641. m_pOldValue = new typename CUndoAttributeArrayBase<T>::StorageType_t[nCount];
  642. m_pValue = new typename CUndoAttributeArrayBase<T>::StorageType_t[nCount];
  643. CDmrArray<T> array( pAttribute );
  644. for ( int i = 0; i < nCount; ++i )
  645. {
  646. m_pOldValue[i] = array[ nSlot+i ];
  647. m_pValue[i] = pNewValue[ i ];
  648. }
  649. }
  650. ~CUndoArrayAttributeSetMultipleValueElement()
  651. {
  652. // this is a hack necessitated by MSVC's lack of partially specialized member template support
  653. // (ie otherwise I'd just create a CUndoArrayAttributeSetMultipleValueElement< DmElementHandle_t,BaseClass> version with this code)
  654. // anyways, the casting hackiness only happens when the value is actually a DmElementHandle_t, so it's completely safe
  655. if ( CDmAttributeInfo< T >::AttributeType() == AT_ELEMENT )
  656. {
  657. DmElementHandle_t value = DMELEMENT_HANDLE_INVALID;
  658. for ( int i = 0; i < m_nCount; ++i )
  659. {
  660. m_pOldValue[ i ] = m_pValue[ i ] = *( T* )&value;
  661. }
  662. }
  663. delete[] m_pOldValue;
  664. delete[] m_pValue;
  665. }
  666. virtual void Undo()
  667. {
  668. CDmrArray<T> array( GetAttribute() );
  669. if ( array.IsValid() )
  670. {
  671. for ( int i = 0; i < m_nCount; ++i )
  672. {
  673. array.Set( m_nSlot+i, m_pOldValue[i] );
  674. }
  675. }
  676. }
  677. virtual void Redo()
  678. {
  679. CDmrArray<T> array( GetAttribute() );
  680. if ( array.IsValid() )
  681. {
  682. for ( int i = 0; i < m_nCount; ++i )
  683. {
  684. array.Set( m_nSlot+i, m_pValue[i] );
  685. }
  686. }
  687. }
  688. private:
  689. int m_nSlot;
  690. int m_nCount;
  691. typename CUndoAttributeArrayBase<T>::StorageType_t *m_pOldValue;
  692. typename CUndoAttributeArrayBase<T>::StorageType_t *m_pValue;
  693. };
  694. //-----------------------------------------------------------------------------
  695. //
  696. // Implementation Undo for CDmAttributeTyped
  697. //
  698. //-----------------------------------------------------------------------------
  699. template< class T >
  700. class CUndoAttributeArrayInsertBefore : public CUndoAttributeArrayBase<T>
  701. {
  702. typedef CUndoAttributeArrayBase<T> BaseClass;
  703. public:
  704. CUndoAttributeArrayInsertBefore( CDmAttribute *pAttribute, int slot, int count = 1 ) :
  705. BaseClass( pAttribute, "CUndoAttributeArrayInsertBefore" ),
  706. m_nIndex( slot ), m_nCount( count )
  707. {
  708. Assert( pAttribute->GetOwner() && pAttribute->GetOwner()->GetFileId() != DMFILEID_INVALID );
  709. }
  710. virtual void Undo()
  711. {
  712. CDmrArray<T> array( GetAttribute() );
  713. if ( array.IsValid() )
  714. {
  715. array.RemoveMultiple( m_nIndex, m_nCount );
  716. }
  717. }
  718. virtual void Redo()
  719. {
  720. CDmrArray<T> array( GetAttribute() );
  721. if ( array.IsValid() )
  722. {
  723. T defaultVal;
  724. CDmAttributeInfo<T>::SetDefaultValue( defaultVal );
  725. array.InsertMultipleBefore( m_nIndex, m_nCount );
  726. for( int i = 0; i < m_nCount; ++i )
  727. {
  728. array.Set( m_nIndex + i, defaultVal );
  729. }
  730. }
  731. }
  732. private:
  733. int m_nIndex;
  734. int m_nCount;
  735. };
  736. //-----------------------------------------------------------------------------
  737. //
  738. // Implementation Undo for inserting a copy
  739. //
  740. //-----------------------------------------------------------------------------
  741. template< class T >
  742. class CUndoAttributeArrayInsertCopyBefore : public CUndoAttributeArrayBase<T>
  743. {
  744. typedef CUndoAttributeArrayBase<T> BaseClass;
  745. public:
  746. CUndoAttributeArrayInsertCopyBefore( CDmAttribute *pAttribute, int slot, const T& newValue ) :
  747. BaseClass( pAttribute, "CUndoAttributeArrayInsertCopyBefore" ),
  748. m_nIndex( slot ),
  749. m_newValue( newValue )
  750. {
  751. Assert( pAttribute->GetOwner() && pAttribute->GetOwner()->GetFileId() != DMFILEID_INVALID );
  752. }
  753. virtual void Undo()
  754. {
  755. CDmrArray<T> array( GetAttribute() );
  756. if ( array.IsValid() )
  757. {
  758. array.Remove( m_nIndex );
  759. }
  760. }
  761. virtual void Redo()
  762. {
  763. CDmrArray<T> array( GetAttribute() );
  764. if ( array.IsValid() )
  765. {
  766. array.InsertBefore( m_nIndex, m_newValue );
  767. }
  768. }
  769. private:
  770. int m_nIndex;
  771. typename CUndoAttributeArrayBase<T>::StorageType_t m_newValue;
  772. };
  773. //-----------------------------------------------------------------------------
  774. //
  775. // Implementation Undo for remove
  776. //
  777. //-----------------------------------------------------------------------------
  778. template< class T >
  779. class CUndoAttributeArrayRemoveElement : public CUndoAttributeArrayBase<T>
  780. {
  781. typedef CUndoAttributeArrayBase<T> BaseClass;
  782. public:
  783. CUndoAttributeArrayRemoveElement( CDmAttribute *pAttribute, bool fastRemove, int elem, int count ) :
  784. BaseClass( pAttribute, "CUndoAttributeArrayRemoveElement" ),
  785. m_bFastRemove( fastRemove ), m_nIndex( elem ), m_nCount( count )
  786. {
  787. Assert( pAttribute->GetOwner() && pAttribute->GetOwner()->GetFileId() != DMFILEID_INVALID );
  788. Assert( m_nCount >= 1 );
  789. // If it's fastremove, count must == 1
  790. Assert( !m_bFastRemove || m_nCount == 1 );
  791. CDmrArray< T > array( pAttribute );
  792. Assert( array.IsValid() );
  793. for ( int i = 0 ; i < m_nCount; ++i )
  794. {
  795. m_OldValues.AddToTail( array[ elem + i ] );
  796. }
  797. }
  798. ~CUndoAttributeArrayRemoveElement()
  799. {
  800. // this is a hack necessitated by MSVC's lack of partially specialized member template support
  801. // (ie otherwise I'd just create a CUndoArrayAttributeSetMultipleValueElement< DmElementHandle_t,BaseClass> version with this code)
  802. // anyways, the casting hackiness only happens when the value is actually a DmElementHandle_t, so it's completely safe
  803. if ( CDmAttributeInfo< T >::AttributeType() == AT_ELEMENT )
  804. {
  805. DmElementHandle_t value = DMELEMENT_HANDLE_INVALID;
  806. for ( int i = 0; i < m_nCount; ++i )
  807. {
  808. m_OldValues[ i ] = *( T* )&value;
  809. }
  810. m_OldValues.RemoveAll();
  811. }
  812. }
  813. virtual void Undo()
  814. {
  815. CDmrArray<T> array( GetAttribute() );
  816. if ( array.IsValid() )
  817. {
  818. if ( m_bFastRemove )
  819. {
  820. Assert( m_nCount == 1 );
  821. Assert( m_OldValues.Count() == 1 );
  822. if ( array.Count() > m_nIndex )
  823. {
  824. // Get value at previous index (it was moved down from the "end" before
  825. T m_EndValue = array.Get( m_nIndex );
  826. // Restore previous value
  827. array.Set( m_nIndex, m_OldValues[ 0 ] );
  828. // Put old value back to end of array
  829. array.AddToTail( m_EndValue );
  830. }
  831. else
  832. {
  833. Assert( array.Count() == m_nIndex );
  834. array.AddToTail( m_OldValues[ 0 ] );
  835. }
  836. }
  837. else
  838. {
  839. int insertPos = m_nIndex;
  840. for ( int i = 0; i < m_nCount; ++i )
  841. {
  842. array.InsertBefore( insertPos++, m_OldValues[ i ] );
  843. }
  844. }
  845. }
  846. }
  847. virtual void Redo()
  848. {
  849. CDmrArray<T> array( GetAttribute() );
  850. if ( array.IsValid() )
  851. {
  852. if ( m_bFastRemove )
  853. {
  854. Assert( m_nCount == 1 );
  855. Assert( m_OldValues.Count() == 1 );
  856. array.FastRemove( m_nIndex );
  857. }
  858. else
  859. {
  860. array.RemoveMultiple( m_nIndex, m_nCount );
  861. }
  862. }
  863. }
  864. virtual const char *GetDesc()
  865. {
  866. static char buf[ 128 ];
  867. const char *base = BaseClass::GetDesc();
  868. Q_snprintf( buf, sizeof( buf ), "%s (%s) = remove( pos %i, count %i )", base, GetAttributeName(), m_nIndex, m_nCount );
  869. return buf;
  870. }
  871. private:
  872. bool m_bFastRemove;
  873. int m_nIndex;
  874. int m_nCount;
  875. CUtlVector< typename CUndoAttributeArrayBase<T>::StorageType_t > m_OldValues;
  876. };
  877. template< class T >
  878. class CUndoAttributeArrayCopyAllElement : public CUndoAttributeArrayBase<T>
  879. {
  880. typedef CUndoAttributeArrayBase<T> BaseClass;
  881. public:
  882. CUndoAttributeArrayCopyAllElement( CDmAttribute *pAttribute, const T *pNewValues, int nNewSize, bool purgeOnRemove = false )
  883. : BaseClass( pAttribute, "CUndoAttributeArrayCopyAllElement" ),
  884. m_bPurge( purgeOnRemove )
  885. {
  886. Assert( pAttribute->GetOwner() && pAttribute->GetOwner()->GetFileId() != DMFILEID_INVALID );
  887. CDmrArray< T > att( pAttribute );
  888. Assert( att.IsValid() );
  889. if ( pNewValues != NULL && nNewSize > 0 )
  890. {
  891. m_pNewValues = new typename CUndoAttributeArrayBase<T>::StorageType_t[ nNewSize ];
  892. for ( int i = 0; i < nNewSize; ++i )
  893. {
  894. m_pNewValues[ i ] = pNewValues[ i ];
  895. }
  896. m_nNewSize = nNewSize;
  897. }
  898. else
  899. {
  900. m_pNewValues = NULL;
  901. m_nNewSize = 0;
  902. }
  903. int nOldSize = att.Count();
  904. const T *pOldValues = att.Base();
  905. if ( pOldValues != NULL && nOldSize > 0 )
  906. {
  907. m_pOldValues = new typename CUndoAttributeArrayBase<T>::StorageType_t[ nOldSize ];
  908. for ( int i = 0; i < nOldSize; ++i )
  909. {
  910. m_pOldValues[ i ] = pOldValues[ i ];
  911. }
  912. m_nOldSize = nOldSize;
  913. }
  914. else
  915. {
  916. m_pOldValues = NULL;
  917. m_nOldSize = 0;
  918. }
  919. }
  920. ~CUndoAttributeArrayCopyAllElement()
  921. {
  922. // this is a hack necessitated by MSVC's lack of partially specialized member template support
  923. // (ie otherwise I'd just create a CUndoArrayAttributeSetMultipleValueElement< DmElementHandle_t,BaseClass> version with this code)
  924. // anyways, the casting hackiness only happens when the value is actually a DmElementHandle_t, so it's completely safe
  925. if ( CDmAttributeInfo< T >::AttributeType() == AT_ELEMENT )
  926. {
  927. DmElementHandle_t value = DMELEMENT_HANDLE_INVALID;
  928. for ( int i = 0; i < m_nOldSize; ++i )
  929. {
  930. m_pOldValues[ i ] = *( T* )&value;
  931. }
  932. for ( int i = 0; i < m_nNewSize; ++i )
  933. {
  934. m_pNewValues[ i ] = *( T* )&value;
  935. }
  936. }
  937. delete[] m_pOldValues;
  938. delete[] m_pNewValues;
  939. }
  940. virtual void Undo()
  941. {
  942. CDmrArray<T> array( GetAttribute() );
  943. if ( array.IsValid() )
  944. {
  945. array.RemoveAll();
  946. for ( int i = 0; i < m_nOldSize; ++i )
  947. {
  948. array.AddToTail( m_pOldValues[ i ] );
  949. }
  950. }
  951. }
  952. virtual void Redo()
  953. {
  954. CDmrArray<T> array( GetAttribute() );
  955. if ( array.IsValid() )
  956. {
  957. array.RemoveAll();
  958. for ( int i = 0; i < m_nNewSize; ++i )
  959. {
  960. array.AddToTail( m_pNewValues[ i ] );
  961. }
  962. if ( m_bPurge )
  963. {
  964. Assert( array.Count() == 0 );
  965. array.Purge();
  966. }
  967. }
  968. }
  969. private:
  970. typename CUndoAttributeArrayBase<T>::StorageType_t *m_pOldValues;
  971. int m_nOldSize;
  972. typename CUndoAttributeArrayBase<T>::StorageType_t *m_pNewValues;
  973. int m_nNewSize;
  974. bool m_bPurge;
  975. };
  976. //-----------------------------------------------------------------------------
  977. // CDmArrayAttributeOp implementation.
  978. //-----------------------------------------------------------------------------
  979. //-----------------------------------------------------------------------------
  980. // Callbacks when elements are added + removed
  981. //-----------------------------------------------------------------------------
  982. template< class T >
  983. void CDmArrayAttributeOp<T>::OnAttributeArrayElementAdded( int nFirstElem, int nLastElem, bool bUpdateElementReferences )
  984. {
  985. CDmElement *pOwner = m_pAttribute->GetOwner();
  986. if ( m_pAttribute->IsFlagSet( FATTRIB_HAS_ARRAY_CALLBACK ) && !CDmeElementAccessor::IsBeingUnserialized( pOwner ) )
  987. {
  988. pOwner->OnAttributeArrayElementAdded( m_pAttribute, nFirstElem, nLastElem );
  989. }
  990. }
  991. template< > inline void CDmArrayAttributeOp< DmElementHandle_t >::OnAttributeArrayElementAdded( int nFirstElem, int nLastElem, bool bUpdateElementReferences )
  992. {
  993. CDmElement *pOwner = m_pAttribute->GetOwner();
  994. if ( m_pAttribute->IsFlagSet( FATTRIB_HAS_ARRAY_CALLBACK ) && !CDmeElementAccessor::IsBeingUnserialized( pOwner ) )
  995. {
  996. pOwner->OnAttributeArrayElementAdded( m_pAttribute, nFirstElem, nLastElem );
  997. }
  998. if ( bUpdateElementReferences )
  999. {
  1000. for ( int i = nFirstElem; i <= nLastElem; ++i )
  1001. {
  1002. g_pDataModelImp->OnElementReferenceAdded( Data()[ i ], m_pAttribute );
  1003. }
  1004. }
  1005. }
  1006. template< class T >
  1007. void CDmArrayAttributeOp<T>::OnAttributeArrayElementRemoved( int nFirstElem, int nLastElem )
  1008. {
  1009. CDmElement *pOwner = m_pAttribute->GetOwner();
  1010. if ( m_pAttribute->IsFlagSet( FATTRIB_HAS_ARRAY_CALLBACK ) && !CDmeElementAccessor::IsBeingUnserialized( pOwner ) )
  1011. {
  1012. pOwner->OnAttributeArrayElementRemoved( m_pAttribute, nFirstElem, nLastElem );
  1013. }
  1014. }
  1015. template< > void CDmArrayAttributeOp< DmElementHandle_t >::OnAttributeArrayElementRemoved( int nFirstElem, int nLastElem )
  1016. {
  1017. CDmElement *pOwner = m_pAttribute->GetOwner();
  1018. if ( m_pAttribute->IsFlagSet( FATTRIB_HAS_ARRAY_CALLBACK ) && !CDmeElementAccessor::IsBeingUnserialized( pOwner ) )
  1019. {
  1020. pOwner->OnAttributeArrayElementRemoved( m_pAttribute, nFirstElem, nLastElem );
  1021. }
  1022. for ( int i = nFirstElem; i <= nLastElem; ++i )
  1023. {
  1024. g_pDataModelImp->OnElementReferenceRemoved( Data()[ i ], m_pAttribute );
  1025. }
  1026. }
  1027. //-----------------------------------------------------------------------------
  1028. // Count
  1029. //-----------------------------------------------------------------------------
  1030. template< class T >
  1031. int CDmArrayAttributeOp<T>::Count() const
  1032. {
  1033. return Data().Count();
  1034. }
  1035. //-----------------------------------------------------------------------------
  1036. // Should we insert this element into the list?
  1037. //-----------------------------------------------------------------------------
  1038. template< class T >
  1039. inline bool CDmArrayAttributeOp<T>::ShouldInsertElement( const T& src )
  1040. {
  1041. return true;
  1042. }
  1043. template<> inline bool CDmArrayAttributeOp<DmElementHandle_t>::ShouldInsertElement( const DmElementHandle_t& src )
  1044. {
  1045. // For element, we need to check that the type matches
  1046. if ( !IsA( src, Data().m_ElementType ) )
  1047. return false;
  1048. if ( m_pAttribute->IsFlagSet( FATTRIB_NODUPLICATES ) )
  1049. {
  1050. // See if value exists
  1051. int idx = Data().Find( src );
  1052. if ( idx != Data().InvalidIndex() )
  1053. return false;
  1054. }
  1055. return true;
  1056. }
  1057. template< class T >
  1058. inline bool CDmArrayAttributeOp<T>::ShouldInsert( const T& src )
  1059. {
  1060. if ( !ShouldInsertElement( src ) )
  1061. return false;
  1062. return m_pAttribute->MarkDirty();
  1063. }
  1064. //-----------------------------------------------------------------------------
  1065. // Insert Before
  1066. //-----------------------------------------------------------------------------
  1067. template< class T >
  1068. int CDmArrayAttributeOp<T>::InsertBefore( int elem, const T& src )
  1069. {
  1070. if ( !ShouldInsert( src ) )
  1071. return Data().InvalidIndex();
  1072. if ( g_pDataModel->UndoEnabledForElement( m_pAttribute->GetOwner() ) )
  1073. {
  1074. CUndoAttributeArrayInsertCopyBefore<T> *pUndo = new CUndoAttributeArrayInsertCopyBefore<T>( m_pAttribute, elem, src );
  1075. g_pDataModel->AddUndoElement( pUndo );
  1076. }
  1077. m_pAttribute->PreChanged();
  1078. int nIndex = Data().InsertBefore( elem, src );
  1079. OnAttributeArrayElementAdded( nIndex, nIndex );
  1080. m_pAttribute->OnChanged( true );
  1081. return nIndex;
  1082. }
  1083. template< class T >
  1084. inline int CDmArrayAttributeOp<T>::AddToTail( const T& src )
  1085. {
  1086. return InsertBefore( Data().Count(), src );
  1087. }
  1088. //-----------------------------------------------------------------------------
  1089. // Insert Multiple Before
  1090. //-----------------------------------------------------------------------------
  1091. template< class T >
  1092. int CDmArrayAttributeOp<T>::InsertMultipleBefore( int elem, int num )
  1093. {
  1094. if ( !m_pAttribute->MarkDirty() )
  1095. return Data().InvalidIndex();
  1096. // UNDO HOOK
  1097. if ( g_pDataModel->UndoEnabledForElement( m_pAttribute->GetOwner() ) )
  1098. {
  1099. CUndoAttributeArrayInsertBefore<T> *pUndo = new CUndoAttributeArrayInsertBefore<T>( m_pAttribute, elem, num );
  1100. g_pDataModel->AddUndoElement( pUndo );
  1101. }
  1102. m_pAttribute->PreChanged();
  1103. int index = Data().InsertMultipleBefore( elem, num );
  1104. for ( int i = 0; i < num; ++i )
  1105. {
  1106. CDmAttributeInfo<T>::SetDefaultValue( Data()[ index + i ] );
  1107. }
  1108. OnAttributeArrayElementAdded( index, index + num - 1 );
  1109. m_pAttribute->OnChanged( true );
  1110. return index;
  1111. }
  1112. //-----------------------------------------------------------------------------
  1113. // Removal
  1114. //-----------------------------------------------------------------------------
  1115. template< class T >
  1116. void CDmArrayAttributeOp<T>::FastRemove( int elem )
  1117. {
  1118. if ( !m_pAttribute->MarkDirty() )
  1119. return;
  1120. // UNDO HOOK
  1121. if ( g_pDataModel->UndoEnabledForElement( m_pAttribute->GetOwner() ) )
  1122. {
  1123. CUndoAttributeArrayRemoveElement<T> *pUndo = new CUndoAttributeArrayRemoveElement<T>( m_pAttribute, true, elem, 1 );
  1124. g_pDataModel->AddUndoElement( pUndo );
  1125. }
  1126. m_pAttribute->PreChanged();
  1127. OnAttributeArrayElementRemoved( elem, elem );
  1128. Data().FastRemove( elem );
  1129. m_pAttribute->OnChanged( true );
  1130. }
  1131. template< class T >
  1132. void CDmArrayAttributeOp<T>::Remove( int elem )
  1133. {
  1134. if ( !Data().IsValidIndex( elem ) )
  1135. return;
  1136. if ( !m_pAttribute->MarkDirty() )
  1137. return;
  1138. // UNDO HOOK
  1139. if ( g_pDataModel->UndoEnabledForElement( m_pAttribute->GetOwner() ) )
  1140. {
  1141. CUndoAttributeArrayRemoveElement<T> *pUndo = new CUndoAttributeArrayRemoveElement<T>( m_pAttribute, false, elem, 1 );
  1142. g_pDataModel->AddUndoElement( pUndo );
  1143. }
  1144. m_pAttribute->PreChanged();
  1145. OnAttributeArrayElementRemoved( elem, elem );
  1146. Data().Remove( elem );
  1147. m_pAttribute->OnChanged( true );
  1148. }
  1149. template< class T >
  1150. void CDmArrayAttributeOp<T>::RemoveAll()
  1151. {
  1152. if ( !m_pAttribute->MarkDirty() )
  1153. return;
  1154. // UNDO HOOK
  1155. if ( g_pDataModel->UndoEnabledForElement( m_pAttribute->GetOwner() ) )
  1156. {
  1157. CUndoAttributeArrayCopyAllElement<T> *pUndo = new CUndoAttributeArrayCopyAllElement<T>( m_pAttribute, NULL, 0 );
  1158. g_pDataModel->AddUndoElement( pUndo );
  1159. }
  1160. m_pAttribute->PreChanged();
  1161. OnAttributeArrayElementRemoved( 0, Data().Count() - 1 );
  1162. Data().RemoveAll();
  1163. m_pAttribute->OnChanged( true );
  1164. }
  1165. template< class T >
  1166. void CDmArrayAttributeOp<T>::RemoveMultiple( int elem, int num )
  1167. {
  1168. if ( !m_pAttribute->MarkDirty() )
  1169. return;
  1170. // UNDO HOOK
  1171. if ( g_pDataModel->UndoEnabledForElement( m_pAttribute->GetOwner() ) )
  1172. {
  1173. CUndoAttributeArrayRemoveElement<T> *pUndo = new CUndoAttributeArrayRemoveElement<T>( m_pAttribute, false, elem, num );
  1174. g_pDataModel->AddUndoElement( pUndo );
  1175. }
  1176. m_pAttribute->PreChanged();
  1177. OnAttributeArrayElementRemoved( elem, elem + num - 1 );
  1178. Data().RemoveMultiple( elem, num );
  1179. m_pAttribute->OnChanged( true );
  1180. }
  1181. // Memory deallocation
  1182. template< class T >
  1183. void CDmArrayAttributeOp<T>::Purge()
  1184. {
  1185. if ( !m_pAttribute->MarkDirty() )
  1186. return;
  1187. // UNDO HOOK
  1188. if ( g_pDataModel->UndoEnabledForElement( m_pAttribute->GetOwner() ) )
  1189. {
  1190. CUndoAttributeArrayCopyAllElement<T> *pUndo = new CUndoAttributeArrayCopyAllElement<T>( m_pAttribute, NULL, true );
  1191. g_pDataModel->AddUndoElement( pUndo );
  1192. }
  1193. m_pAttribute->PreChanged();
  1194. OnAttributeArrayElementRemoved( 0, Data().Count() - 1 );
  1195. Data().Purge();
  1196. m_pAttribute->OnChanged( true );
  1197. }
  1198. //-----------------------------------------------------------------------------
  1199. // Copy Array
  1200. //-----------------------------------------------------------------------------
  1201. template< class T >
  1202. void CDmArrayAttributeOp<T>::PerformCopyArray( const T *pArray, int nCount )
  1203. {
  1204. Data().CopyArray( pArray, nCount );
  1205. }
  1206. template<> void CDmArrayAttributeOp<DmElementHandle_t>::PerformCopyArray( const DmElementHandle_t *pArray, int nCount )
  1207. {
  1208. Data().RemoveAll();
  1209. for ( int i = 0; i < nCount; ++i )
  1210. {
  1211. if ( ShouldInsertElement( pArray[ i ] ) )
  1212. {
  1213. Data().AddToTail( pArray[ i ] );
  1214. }
  1215. }
  1216. }
  1217. template< class T >
  1218. void CDmArrayAttributeOp<T>::CopyArray( const T *pArray, int nCount )
  1219. {
  1220. if ( Data().Base() == pArray )
  1221. {
  1222. int nCurrentCount = Data().Count();
  1223. if ( nCurrentCount > nCount )
  1224. {
  1225. RemoveMultiple( nCount, nCurrentCount - nCount );
  1226. }
  1227. else if ( nCurrentCount < nCount )
  1228. {
  1229. InsertMultipleBefore( nCurrentCount, nCount - nCurrentCount );
  1230. }
  1231. return;
  1232. }
  1233. if ( !m_pAttribute->MarkDirty() )
  1234. return;
  1235. // UNDO HOOK
  1236. if ( g_pDataModel->UndoEnabledForElement( m_pAttribute->GetOwner() ) )
  1237. {
  1238. CUndoAttributeArrayCopyAllElement<T> *pUndo = new CUndoAttributeArrayCopyAllElement<T>( m_pAttribute, pArray, nCount );
  1239. g_pDataModel->AddUndoElement( pUndo );
  1240. }
  1241. m_pAttribute->PreChanged();
  1242. OnAttributeArrayElementRemoved( 0, Data().Count() - 1 );
  1243. PerformCopyArray( pArray, nCount );
  1244. OnAttributeArrayElementAdded( 0, Data().Count() - 1 );
  1245. m_pAttribute->OnChanged( true );
  1246. }
  1247. //-----------------------------------------------------------------------------
  1248. // Swap Array
  1249. //-----------------------------------------------------------------------------
  1250. template< class T >
  1251. void CDmArrayAttributeOp<T>::SwapArray( CUtlVector< T >& src )
  1252. {
  1253. // this is basically just a faster version of CopyArray
  1254. // the end result (for purposes of undo) are the same
  1255. // but there's no copy - just a pointer/etc swap
  1256. if ( !m_pAttribute->MarkDirty() )
  1257. return;
  1258. // UNDO HOOK
  1259. if ( g_pDataModel->UndoEnabledForElement( m_pAttribute->GetOwner() ) )
  1260. {
  1261. CUndoAttributeArrayCopyAllElement<T> *pUndo = new CUndoAttributeArrayCopyAllElement<T>( m_pAttribute, src.Base(), src.Count() );
  1262. g_pDataModel->AddUndoElement( pUndo );
  1263. }
  1264. m_pAttribute->PreChanged();
  1265. OnAttributeArrayElementRemoved( 0, Data().Count() - 1 );
  1266. Data().Swap( src );
  1267. OnAttributeArrayElementAdded( 0, Data().Count() - 1 );
  1268. m_pAttribute->OnChanged( true );
  1269. }
  1270. template< > void CDmArrayAttributeOp<DmElementHandle_t>::SwapArray( CUtlVector< DmElementHandle_t >& src )
  1271. {
  1272. // This feature doesn't work for elements..
  1273. // Can't do it owing to typesafety reasons as well as supporting the NODUPLICATES feature.
  1274. Assert( 0 );
  1275. }
  1276. //-----------------------------------------------------------------------------
  1277. // Set value
  1278. //-----------------------------------------------------------------------------
  1279. template< class T >
  1280. void CDmArrayAttributeOp<T>::Set( int i, const T& value )
  1281. {
  1282. if ( i < 0 || i >= Data().Count() )
  1283. {
  1284. Assert( !"CDmAttributeArray<T>::Set out of range value!\n" );
  1285. return;
  1286. }
  1287. // Don't bother doing anything if the attribute is equal
  1288. if ( IsAttributeEqual( Data()[i], value ) )
  1289. return;
  1290. if ( !ShouldInsert( value ) )
  1291. return;
  1292. if ( g_pDataModel->UndoEnabledForElement( m_pAttribute->GetOwner() ) )
  1293. {
  1294. CUndoArrayAttributeSetValueElement<T> *pUndo = new CUndoArrayAttributeSetValueElement<T>( m_pAttribute, i, value );
  1295. g_pDataModel->AddUndoElement( pUndo );
  1296. }
  1297. m_pAttribute->PreChanged();
  1298. OnAttributeArrayElementRemoved( i, i );
  1299. Data()[i] = value;
  1300. OnAttributeArrayElementAdded( i, i );
  1301. m_pAttribute->OnChanged( false );
  1302. }
  1303. template< class T >
  1304. void CDmArrayAttributeOp<T>::Set( CDmAttribute *pAttribute, int i, DmAttributeType_t valueType, const void *pValue )
  1305. {
  1306. if ( valueType == ArrayTypeToValueType( pAttribute->GetType() ) )
  1307. {
  1308. // This version is in IDmAttributeOp
  1309. CDmArrayAttributeOp< T > array( pAttribute );
  1310. array.Set( i, *(const T*)pValue );
  1311. }
  1312. }
  1313. //-----------------------------------------------------------------------------
  1314. // Set multiple values
  1315. //-----------------------------------------------------------------------------
  1316. template< class T >
  1317. void CDmArrayAttributeOp<T>::SetMultiple( int i, int nCount, const T* pValue )
  1318. {
  1319. if ( i < 0 || ( i+nCount ) > Data().Count() )
  1320. {
  1321. AssertMsg( 0, "CDmAttributeArray<T>::SetMultiple out of range value!\n" );
  1322. return;
  1323. }
  1324. // Test for equality
  1325. bool bEqual = true;
  1326. for ( int j = 0; j < nCount; ++j )
  1327. {
  1328. if ( !IsAttributeEqual( Data()[i+j], pValue[j] ) )
  1329. {
  1330. bEqual = false;
  1331. break;
  1332. }
  1333. }
  1334. if ( bEqual )
  1335. return;
  1336. if ( !m_pAttribute->MarkDirty() )
  1337. return;
  1338. if ( g_pDataModel->UndoEnabledForElement( m_pAttribute->GetOwner() ) )
  1339. {
  1340. CUndoArrayAttributeSetMultipleValueElement<T> *pUndo = new CUndoArrayAttributeSetMultipleValueElement<T>( m_pAttribute, i, nCount, pValue );
  1341. g_pDataModel->AddUndoElement( pUndo );
  1342. }
  1343. m_pAttribute->PreChanged();
  1344. OnAttributeArrayElementRemoved( i, i+nCount-1 );
  1345. for ( int j = 0; j < nCount; ++j )
  1346. {
  1347. if ( ShouldInsertElement( pValue[j] ) )
  1348. {
  1349. Data()[i+j] = pValue[j];
  1350. }
  1351. }
  1352. OnAttributeArrayElementAdded( i, i+nCount-1 );
  1353. m_pAttribute->OnChanged( false );
  1354. }
  1355. template< class T >
  1356. void CDmArrayAttributeOp<T>::SetMultiple( CDmAttribute *pAttribute, int i, int nCount, DmAttributeType_t valueType, const void *pValue )
  1357. {
  1358. if ( valueType == ArrayTypeToValueType( pAttribute->GetType() ) )
  1359. {
  1360. // This version is in IDmAttributeOp
  1361. CDmArrayAttributeOp< T > array( pAttribute );
  1362. array.SetMultiple( i, nCount, (const T*)pValue );
  1363. }
  1364. }
  1365. //-----------------------------------------------------------------------------
  1366. // Version of SetValue that's in IDmAttributeOp
  1367. //-----------------------------------------------------------------------------
  1368. template< class T >
  1369. void CDmArrayAttributeOp<T>::SetValue( CDmAttribute *pAttribute, DmAttributeType_t valueType, const void *pValue )
  1370. {
  1371. Assert( pAttribute->GetType() == valueType );
  1372. if ( pAttribute->GetType() == valueType )
  1373. {
  1374. CDmArrayAttributeOp<T> accessor( pAttribute );
  1375. const CUtlVector<T>* pArray = reinterpret_cast< const CUtlVector<T>* >( pValue );
  1376. accessor.CopyArray( pArray->Base(), pArray->Count() );
  1377. }
  1378. }
  1379. //-----------------------------------------------------------------------------
  1380. // Swap
  1381. //-----------------------------------------------------------------------------
  1382. template< class T >
  1383. void CDmArrayAttributeOp<T>::Swap( int i, int j )
  1384. {
  1385. if ( i == j )
  1386. return;
  1387. // TODO - define Swap<T> for all attribute types to make swapping strings
  1388. // and voids fast (via pointer swaps, rather than 3 copies!)
  1389. T vk = Data()[ i ];
  1390. if ( IsAttributeEqual( vk, Data()[j] ) )
  1391. return;
  1392. if ( !m_pAttribute->MarkDirty() )
  1393. return;
  1394. if ( g_pDataModel->UndoEnabledForElement( m_pAttribute->GetOwner() ) )
  1395. {
  1396. CUndoArrayAttributeSetValueElement<T> *pUndo = new CUndoArrayAttributeSetValueElement<T>( m_pAttribute, i, Data()[ j ] );
  1397. g_pDataModel->AddUndoElement( pUndo );
  1398. pUndo = new CUndoArrayAttributeSetValueElement<T>( m_pAttribute, j, vk );
  1399. g_pDataModel->AddUndoElement( pUndo );
  1400. }
  1401. m_pAttribute->PreChanged();
  1402. OnAttributeArrayElementRemoved( i, i );
  1403. Data()[i] = Data()[j];
  1404. OnAttributeArrayElementAdded( i, i );
  1405. OnAttributeArrayElementRemoved( j, j );
  1406. Data()[j] = vk;
  1407. OnAttributeArrayElementAdded( j, j );
  1408. m_pAttribute->OnChanged( false );
  1409. }
  1410. //-----------------------------------------------------------------------------
  1411. // Methods related to serialization
  1412. //-----------------------------------------------------------------------------
  1413. template< class T >
  1414. bool CDmArrayAttributeOp<T>::Unserialize( CDmAttribute *pAttribute, CUtlBuffer &buf )
  1415. {
  1416. if ( !pAttribute->MarkDirty() )
  1417. return false;
  1418. MEM_ALLOC_CREDIT_CLASS();
  1419. CUtlVector< T > tempVal;
  1420. bool bRet = ::Unserialize( buf, tempVal );
  1421. // Don't need undo hook since this goes through Swap route
  1422. CDmArrayAttributeOp<T> accessor( pAttribute );
  1423. accessor.SwapArray( tempVal );
  1424. return bRet;
  1425. }
  1426. template<> bool CDmArrayAttributeOp<DmElementHandle_t>::Unserialize( CDmAttribute *pAttribute, CUtlBuffer &buf )
  1427. {
  1428. // Need to specialize this because element handles can't use SwapArray
  1429. // because it's incapable of doing type safety checks or looking for FATTRIB_NODUPLICATES
  1430. if ( !CDmAttributeAccessor::MarkDirty( pAttribute ) )
  1431. return false;
  1432. MEM_ALLOC_CREDIT_CLASS();
  1433. CUtlVector< DmElementHandle_t > tempVal;
  1434. bool bRet = ::Unserialize( buf, tempVal );
  1435. // Don't need undo hook since this goes through copy route
  1436. CDmArrayAttributeOp<DmElementHandle_t> accessor( pAttribute );
  1437. accessor.CopyArray( tempVal.Base(), tempVal.Count() );
  1438. return bRet;
  1439. }
  1440. // Serialization of a single element
  1441. template< class T >
  1442. bool CDmArrayAttributeOp<T>::SerializeElement( const CDmAttribute *pAttribute, int nElement, CUtlBuffer &buf )
  1443. {
  1444. CDmrArrayConst<T> array( pAttribute );
  1445. return ::Serialize( buf, array[ nElement ] );
  1446. }
  1447. template< class T >
  1448. bool CDmArrayAttributeOp<T>::UnserializeElement( CDmAttribute *pAttribute, CUtlBuffer &buf )
  1449. {
  1450. if ( !CDmAttributeAccessor::MarkDirty( pAttribute ) )
  1451. return false;
  1452. MEM_ALLOC_CREDIT_CLASS();
  1453. T temp;
  1454. bool bReadElement = ::Unserialize( buf, temp );
  1455. if ( bReadElement )
  1456. {
  1457. pAttribute->PreChanged();
  1458. CDmArrayAttributeOp<T> accessor( pAttribute );
  1459. accessor.AddToTail( temp );
  1460. pAttribute->OnChanged( true );
  1461. }
  1462. return bReadElement;
  1463. }
  1464. template< class T >
  1465. bool CDmArrayAttributeOp<T>::UnserializeElement( CDmAttribute *pAttribute, int nElement, CUtlBuffer &buf )
  1466. {
  1467. if ( !CDmAttributeAccessor::MarkDirty( pAttribute ) )
  1468. return false;
  1469. CDmrArray<T> array( pAttribute );
  1470. if ( array.Count() <= nElement )
  1471. return false;
  1472. MEM_ALLOC_CREDIT_CLASS();
  1473. pAttribute->PreChanged();
  1474. bool bReadElement = ::Unserialize( buf, *const_cast<T*>( &array[nElement] ) );
  1475. if ( bReadElement )
  1476. {
  1477. pAttribute->OnChanged();
  1478. }
  1479. return bReadElement;
  1480. }
  1481. template< class T >
  1482. void CDmArrayAttributeOp<T>::OnUnserializationFinished( CDmAttribute *pAttribute )
  1483. {
  1484. CDmArrayAttributeOp<T> ref( pAttribute );
  1485. int nCount = ref.Count();
  1486. if ( nCount > 0 )
  1487. {
  1488. ref.OnAttributeArrayElementAdded( 0, nCount - 1, false );
  1489. }
  1490. CDmAttributeAccessor::OnChanged( pAttribute, true, true );
  1491. }
  1492. //-----------------------------------------------------------------------------
  1493. //
  1494. // CDmAttribute begins here
  1495. //
  1496. //-----------------------------------------------------------------------------
  1497. //-----------------------------------------------------------------------------
  1498. // Memory pool used for CDmAttribute
  1499. //-----------------------------------------------------------------------------
  1500. CUtlMemoryPool g_AttrAlloc( sizeof( CDmAttribute ), 32, CUtlMemoryPool::GROW_SLOW, "CDmAttribute pool" );
  1501. //-----------------------------------------------------------------------------
  1502. // Class factory
  1503. //-----------------------------------------------------------------------------
  1504. // turn memdbg off temporarily so we can get at placement new
  1505. #include "tier0/memdbgoff.h"
  1506. CDmAttribute *CDmAttribute::CreateAttribute( CDmElement *pOwner, DmAttributeType_t type, const char *pAttributeName )
  1507. {
  1508. switch( type )
  1509. {
  1510. case AT_UNKNOWN:
  1511. Assert( 0 );
  1512. return NULL;
  1513. default:
  1514. {
  1515. void *pMem = g_AttrAlloc.Alloc( sizeof( CDmAttribute ) );
  1516. return ::new( pMem ) CDmAttribute( pOwner, type, pAttributeName );
  1517. }
  1518. }
  1519. }
  1520. CDmAttribute *CDmAttribute::CreateExternalAttribute( CDmElement *pOwner, DmAttributeType_t type, const char *pAttributeName, void *pExternalMemory )
  1521. {
  1522. switch( type )
  1523. {
  1524. case AT_UNKNOWN:
  1525. Assert( 0 );
  1526. return NULL;
  1527. default:
  1528. {
  1529. void *pMem = g_AttrAlloc.Alloc( sizeof( CDmAttribute ) );
  1530. return ::new( pMem ) CDmAttribute( pOwner, type, pAttributeName, pExternalMemory );
  1531. }
  1532. }
  1533. }
  1534. void CDmAttribute::DestroyAttribute( CDmAttribute *pAttribute )
  1535. {
  1536. if ( !pAttribute )
  1537. return;
  1538. switch( pAttribute->GetType() )
  1539. {
  1540. case AT_UNKNOWN:
  1541. break;
  1542. default:
  1543. pAttribute->~CDmAttribute();
  1544. #ifdef _DEBUG
  1545. memset( pAttribute, 0xDD, sizeof(CDmAttribute) );
  1546. #endif
  1547. g_AttrAlloc.Free( pAttribute );
  1548. break;
  1549. }
  1550. }
  1551. // turn memdbg back on after using placement new
  1552. #include "tier0/memdbgon.h"
  1553. //-----------------------------------------------------------------------------
  1554. // Constructor, destructor
  1555. //-----------------------------------------------------------------------------
  1556. CDmAttribute::CDmAttribute( CDmElement *pOwner, DmAttributeType_t type, const char *pAttributeName ) :
  1557. m_pData( NULL )
  1558. {
  1559. Init( pOwner, type, pAttributeName );
  1560. CreateAttributeData();
  1561. }
  1562. CDmAttribute::CDmAttribute( CDmElement *pOwner, DmAttributeType_t type, const char *pAttributeName, void *pMemory ) :
  1563. m_pData( pMemory )
  1564. {
  1565. Init( pOwner, type, pAttributeName );
  1566. s_pAttrInfo[ GetType() ]->SetDefaultValue( m_pData );
  1567. AddFlag( FATTRIB_EXTERNAL );
  1568. }
  1569. void CDmAttribute::Init( CDmElement *pOwner, DmAttributeType_t type, const char *pAttributeName )
  1570. {
  1571. // FIXME - this is just here temporarily to catch old code trying to create type and id attributes
  1572. // this shouldn't actually be illegal, since users should be able to create attributes of whatever name they want
  1573. Assert( V_strcmp( pAttributeName, "type" ) && V_strcmp( pAttributeName, "id" ) );
  1574. m_pOwner = pOwner;
  1575. m_Name = g_pDataModel->GetSymbol( pAttributeName );
  1576. m_nFlags = type;
  1577. m_Handle = DMATTRIBUTE_HANDLE_INVALID;
  1578. m_pNext = NULL;
  1579. m_hMailingList = DMMAILINGLIST_INVALID;
  1580. switch ( type )
  1581. {
  1582. case AT_ELEMENT:
  1583. case AT_ELEMENT_ARRAY:
  1584. case AT_OBJECTID:
  1585. case AT_OBJECTID_ARRAY:
  1586. m_nFlags |= FATTRIB_TOPOLOGICAL;
  1587. break;
  1588. }
  1589. }
  1590. CDmAttribute::~CDmAttribute()
  1591. {
  1592. switch( GetType() )
  1593. {
  1594. case AT_ELEMENT:
  1595. g_pDataModelImp->OnElementReferenceRemoved( GetValue<DmElementHandle_t>(), this );
  1596. break;
  1597. case AT_ELEMENT_ARRAY:
  1598. {
  1599. CDmrElementArray<> array( this );
  1600. int nElements = array.Count();
  1601. for ( int i = 0; i < nElements; ++i )
  1602. {
  1603. g_pDataModelImp->OnElementReferenceRemoved( array.GetHandle( i ), this );
  1604. }
  1605. }
  1606. break;
  1607. }
  1608. CleanupMailingList();
  1609. InvalidateHandle();
  1610. DeleteAttributeData();
  1611. }
  1612. //-----------------------------------------------------------------------------
  1613. // Creates the attribute data
  1614. //-----------------------------------------------------------------------------
  1615. void CDmAttribute::CreateAttributeData()
  1616. {
  1617. // Free the attribute memory
  1618. if ( !IsFlagSet( FATTRIB_EXTERNAL ) )
  1619. {
  1620. Assert( !m_pData );
  1621. m_pData = s_pAttrInfo[ GetType() ]->CreateAttributeData( );
  1622. }
  1623. }
  1624. //-----------------------------------------------------------------------------
  1625. // Deletes the attribute data
  1626. //-----------------------------------------------------------------------------
  1627. void CDmAttribute::DeleteAttributeData()
  1628. {
  1629. // Free the attribute memory
  1630. if ( m_pData && !IsFlagSet( FATTRIB_EXTERNAL ) )
  1631. {
  1632. s_pAttrInfo[ GetType() ]->DestroyAttributeData( m_pData );
  1633. m_pData = NULL;
  1634. }
  1635. }
  1636. //-----------------------------------------------------------------------------
  1637. // Used only in attribute element arrays
  1638. //-----------------------------------------------------------------------------
  1639. void CDmAttribute::SetElementTypeSymbol( UtlSymId_t typeSymbol )
  1640. {
  1641. switch ( GetType() )
  1642. {
  1643. case AT_ELEMENT:
  1644. {
  1645. DmElementAttribute_t *pData = GetData< DmElementHandle_t >();
  1646. Assert( pData->m_Handle == DMELEMENT_HANDLE_INVALID || ::IsA( pData->m_Handle, typeSymbol ) );
  1647. pData->m_ElementType = typeSymbol;
  1648. }
  1649. break;
  1650. case AT_ELEMENT_ARRAY:
  1651. {
  1652. #ifdef _DEBUG
  1653. CDmrElementArray<> array( this );
  1654. if ( array.GetElementType() != UTL_INVAL_SYMBOL )
  1655. {
  1656. int i;
  1657. int c = array.Count();
  1658. for ( i = 0; i < c; ++i )
  1659. {
  1660. Assert( array.GetHandle( i ) == DMELEMENT_HANDLE_INVALID || ::IsA( array.GetHandle( i ), typeSymbol ) );
  1661. }
  1662. }
  1663. #endif
  1664. DmElementArray_t *pData = GetArrayData< DmElementHandle_t >();
  1665. pData->m_ElementType = typeSymbol;
  1666. }
  1667. break;
  1668. default:
  1669. Assert(0);
  1670. break;
  1671. }
  1672. }
  1673. UtlSymId_t CDmAttribute::GetElementTypeSymbol() const
  1674. {
  1675. switch ( GetType() )
  1676. {
  1677. case AT_ELEMENT:
  1678. return GetData< DmElementHandle_t >()->m_ElementType;
  1679. case AT_ELEMENT_ARRAY:
  1680. return GetArrayData< DmElementHandle_t >()->m_ElementType;
  1681. default:
  1682. Assert(0);
  1683. break;
  1684. }
  1685. return UTL_INVAL_SYMBOL;
  1686. }
  1687. //-----------------------------------------------------------------------------
  1688. // Is modification allowed in this phase?
  1689. //-----------------------------------------------------------------------------
  1690. bool CDmAttribute::ModificationAllowed() const
  1691. {
  1692. if ( IsFlagSet( FATTRIB_READONLY ) )
  1693. return false;
  1694. DmPhase_t phase = g_pDmElementFramework->GetPhase();
  1695. if ( phase == PH_EDIT )
  1696. return true;
  1697. if ( ( phase == PH_OPERATE ) && !IsFlagSet( FATTRIB_TOPOLOGICAL ) )
  1698. return true;
  1699. return false;
  1700. }
  1701. bool CDmAttribute::MarkDirty()
  1702. {
  1703. if ( !ModificationAllowed() )
  1704. {
  1705. Assert( 0 );
  1706. return false;
  1707. }
  1708. AddFlag( FATTRIB_DIRTY | FATTRIB_OPERATOR_DIRTY );
  1709. CDmeElementAccessor::MarkDirty( m_pOwner );
  1710. return true;
  1711. }
  1712. //-----------------------------------------------------------------------------
  1713. // Called before and after the attribute has changed
  1714. //-----------------------------------------------------------------------------
  1715. void CDmAttribute::PreChanged()
  1716. {
  1717. if ( IsFlagSet( FATTRIB_HAS_PRE_CALLBACK ) && !CDmeElementAccessor::IsBeingUnserialized( m_pOwner ) )
  1718. {
  1719. m_pOwner->PreAttributeChanged( this );
  1720. }
  1721. // FIXME: What about mailing lists?
  1722. }
  1723. void CDmAttribute::OnChanged( bool bArrayCountChanged, bool bIsTopological )
  1724. {
  1725. if ( IsFlagSet( FATTRIB_HAS_CALLBACK ) && !CDmeElementAccessor::IsBeingUnserialized( m_pOwner ) )
  1726. {
  1727. m_pOwner->OnAttributeChanged( this );
  1728. }
  1729. if ( ( m_hMailingList != DMMAILINGLIST_INVALID ) && !CDmeElementAccessor::IsBeingUnserialized( m_pOwner ) )
  1730. {
  1731. if ( !g_pDataModelImp->PostAttributeChanged( m_hMailingList, this ) )
  1732. {
  1733. CleanupMailingList();
  1734. }
  1735. }
  1736. if ( bIsTopological || IsTopological( GetType() ) )
  1737. {
  1738. g_pDataModelImp->NotifyState( NOTIFY_CHANGE_TOPOLOGICAL );
  1739. }
  1740. else
  1741. {
  1742. g_pDataModelImp->NotifyState( bArrayCountChanged ? NOTIFY_CHANGE_ATTRIBUTE_ARRAY_SIZE : NOTIFY_CHANGE_ATTRIBUTE_VALUE );
  1743. }
  1744. }
  1745. //-----------------------------------------------------------------------------
  1746. // Type conversion related methods
  1747. //-----------------------------------------------------------------------------
  1748. template< class T > bool CDmAttribute::IsTypeConvertable() const
  1749. {
  1750. return ( CDmAttributeInfo< T >::ATTRIBUTE_TYPE == GetType() );
  1751. }
  1752. template<> bool CDmAttribute::IsTypeConvertable<bool>() const
  1753. {
  1754. DmAttributeType_t type = GetType();
  1755. return ( type == AT_BOOL || type == AT_INT || type == AT_FLOAT );
  1756. }
  1757. template<> bool CDmAttribute::IsTypeConvertable<int>() const
  1758. {
  1759. DmAttributeType_t type = GetType();
  1760. return ( type == AT_INT || type == AT_BOOL || type == AT_FLOAT );
  1761. }
  1762. template<> bool CDmAttribute::IsTypeConvertable<float>() const
  1763. {
  1764. DmAttributeType_t type = GetType();
  1765. return ( type == AT_FLOAT || type == AT_INT || type == AT_BOOL );
  1766. }
  1767. template<> bool CDmAttribute::IsTypeConvertable<QAngle>() const
  1768. {
  1769. DmAttributeType_t type = GetType();
  1770. return ( type == AT_QANGLE || type == AT_QUATERNION );
  1771. }
  1772. template<> bool CDmAttribute::IsTypeConvertable<Quaternion>() const
  1773. {
  1774. DmAttributeType_t type = GetType();
  1775. return ( type == AT_QUATERNION || type == AT_QANGLE);
  1776. }
  1777. template< class T > void CDmAttribute::CopyData( const T& value )
  1778. {
  1779. *reinterpret_cast< T* >( m_pData ) = value;
  1780. }
  1781. template< class T > void CDmAttribute::CopyDataOut( T& value ) const
  1782. {
  1783. value = *reinterpret_cast< const T* >( m_pData );
  1784. }
  1785. template<> void CDmAttribute::CopyData( const bool& value )
  1786. {
  1787. switch( GetType() )
  1788. {
  1789. case AT_BOOL:
  1790. *reinterpret_cast< bool* >( m_pData ) = value;
  1791. break;
  1792. case AT_INT:
  1793. *reinterpret_cast< int* >( m_pData ) = value ? 1 : 0;
  1794. break;
  1795. case AT_FLOAT:
  1796. *reinterpret_cast< float* >( m_pData ) = value ? 1.0f : 0.0f;
  1797. break;
  1798. }
  1799. }
  1800. template<> void CDmAttribute::CopyDataOut( bool& value ) const
  1801. {
  1802. switch( GetType() )
  1803. {
  1804. case AT_BOOL:
  1805. value = *reinterpret_cast< bool* >( m_pData );
  1806. break;
  1807. case AT_INT:
  1808. value = *reinterpret_cast< int* >( m_pData ) != 0;
  1809. break;
  1810. case AT_FLOAT:
  1811. value = *reinterpret_cast< float* >( m_pData ) != 0.0f;
  1812. break;
  1813. }
  1814. }
  1815. template<> void CDmAttribute::CopyData( const int& value )
  1816. {
  1817. switch( GetType() )
  1818. {
  1819. case AT_BOOL:
  1820. *reinterpret_cast< bool* >( m_pData ) = value != 0;
  1821. break;
  1822. case AT_INT:
  1823. *reinterpret_cast< int* >( m_pData ) = value;
  1824. break;
  1825. case AT_FLOAT:
  1826. *reinterpret_cast< float* >( m_pData ) = value;
  1827. break;
  1828. }
  1829. }
  1830. template<> void CDmAttribute::CopyDataOut( int& value ) const
  1831. {
  1832. switch( GetType() )
  1833. {
  1834. case AT_BOOL:
  1835. value = *reinterpret_cast< bool* >( m_pData ) ? 1 : 0;
  1836. break;
  1837. case AT_INT:
  1838. value = *reinterpret_cast< int* >( m_pData );
  1839. break;
  1840. case AT_FLOAT:
  1841. value = *reinterpret_cast< float* >( m_pData );
  1842. break;
  1843. }
  1844. }
  1845. template<> void CDmAttribute::CopyData( const float& value )
  1846. {
  1847. switch( GetType() )
  1848. {
  1849. case AT_BOOL:
  1850. *reinterpret_cast< bool* >( m_pData ) = value != 0.0f;
  1851. break;
  1852. case AT_INT:
  1853. *reinterpret_cast< int* >( m_pData ) = value;
  1854. break;
  1855. case AT_FLOAT:
  1856. *reinterpret_cast< float* >( m_pData ) = value;
  1857. break;
  1858. }
  1859. }
  1860. template<> void CDmAttribute::CopyDataOut( float& value ) const
  1861. {
  1862. switch( GetType() )
  1863. {
  1864. case AT_BOOL:
  1865. value = *reinterpret_cast< bool* >( m_pData ) ? 1.0f : 0.0f;
  1866. break;
  1867. case AT_INT:
  1868. value = *reinterpret_cast< int* >( m_pData );
  1869. break;
  1870. case AT_FLOAT:
  1871. value = *reinterpret_cast< float* >( m_pData );
  1872. break;
  1873. }
  1874. }
  1875. template<> void CDmAttribute::CopyData( const QAngle& value )
  1876. {
  1877. switch( GetType() )
  1878. {
  1879. case AT_QANGLE:
  1880. *reinterpret_cast< QAngle* >( m_pData ) = value;
  1881. break;
  1882. case AT_QUATERNION:
  1883. {
  1884. Quaternion qValue;
  1885. AngleQuaternion( value, qValue );
  1886. *reinterpret_cast< Quaternion* >( m_pData ) = qValue;
  1887. }
  1888. break;
  1889. }
  1890. }
  1891. template<> void CDmAttribute::CopyDataOut( QAngle& value ) const
  1892. {
  1893. switch( GetType() )
  1894. {
  1895. case AT_QANGLE:
  1896. value = *reinterpret_cast< QAngle* >( m_pData );
  1897. break;
  1898. case AT_QUATERNION:
  1899. QuaternionAngles( *reinterpret_cast< Quaternion* >( m_pData ), value );
  1900. break;
  1901. }
  1902. }
  1903. template<> void CDmAttribute::CopyData( const Quaternion& value )
  1904. {
  1905. switch( GetType() )
  1906. {
  1907. case AT_QANGLE:
  1908. {
  1909. QAngle aValue;
  1910. QuaternionAngles( value, aValue );
  1911. *reinterpret_cast< QAngle* >( m_pData ) = aValue;
  1912. }
  1913. break;
  1914. case AT_QUATERNION:
  1915. *reinterpret_cast< Quaternion* >( m_pData ) = value;
  1916. break;
  1917. }
  1918. }
  1919. template<> void CDmAttribute::CopyDataOut( Quaternion& value ) const
  1920. {
  1921. switch( GetType() )
  1922. {
  1923. case AT_QANGLE:
  1924. AngleQuaternion( *reinterpret_cast< QAngle* >( m_pData ), value );
  1925. break;
  1926. case AT_QUATERNION:
  1927. value = *reinterpret_cast< Quaternion* >( m_pData );
  1928. break;
  1929. }
  1930. }
  1931. template<> void CDmAttribute::CopyData( const DmElementHandle_t& value )
  1932. {
  1933. g_pDataModelImp->OnElementReferenceRemoved( GetValue<DmElementHandle_t>(), this );
  1934. *reinterpret_cast< DmElementHandle_t* >( m_pData ) = value;
  1935. g_pDataModelImp->OnElementReferenceAdded( value, this );
  1936. }
  1937. //-----------------------------------------------------------------------------
  1938. // Should we be allowed to modify the attribute data?
  1939. //-----------------------------------------------------------------------------
  1940. template< class T >
  1941. bool CDmAttribute::ShouldModify( const T& value )
  1942. {
  1943. if ( !IsTypeConvertable<T>() )
  1944. return false;
  1945. if ( ( GetType() == CDmAttributeInfo<T>::ATTRIBUTE_TYPE ) && IsAttributeEqual( GetValue<T>(), value ) )
  1946. return false;
  1947. return MarkDirty();
  1948. }
  1949. template<> bool CDmAttribute::ShouldModify( const DmElementHandle_t& value )
  1950. {
  1951. if ( !IsTypeConvertable<DmElementHandle_t>() )
  1952. return false;
  1953. if ( IsAttributeEqual( GetValue<DmElementHandle_t>(), value ) )
  1954. return false;
  1955. DmElementAttribute_t *pData = GetData<DmElementHandle_t>();
  1956. if ( pData->m_ElementType != UTL_INVAL_SYMBOL && !::IsA( value, pData->m_ElementType ) )
  1957. return false;
  1958. return MarkDirty();
  1959. }
  1960. //-----------------------------------------------------------------------------
  1961. // Main entry point for single-valued SetValue
  1962. //-----------------------------------------------------------------------------
  1963. template< class T >
  1964. void CDmAttribute::SetValue( const T &value )
  1965. {
  1966. if ( !ShouldModify( value ) )
  1967. return;
  1968. // UNDO Hook
  1969. if ( g_pDataModel->UndoEnabledForElement( m_pOwner ) )
  1970. {
  1971. CUndoAttributeSetValueElement<T> *pUndo = new CUndoAttributeSetValueElement<T>( this, value );
  1972. g_pDataModel->AddUndoElement( pUndo );
  1973. }
  1974. bool bIsBeingUnserialized = CDmeElementAccessor::IsBeingUnserialized( m_pOwner );
  1975. if ( IsFlagSet( FATTRIB_HAS_PRE_CALLBACK ) && !bIsBeingUnserialized )
  1976. {
  1977. m_pOwner->PreAttributeChanged( this );
  1978. }
  1979. CopyData< T >( value );
  1980. if ( !bIsBeingUnserialized )
  1981. {
  1982. if ( IsFlagSet( FATTRIB_HAS_CALLBACK ) )
  1983. {
  1984. m_pOwner->OnAttributeChanged( this );
  1985. }
  1986. if ( m_hMailingList != DMMAILINGLIST_INVALID )
  1987. {
  1988. if ( !g_pDataModelImp->PostAttributeChanged( m_hMailingList, this ) )
  1989. {
  1990. CleanupMailingList();
  1991. }
  1992. }
  1993. }
  1994. g_pDataModelImp->NotifyState( IsTopological( GetType() ) ? NOTIFY_CHANGE_TOPOLOGICAL : NOTIFY_CHANGE_ATTRIBUTE_VALUE );
  1995. }
  1996. //-----------------------------------------------------------------------------
  1997. // Versions that work on arrays
  1998. //-----------------------------------------------------------------------------
  1999. #define ATTRIBUTE_SET_VALUE_ARRAY( _type ) \
  2000. template<> void CDmAttribute::SetValue( const CUtlVector< _type >& value ) \
  2001. { \
  2002. CDmArrayAttributeOp< _type > accessor( this ); \
  2003. accessor.CopyArray( value.Base(), value.Count() ); \
  2004. }
  2005. void CDmAttribute::SetValue( const CDmAttribute *pAttribute )
  2006. {
  2007. s_pAttrInfo[ GetType() ]->SetValue( this, pAttribute->GetType(), pAttribute->GetAttributeData() );
  2008. }
  2009. void CDmAttribute::SetValue( CDmAttribute *pAttribute )
  2010. {
  2011. s_pAttrInfo[ GetType() ]->SetValue( this, pAttribute->GetType(), pAttribute->GetAttributeData() );
  2012. }
  2013. void CDmAttribute::SetValue( DmAttributeType_t valueType, const void *pValue )
  2014. {
  2015. s_pAttrInfo[ GetType() ]->SetValue( this, valueType, pValue );
  2016. }
  2017. //-----------------------------------------------------------------------------
  2018. // Sets the attribute to its default value based on its type
  2019. //-----------------------------------------------------------------------------
  2020. void CDmAttribute::SetToDefaultValue()
  2021. {
  2022. s_pAttrInfo[ GetType() ]->SetToDefaultValue( this );
  2023. }
  2024. //-----------------------------------------------------------------------------
  2025. // Convert to and from string
  2026. //-----------------------------------------------------------------------------
  2027. void CDmAttribute::SetValueFromString( const char *pValue )
  2028. {
  2029. switch ( GetType() )
  2030. {
  2031. case AT_STRING:
  2032. SetValue( pValue );
  2033. break;
  2034. default:
  2035. {
  2036. int nLen = pValue ? Q_strlen( pValue ) : 0;
  2037. if ( nLen == 0 )
  2038. {
  2039. SetToDefaultValue();
  2040. break;
  2041. }
  2042. CUtlBuffer buf( pValue, nLen, CUtlBuffer::TEXT_BUFFER | CUtlBuffer::READ_ONLY );
  2043. if ( !Unserialize( buf ) )
  2044. {
  2045. SetToDefaultValue();
  2046. }
  2047. }
  2048. break;
  2049. }
  2050. }
  2051. const char *CDmAttribute::GetValueAsString( char *pBuffer, size_t nBufLen ) const
  2052. {
  2053. Assert( pBuffer );
  2054. CUtlBuffer buf( pBuffer, nBufLen, CUtlBuffer::TEXT_BUFFER );
  2055. Serialize( buf );
  2056. return pBuffer;
  2057. }
  2058. //-----------------------------------------------------------------------------
  2059. // Name, type
  2060. //-----------------------------------------------------------------------------
  2061. const char* CDmAttribute::GetTypeString() const
  2062. {
  2063. return ::GetTypeString( GetType() );
  2064. }
  2065. const char *GetTypeString( DmAttributeType_t type )
  2066. {
  2067. if ( ( type >= 0 ) && ( type < AT_TYPE_COUNT ) )
  2068. return s_pAttrInfo[ type ]->AttributeTypeName();
  2069. return "unknown";
  2070. }
  2071. void CDmAttribute::SetName( const char *pNewName )
  2072. {
  2073. if ( m_pOwner->HasAttribute( pNewName ) && Q_stricmp( GetName(), pNewName ) )
  2074. {
  2075. Warning( "Tried to rename from '%s' to '%s', but '%s' already exists\n",
  2076. GetName(), pNewName, pNewName );
  2077. return;
  2078. }
  2079. if ( !MarkDirty() )
  2080. return;
  2081. // UNDO Hook
  2082. if ( g_pDataModel->UndoEnabledForElement( m_pOwner ) )
  2083. {
  2084. CUndoAttributeRenameElement *pUndo = new CUndoAttributeRenameElement( this, pNewName );
  2085. g_pDataModel->AddUndoElement( pUndo );
  2086. }
  2087. m_Name = g_pDataModel->GetSymbol( pNewName );
  2088. g_pDataModelImp->NotifyState( NOTIFY_CHANGE_TOPOLOGICAL );
  2089. }
  2090. //-----------------------------------------------------------------------------
  2091. // Serialization
  2092. //-----------------------------------------------------------------------------
  2093. bool CDmAttribute::SerializesOnMultipleLines() const
  2094. {
  2095. return s_pAttrInfo[ GetType() ]->SerializesOnMultipleLines();
  2096. }
  2097. bool CDmAttribute::Serialize( CUtlBuffer &buf ) const
  2098. {
  2099. return s_pAttrInfo[ GetType() ]->Serialize( this, buf );
  2100. }
  2101. bool CDmAttribute::Unserialize( CUtlBuffer &buf )
  2102. {
  2103. return s_pAttrInfo[ GetType() ]->Unserialize( this, buf );
  2104. }
  2105. bool CDmAttribute::SerializeElement( int nElement, CUtlBuffer &buf ) const
  2106. {
  2107. return s_pAttrInfo[ GetType() ]->SerializeElement( this, nElement, buf );
  2108. }
  2109. bool CDmAttribute::UnserializeElement( CUtlBuffer &buf )
  2110. {
  2111. return s_pAttrInfo[ GetType() ]->UnserializeElement( this, buf );
  2112. }
  2113. bool CDmAttribute::UnserializeElement( int nElement, CUtlBuffer &buf )
  2114. {
  2115. return s_pAttrInfo[ GetType() ]->UnserializeElement( this, nElement, buf );
  2116. }
  2117. // Called by elements after unserialization of their attributes is complete
  2118. void CDmAttribute::OnUnserializationFinished()
  2119. {
  2120. return s_pAttrInfo[ GetType() ]->OnUnserializationFinished( this );
  2121. }
  2122. //-----------------------------------------------------------------------------
  2123. // Methods related to attribute change notification
  2124. //-----------------------------------------------------------------------------
  2125. void CDmAttribute::CleanupMailingList()
  2126. {
  2127. if ( m_hMailingList != DMMAILINGLIST_INVALID )
  2128. {
  2129. g_pDataModelImp->DestroyMailingList( m_hMailingList );
  2130. m_hMailingList = DMMAILINGLIST_INVALID;
  2131. }
  2132. }
  2133. void CDmAttribute::NotifyWhenChanged( DmElementHandle_t h, bool bNotify )
  2134. {
  2135. if ( bNotify )
  2136. {
  2137. if ( m_hMailingList == DMMAILINGLIST_INVALID )
  2138. {
  2139. m_hMailingList = g_pDataModelImp->CreateMailingList();
  2140. }
  2141. g_pDataModelImp->AddElementToMailingList( m_hMailingList, h );
  2142. return;
  2143. }
  2144. if ( m_hMailingList != DMMAILINGLIST_INVALID )
  2145. {
  2146. if ( !g_pDataModelImp->RemoveElementFromMailingList( m_hMailingList, h ) )
  2147. {
  2148. CleanupMailingList();
  2149. }
  2150. }
  2151. }
  2152. //-----------------------------------------------------------------------------
  2153. // Get the attribute/create an attribute handle
  2154. //-----------------------------------------------------------------------------
  2155. DmAttributeHandle_t CDmAttribute::GetHandle( bool bCreate )
  2156. {
  2157. if ( (m_Handle == DMATTRIBUTE_HANDLE_INVALID) && bCreate )
  2158. {
  2159. m_Handle = g_pDataModelImp->AcquireAttributeHandle( this );
  2160. }
  2161. Assert( (m_Handle == DMATTRIBUTE_HANDLE_INVALID) || g_pDataModel->IsAttributeHandleValid( m_Handle ) );
  2162. return m_Handle;
  2163. }
  2164. void CDmAttribute::InvalidateHandle()
  2165. {
  2166. g_pDataModelImp->ReleaseAttributeHandle( m_Handle );
  2167. m_Handle = DMATTRIBUTE_HANDLE_INVALID;
  2168. }
  2169. //-----------------------------------------------------------------------------
  2170. // Memory usage estimations
  2171. //-----------------------------------------------------------------------------
  2172. bool HandleCompare( const DmElementHandle_t &a, const DmElementHandle_t &b )
  2173. {
  2174. return a == b;
  2175. }
  2176. unsigned int HandleHash( const DmElementHandle_t &h )
  2177. {
  2178. return (unsigned int)h;
  2179. }
  2180. int CDmAttribute::EstimateMemoryUsage( TraversalDepth_t depth ) const
  2181. {
  2182. CUtlHash< DmElementHandle_t > visited( 1024, 0, 0, HandleCompare, HandleHash );
  2183. return EstimateMemoryUsageInternal( visited, depth, 0 ) ;
  2184. }
  2185. int CDmAttribute::EstimateMemoryUsageInternal( CUtlHash< DmElementHandle_t > &visited, TraversalDepth_t depth, int *pCategories ) const
  2186. {
  2187. int nOverhead = sizeof( *this );
  2188. int nAttributeDataSize = s_pAttrInfo[ GetType() ]->DataSize();
  2189. int nTotalMemory = nOverhead + nAttributeDataSize;
  2190. int nAttributeExtraDataSize = 0;
  2191. if ( IsArrayType( GetType() ) )
  2192. {
  2193. CDmrGenericArrayConst array( this );
  2194. int nCount = array.Count();
  2195. nAttributeExtraDataSize = nCount * s_pAttrInfo[ GetType() ]->ValueSize(); // Data in the UtlVector
  2196. int nMallocOverhead = ( array.Count() == 0 ) ? 0 : 8; // malloc overhead inside the vector
  2197. nOverhead += nMallocOverhead;
  2198. nTotalMemory += nAttributeExtraDataSize + nMallocOverhead;
  2199. }
  2200. if ( pCategories )
  2201. {
  2202. ++pCategories[MEMORY_CATEGORY_ATTRIBUTE_COUNT];
  2203. pCategories[MEMORY_CATEGORY_ATTRIBUTE_DATA] += nAttributeDataSize + nAttributeExtraDataSize;
  2204. pCategories[MEMORY_CATEGORY_ATTRIBUTE_OVERHEAD] += nOverhead;
  2205. if ( !IsDataInline() )
  2206. {
  2207. pCategories[MEMORY_CATEGORY_OUTER] -= nAttributeDataSize;
  2208. Assert( pCategories[MEMORY_CATEGORY_OUTER] >= 0 );
  2209. nTotalMemory -= nAttributeDataSize;
  2210. }
  2211. }
  2212. switch ( GetType() )
  2213. {
  2214. case AT_STRING:
  2215. {
  2216. const CUtlString &value = GetValue<CUtlString>();
  2217. if ( pCategories )
  2218. {
  2219. pCategories[MEMORY_CATEGORY_ATTRIBUTE_DATA] += value.Length() + 1;
  2220. pCategories[MEMORY_CATEGORY_ATTRIBUTE_OVERHEAD] += 8;
  2221. }
  2222. return nTotalMemory + value.Length() + 1 + 8; // string's length skips trailing null
  2223. }
  2224. case AT_STRING_ARRAY:
  2225. {
  2226. const CUtlVector< CUtlString > &array = GetValue< CUtlVector< CUtlString > >( );
  2227. for ( int i = 0; i < array.Count(); ++i )
  2228. {
  2229. int nStrLen = array[ i ].Length() + 1;
  2230. if ( pCategories )
  2231. {
  2232. pCategories[MEMORY_CATEGORY_ATTRIBUTE_DATA] += nStrLen;
  2233. pCategories[MEMORY_CATEGORY_ATTRIBUTE_OVERHEAD] += 8;
  2234. }
  2235. nTotalMemory += nStrLen + 8; // string's length skips trailing null
  2236. }
  2237. return nTotalMemory;
  2238. }
  2239. case AT_VOID:
  2240. {
  2241. const CUtlBinaryBlock &value = GetValue< CUtlBinaryBlock >();
  2242. if ( pCategories )
  2243. {
  2244. pCategories[MEMORY_CATEGORY_ATTRIBUTE_DATA] += value.Length();
  2245. pCategories[MEMORY_CATEGORY_ATTRIBUTE_OVERHEAD] += 8;
  2246. }
  2247. return nTotalMemory + value.Length() + 8;
  2248. }
  2249. case AT_VOID_ARRAY:
  2250. {
  2251. const CUtlVector< CUtlBinaryBlock > &array = GetValue< CUtlVector< CUtlBinaryBlock > >();
  2252. for ( int i = 0; i < array.Count(); ++i )
  2253. {
  2254. if ( pCategories )
  2255. {
  2256. pCategories[MEMORY_CATEGORY_ATTRIBUTE_DATA] += array[ i ].Length();
  2257. pCategories[MEMORY_CATEGORY_ATTRIBUTE_OVERHEAD] += 8;
  2258. }
  2259. nTotalMemory += array[ i ].Length() + 8;
  2260. }
  2261. return nTotalMemory;
  2262. }
  2263. case AT_ELEMENT:
  2264. if ( ShouldTraverse( this, depth ) )
  2265. {
  2266. CDmElement *pElement = GetValueElement<CDmElement>();
  2267. if ( pElement )
  2268. {
  2269. nTotalMemory += CDmeElementAccessor::EstimateMemoryUsage( pElement, visited, depth, pCategories );
  2270. }
  2271. }
  2272. return nTotalMemory;
  2273. case AT_ELEMENT_ARRAY:
  2274. if ( ShouldTraverse( this, depth ) )
  2275. {
  2276. CDmrElementArrayConst<> array( this );
  2277. for ( int i = 0; i < array.Count(); ++i )
  2278. {
  2279. CDmElement *pElement = array[ i ];
  2280. if ( pElement )
  2281. {
  2282. nTotalMemory += CDmeElementAccessor::EstimateMemoryUsage( pElement, visited, depth, pCategories );
  2283. }
  2284. }
  2285. }
  2286. return nTotalMemory;
  2287. }
  2288. return nTotalMemory;
  2289. }
  2290. //-----------------------------------------------------------------------------
  2291. //
  2292. // CDmaArrayBase starts here
  2293. //
  2294. //-----------------------------------------------------------------------------
  2295. //-----------------------------------------------------------------------------
  2296. // Constructor
  2297. //-----------------------------------------------------------------------------
  2298. template< class T, class B >
  2299. CDmaArrayConstBase<T,B>::CDmaArrayConstBase( )
  2300. {
  2301. m_pAttribute = NULL;
  2302. }
  2303. //-----------------------------------------------------------------------------
  2304. // Search
  2305. //-----------------------------------------------------------------------------
  2306. template< class T, class B >
  2307. int CDmaArrayConstBase<T,B>::Find( const T &value ) const
  2308. {
  2309. return Value().Find( value );
  2310. }
  2311. //-----------------------------------------------------------------------------
  2312. // Insertion
  2313. //-----------------------------------------------------------------------------
  2314. template< class T, class B >
  2315. int CDmaArrayBase<T,B>::AddToTail()
  2316. {
  2317. T defaultVal;
  2318. CDmAttributeInfo<T>::SetDefaultValue( defaultVal );
  2319. CDmArrayAttributeOp<T> accessor( this->m_pAttribute );
  2320. return accessor.InsertBefore( Value().Count(), defaultVal );
  2321. }
  2322. template< class T, class B >
  2323. int CDmaArrayBase<T,B>::InsertBefore( int elem )
  2324. {
  2325. T defaultVal;
  2326. CDmAttributeInfo<T>::SetDefaultValue( defaultVal );
  2327. CDmArrayAttributeOp<T> accessor( this->m_pAttribute );
  2328. return accessor.InsertBefore( elem, defaultVal );
  2329. }
  2330. template< class T, class B >
  2331. int CDmaArrayBase<T,B>::AddToTail( const T& src )
  2332. {
  2333. CDmArrayAttributeOp<T> accessor( this->m_pAttribute );
  2334. return accessor.InsertBefore( Value().Count(), src );
  2335. }
  2336. template< class T, class B >
  2337. int CDmaArrayBase<T,B>::InsertBefore( int elem, const T& src )
  2338. {
  2339. CDmArrayAttributeOp<T> accessor( this->m_pAttribute );
  2340. return accessor.InsertBefore( elem, src );
  2341. }
  2342. template< class T, class B >
  2343. int CDmaArrayBase<T,B>::AddMultipleToTail( int num )
  2344. {
  2345. CDmArrayAttributeOp<T> accessor( this->m_pAttribute );
  2346. return accessor.InsertMultipleBefore( Value().Count(), num );
  2347. }
  2348. template< class T, class B >
  2349. int CDmaArrayBase<T,B>::InsertMultipleBefore( int elem, int num )
  2350. {
  2351. CDmArrayAttributeOp<T> accessor( this->m_pAttribute );
  2352. return accessor.InsertMultipleBefore( elem, num );
  2353. }
  2354. template< class T, class B >
  2355. void CDmaArrayBase<T,B>::EnsureCount( int num )
  2356. {
  2357. int nCurrentCount = Value().Count();
  2358. if ( nCurrentCount < num )
  2359. {
  2360. AddMultipleToTail( num - nCurrentCount );
  2361. }
  2362. }
  2363. //-----------------------------------------------------------------------------
  2364. // Element modification
  2365. //-----------------------------------------------------------------------------
  2366. template< class T, class B >
  2367. void CDmaArrayBase<T,B>::Set( int i, const T& value )
  2368. {
  2369. CDmArrayAttributeOp<T> accessor( this->m_pAttribute );
  2370. return accessor.Set( i, value );
  2371. }
  2372. template< class T, class B >
  2373. void CDmaArrayBase<T,B>::SetMultiple( int i, int nCount, const T* pValue )
  2374. {
  2375. CDmArrayAttributeOp<T> accessor( this->m_pAttribute );
  2376. accessor.SetMultiple( i, nCount, pValue );
  2377. }
  2378. template< class T, class B >
  2379. void CDmaArrayBase<T,B>::Swap( int i, int j )
  2380. {
  2381. CDmArrayAttributeOp<T> accessor( this->m_pAttribute );
  2382. accessor.Swap( i, j );
  2383. }
  2384. template< class T, class B >
  2385. void CDmaArrayBase<T,B>::SwapArray( CUtlVector< T > &array )
  2386. {
  2387. CDmArrayAttributeOp<T> accessor( this->m_pAttribute );
  2388. accessor.SwapArray( array );
  2389. }
  2390. //-----------------------------------------------------------------------------
  2391. // Copy
  2392. //-----------------------------------------------------------------------------
  2393. template< class T, class B >
  2394. void CDmaArrayBase<T,B>::CopyArray( const T *pArray, int nCount )
  2395. {
  2396. CDmArrayAttributeOp<T> accessor( this->m_pAttribute );
  2397. accessor.CopyArray( pArray, nCount );
  2398. }
  2399. //-----------------------------------------------------------------------------
  2400. // Removal
  2401. //-----------------------------------------------------------------------------
  2402. template< class T, class B >
  2403. void CDmaArrayBase<T,B>::FastRemove( int elem )
  2404. {
  2405. CDmArrayAttributeOp<T> accessor( this->m_pAttribute );
  2406. accessor.FastRemove( elem );
  2407. }
  2408. template< class T, class B >
  2409. void CDmaArrayBase<T,B>::Remove( int elem )
  2410. {
  2411. CDmArrayAttributeOp<T> accessor( this->m_pAttribute );
  2412. accessor.Remove( elem );
  2413. }
  2414. template< class T, class B >
  2415. void CDmaArrayBase<T,B>::RemoveAll()
  2416. {
  2417. CDmArrayAttributeOp<T> accessor( this->m_pAttribute );
  2418. accessor.RemoveAll();
  2419. }
  2420. template< class T, class B >
  2421. void CDmaArrayBase<T,B>::RemoveMultiple( int elem, int num )
  2422. {
  2423. CDmArrayAttributeOp<T> accessor( this->m_pAttribute );
  2424. accessor.RemoveMultiple( elem, num );
  2425. }
  2426. //-----------------------------------------------------------------------------
  2427. // Memory management
  2428. //-----------------------------------------------------------------------------
  2429. template< class T, class B >
  2430. void CDmaArrayBase<T,B>::EnsureCapacity( int num )
  2431. {
  2432. Value().EnsureCapacity( num );
  2433. }
  2434. template< class T, class B >
  2435. void CDmaArrayBase<T,B>::Purge()
  2436. {
  2437. CDmArrayAttributeOp<T> accessor( this->m_pAttribute );
  2438. accessor.Purge();
  2439. }
  2440. //-----------------------------------------------------------------------------
  2441. // Attribute initialization
  2442. //-----------------------------------------------------------------------------
  2443. template< class T, class B >
  2444. void CDmaDecorator<T,B>::Init( CDmElement *pOwner, const char *pAttributeName, int nFlags = 0 )
  2445. {
  2446. Assert( pOwner );
  2447. this->m_pAttribute = pOwner->AddExternalAttribute( pAttributeName, CDmAttributeInfo<CUtlVector<T> >::AttributeType(), &Value() );
  2448. Assert( m_pAttribute );
  2449. if ( nFlags )
  2450. {
  2451. this->m_pAttribute->AddFlag( nFlags );
  2452. }
  2453. }
  2454. //-----------------------------------------------------------------------------
  2455. // Attribute attribute reference
  2456. //-----------------------------------------------------------------------------
  2457. template< class T, class BaseClass >
  2458. void CDmrDecoratorConst<T,BaseClass>::Init( const CDmAttribute* pAttribute )
  2459. {
  2460. if ( pAttribute && pAttribute->GetType() == CDmAttributeInfo< CUtlVector< T > >::AttributeType() )
  2461. {
  2462. this->m_pAttribute = const_cast<CDmAttribute*>( pAttribute );
  2463. Attach( this->m_pAttribute->GetAttributeData() );
  2464. }
  2465. else
  2466. {
  2467. this->m_pAttribute = NULL;
  2468. Attach( NULL );
  2469. }
  2470. }
  2471. template< class T, class BaseClass >
  2472. void CDmrDecoratorConst<T,BaseClass>::Init( const CDmElement *pElement, const char *pAttributeName )
  2473. {
  2474. const CDmAttribute *pAttribute = NULL;
  2475. if ( pElement && pAttributeName && pAttributeName[0] )
  2476. {
  2477. pAttribute = pElement->GetAttribute( pAttributeName );
  2478. }
  2479. Init( pAttribute );
  2480. }
  2481. template< class T, class BaseClass >
  2482. bool CDmrDecoratorConst<T,BaseClass>::IsValid() const
  2483. {
  2484. return this->m_pAttribute != NULL;
  2485. }
  2486. template< class T, class BaseClass >
  2487. void CDmrDecorator<T,BaseClass>::Init( CDmAttribute* pAttribute )
  2488. {
  2489. if ( pAttribute && pAttribute->GetType() == CDmAttributeInfo< CUtlVector< T > >::AttributeType() )
  2490. {
  2491. this->m_pAttribute = pAttribute;
  2492. Attach( this->m_pAttribute->GetAttributeData() );
  2493. }
  2494. else
  2495. {
  2496. this->m_pAttribute = NULL;
  2497. Attach( NULL );
  2498. }
  2499. }
  2500. template< class T, class BaseClass >
  2501. void CDmrDecorator<T,BaseClass>::Init( CDmElement *pElement, const char *pAttributeName, bool bAddAttribute )
  2502. {
  2503. CDmAttribute *pAttribute = NULL;
  2504. if ( pElement && pAttributeName && pAttributeName[0] )
  2505. {
  2506. if ( bAddAttribute )
  2507. {
  2508. pAttribute = pElement->AddAttribute( pAttributeName, CDmAttributeInfo< CUtlVector< T > >::AttributeType() );
  2509. }
  2510. else
  2511. {
  2512. pAttribute = pElement->GetAttribute( pAttributeName );
  2513. }
  2514. }
  2515. Init( pAttribute );
  2516. }
  2517. template< class T, class BaseClass >
  2518. bool CDmrDecorator<T,BaseClass>::IsValid() const
  2519. {
  2520. return this->m_pAttribute != NULL;
  2521. }
  2522. //-----------------------------------------------------------------------------
  2523. //
  2524. // Generic array access
  2525. //
  2526. //-----------------------------------------------------------------------------
  2527. //-----------------------------------------------------------------------------
  2528. // Helper macros to make switch statements based on type
  2529. //-----------------------------------------------------------------------------
  2530. #define ARRAY_METHOD_VOID( _type, _func ) \
  2531. case CDmAttributeInfo< CUtlVector< _type > >::ATTRIBUTE_TYPE: \
  2532. { \
  2533. CDmrArray< _type > &array = *reinterpret_cast< CDmrArray< _type > * >( &arrayShared ); \
  2534. array.Init( m_pAttribute ); \
  2535. array._func; \
  2536. } \
  2537. break;
  2538. #define APPLY_ARRAY_METHOD_VOID( _func ) \
  2539. CDmrArray<int> arrayShared; \
  2540. switch( m_pAttribute->GetType() ) \
  2541. { \
  2542. ARRAY_METHOD_VOID( bool, _func ) \
  2543. ARRAY_METHOD_VOID( int, _func ) \
  2544. ARRAY_METHOD_VOID( float, _func ) \
  2545. ARRAY_METHOD_VOID( Color, _func ) \
  2546. ARRAY_METHOD_VOID( Vector2D, _func ) \
  2547. ARRAY_METHOD_VOID( Vector, _func ) \
  2548. ARRAY_METHOD_VOID( Vector4D, _func ) \
  2549. ARRAY_METHOD_VOID( QAngle, _func ) \
  2550. ARRAY_METHOD_VOID( Quaternion, _func ) \
  2551. ARRAY_METHOD_VOID( VMatrix, _func ) \
  2552. ARRAY_METHOD_VOID( CUtlString, _func ) \
  2553. ARRAY_METHOD_VOID( CUtlBinaryBlock, _func ) \
  2554. ARRAY_METHOD_VOID( DmObjectId_t, _func ) \
  2555. ARRAY_METHOD_VOID( DmElementHandle_t, _func ) \
  2556. default: \
  2557. break; \
  2558. }
  2559. #define ARRAY_METHOD_RET( _type, _func ) \
  2560. case CDmAttributeInfo< CUtlVector< _type > >::ATTRIBUTE_TYPE: \
  2561. { \
  2562. CDmrArray< _type > &array = *reinterpret_cast< CDmrArray< _type > * >( &arrayShared ); \
  2563. array.Init( m_pAttribute ); \
  2564. return array._func; \
  2565. }
  2566. #define APPLY_ARRAY_METHOD_RET( _func ) \
  2567. CDmrArray<int> arrayShared; \
  2568. switch( m_pAttribute->GetType() ) \
  2569. { \
  2570. ARRAY_METHOD_RET( bool, _func ); \
  2571. ARRAY_METHOD_RET( int, _func ); \
  2572. ARRAY_METHOD_RET( float, _func ); \
  2573. ARRAY_METHOD_RET( Color, _func ); \
  2574. ARRAY_METHOD_RET( Vector2D, _func ); \
  2575. ARRAY_METHOD_RET( Vector, _func ); \
  2576. ARRAY_METHOD_RET( Vector4D, _func ); \
  2577. ARRAY_METHOD_RET( QAngle, _func ); \
  2578. ARRAY_METHOD_RET( Quaternion, _func ); \
  2579. ARRAY_METHOD_RET( VMatrix, _func ); \
  2580. ARRAY_METHOD_RET( CUtlString, _func ); \
  2581. ARRAY_METHOD_RET( CUtlBinaryBlock, _func ); \
  2582. ARRAY_METHOD_RET( DmObjectId_t, _func ); \
  2583. ARRAY_METHOD_RET( DmElementHandle_t, _func ); \
  2584. default: \
  2585. break; \
  2586. }
  2587. CDmrGenericArrayConst::CDmrGenericArrayConst() : m_pAttribute( NULL )
  2588. {
  2589. }
  2590. CDmrGenericArrayConst::CDmrGenericArrayConst( const CDmAttribute* pAttribute )
  2591. {
  2592. Init( pAttribute );
  2593. }
  2594. CDmrGenericArrayConst::CDmrGenericArrayConst( const CDmElement *pElement, const char *pAttributeName )
  2595. {
  2596. Init( pElement, pAttributeName );
  2597. }
  2598. void CDmrGenericArrayConst::Init( const CDmAttribute *pAttribute )
  2599. {
  2600. if ( pAttribute && IsArrayType( pAttribute->GetType() ) )
  2601. {
  2602. m_pAttribute = const_cast<CDmAttribute*>( pAttribute );
  2603. }
  2604. else
  2605. {
  2606. m_pAttribute = NULL;
  2607. }
  2608. }
  2609. void CDmrGenericArrayConst::Init( const CDmElement *pElement, const char *pAttributeName )
  2610. {
  2611. const CDmAttribute *pAttribute = ( pElement && pAttributeName && pAttributeName[0] ) ? pElement->GetAttribute( pAttributeName ) : NULL;
  2612. Init( pAttribute );
  2613. }
  2614. int CDmrGenericArrayConst::Count() const
  2615. {
  2616. APPLY_ARRAY_METHOD_RET( Count() );
  2617. return 0;
  2618. }
  2619. const void* CDmrGenericArrayConst::GetUntyped( int i ) const
  2620. {
  2621. APPLY_ARRAY_METHOD_RET( GetUntyped( i ) );
  2622. return NULL;
  2623. }
  2624. const char* CDmrGenericArrayConst::GetAsString( int i, char *pBuffer, size_t nBufLen ) const
  2625. {
  2626. if ( ( Count() > i ) && ( i >= 0 ) )
  2627. {
  2628. CUtlBuffer buf( pBuffer, nBufLen, CUtlBuffer::TEXT_BUFFER );
  2629. m_pAttribute->SerializeElement( i, buf );
  2630. }
  2631. else
  2632. {
  2633. pBuffer[0] = 0;
  2634. }
  2635. return pBuffer;
  2636. }
  2637. CDmrGenericArray::CDmrGenericArray( CDmAttribute* pAttribute )
  2638. {
  2639. Init( pAttribute );
  2640. }
  2641. CDmrGenericArray::CDmrGenericArray( CDmElement *pElement, const char *pAttributeName )
  2642. {
  2643. Init( pElement, pAttributeName );
  2644. }
  2645. void CDmrGenericArray::EnsureCount( int num )
  2646. {
  2647. APPLY_ARRAY_METHOD_VOID( EnsureCount(num) );
  2648. }
  2649. int CDmrGenericArray::AddToTail()
  2650. {
  2651. APPLY_ARRAY_METHOD_RET( AddToTail() );
  2652. return -1;
  2653. }
  2654. void CDmrGenericArray::Remove( int elem )
  2655. {
  2656. APPLY_ARRAY_METHOD_VOID( Remove(elem) );
  2657. }
  2658. void CDmrGenericArray::RemoveAll()
  2659. {
  2660. APPLY_ARRAY_METHOD_VOID( RemoveAll() );
  2661. }
  2662. void CDmrGenericArray::SetMultiple( int i, int nCount, DmAttributeType_t valueType, const void *pValue )
  2663. {
  2664. s_pAttrInfo[ m_pAttribute->GetType() ]->SetMultiple( m_pAttribute, i, nCount, valueType, pValue );
  2665. }
  2666. void CDmrGenericArray::Set( int i, DmAttributeType_t valueType, const void *pValue )
  2667. {
  2668. s_pAttrInfo[ m_pAttribute->GetType() ]->Set( m_pAttribute, i, valueType, pValue );
  2669. }
  2670. void CDmrGenericArray::SetFromString( int i, const char *pValue )
  2671. {
  2672. if ( ( Count() > i ) && ( i >= 0 ) )
  2673. {
  2674. int nLen = pValue ? Q_strlen( pValue ) : 0;
  2675. CUtlBuffer buf( pValue, nLen, CUtlBuffer::TEXT_BUFFER | CUtlBuffer::READ_ONLY );
  2676. m_pAttribute->UnserializeElement( i, buf );
  2677. }
  2678. }
  2679. //-----------------------------------------------------------------------------
  2680. // Skip unserialization for an attribute type (unserialize into a dummy variable)
  2681. //-----------------------------------------------------------------------------
  2682. bool SkipUnserialize( CUtlBuffer &buf, DmAttributeType_t type )
  2683. {
  2684. if ( type == AT_UNKNOWN )
  2685. return false;
  2686. return s_pAttrInfo[ type ]->SkipUnserialize( buf );
  2687. }
  2688. //-----------------------------------------------------------------------------
  2689. // returns the number of attributes currently allocated
  2690. //-----------------------------------------------------------------------------
  2691. int GetAllocatedAttributeCount()
  2692. {
  2693. return g_AttrAlloc.Count();
  2694. }
  2695. //-----------------------------------------------------------------------------
  2696. // Attribute type->name and name->attribute type
  2697. //-----------------------------------------------------------------------------
  2698. const char *AttributeTypeName( DmAttributeType_t type )
  2699. {
  2700. if ( ( type >= 0 ) && ( type < AT_TYPE_COUNT ) )
  2701. return s_pAttrInfo[ type ]->AttributeTypeName();
  2702. return "unknown";
  2703. }
  2704. DmAttributeType_t AttributeType( const char *pName )
  2705. {
  2706. for ( int i = 0; i < AT_TYPE_COUNT; ++i )
  2707. {
  2708. if ( !Q_stricmp( s_pAttrInfo[ i ]->AttributeTypeName(), pName ) )
  2709. return (DmAttributeType_t)i;
  2710. }
  2711. return AT_UNKNOWN;
  2712. }
  2713. //-----------------------------------------------------------------------------
  2714. // Explicit template instantiation for the known attribute types
  2715. //-----------------------------------------------------------------------------
  2716. template <class T>
  2717. class CInstantiateOp
  2718. {
  2719. public:
  2720. CInstantiateOp()
  2721. {
  2722. s_pAttrInfo[ CDmAttributeInfo<T>::ATTRIBUTE_TYPE ] = new CDmAttributeOp< T >;
  2723. }
  2724. };
  2725. static CInstantiateOp<DmUnknownAttribute_t> __s_AttrDmUnknownAttribute_t;
  2726. #define INSTANTIATE_GENERIC_OPS( _className ) \
  2727. template< > class CInstantiateOp< CUtlVector< _className > > \
  2728. { \
  2729. public: \
  2730. CInstantiateOp() \
  2731. { \
  2732. s_pAttrInfo[ CDmAttributeInfo< CUtlVector< _className > >::ATTRIBUTE_TYPE ] = new CDmArrayAttributeOp< _className >; \
  2733. } \
  2734. }; \
  2735. static CInstantiateOp< _className > __s_Attr ## _className; \
  2736. static CInstantiateOp< CUtlVector< _className > > __s_AttrArray ## _className;
  2737. #define DEFINE_ATTRIBUTE_TYPE( _type ) \
  2738. INSTANTIATE_GENERIC_OPS( _type ) \
  2739. ATTRIBUTE_SET_VALUE_ARRAY( _type ) \
  2740. template void CDmAttribute::SetValue< _type >( const _type& value ); \
  2741. template class CDmArrayAttributeOp< _type >; \
  2742. template class CDmaArrayBase< _type, CDmaDataInternal< CUtlVector< _type > > >; \
  2743. template class CDmaArrayBase< _type, CDmaDataExternal< CUtlVector< _type > > >; \
  2744. template class CDmaArrayConstBase< _type, CDmaDataInternal< CUtlVector< _type > > >; \
  2745. template class CDmaArrayConstBase< _type, CDmaDataExternal< CUtlVector< _type > > >; \
  2746. template class CDmaDecorator< _type, CDmaArrayBase< _type, CDmaDataInternal< CUtlVector< _type > > > >; \
  2747. template class CDmrDecorator< _type, CDmaArrayBase< _type, CDmaDataExternal< CUtlVector< _type > > > >; \
  2748. template class CDmrDecoratorConst< _type, CDmaArrayConstBase< _type, CDmaDataExternal< CUtlVector< _type > > > >;
  2749. DEFINE_ATTRIBUTE_TYPE( int )
  2750. DEFINE_ATTRIBUTE_TYPE( float )
  2751. DEFINE_ATTRIBUTE_TYPE( bool )
  2752. DEFINE_ATTRIBUTE_TYPE( Color )
  2753. DEFINE_ATTRIBUTE_TYPE( Vector2D )
  2754. DEFINE_ATTRIBUTE_TYPE( Vector )
  2755. DEFINE_ATTRIBUTE_TYPE( Vector4D )
  2756. DEFINE_ATTRIBUTE_TYPE( QAngle )
  2757. DEFINE_ATTRIBUTE_TYPE( Quaternion )
  2758. DEFINE_ATTRIBUTE_TYPE( VMatrix )
  2759. DEFINE_ATTRIBUTE_TYPE( CUtlString )
  2760. DEFINE_ATTRIBUTE_TYPE( CUtlBinaryBlock )
  2761. DEFINE_ATTRIBUTE_TYPE( DmObjectId_t )
  2762. DEFINE_ATTRIBUTE_TYPE( DmElementHandle_t )
  2763. template class CDmaDecorator< CUtlString, CDmaStringArrayBase< CDmaDataInternal< CUtlVector< CUtlString > > > >;
  2764. template class CDmrDecorator< CUtlString, CDmaStringArrayBase< CDmaDataExternal< CUtlVector< CUtlString > > > >;