Counter Strike : Global Offensive Source Code
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.

3564 lines
98 KiB

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