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.

1210 lines
42 KiB

  1. //====== Copyright � 1996-2004, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #ifndef DMELEMENT_H
  7. #define DMELEMENT_H
  8. #ifdef _WIN32
  9. #pragma once
  10. #endif
  11. #include "tier1/utlmap.h"
  12. #include "tier1/utlhash.h"
  13. #include "tier1/utlvector.h"
  14. #include "tier1/utlsymbol.h"
  15. #include "tier1/mempool.h"
  16. #include "datamodel/attributeflags.h"
  17. #include "datamodel/idatamodel.h"
  18. #include "datamodel/dmattribute.h"
  19. #include "datamodel/dmvar.h"
  20. #include "tier0/vprof.h"
  21. #include "tier1/utlsymbollarge.h"
  22. //-----------------------------------------------------------------------------
  23. // Forward declarations:
  24. //-----------------------------------------------------------------------------
  25. class CDmAttribute;
  26. class Color;
  27. class Vector;
  28. class QAngle;
  29. class Quaternion;
  30. class VMatrix;
  31. class CDmElement;
  32. //-----------------------------------------------------------------------------
  33. // Suppress some SWIG warnings, only for SWIG. Here because many SWIG
  34. // projects %import this header directly
  35. //-----------------------------------------------------------------------------
  36. #ifdef SWIG
  37. %ignore CAttributeReferenceIterator::operator++;
  38. %warnfilter( 302 ) FindReferringElement;
  39. %warnfilter( 302 ) CopyElements;
  40. %warnfilter( 509 ) CDmElement::SetParity;
  41. #endif // SWIG
  42. //-----------------------------------------------------------------------------
  43. //
  44. //-----------------------------------------------------------------------------
  45. typedef bool (CDmElement::*pfnCommandMethod)( const char *command, const char *args );
  46. // element/element array traversal path item - assumes the full path does NOT contain cycles
  47. struct ElementPathItem_t
  48. {
  49. ElementPathItem_t( DmElementHandle_t hElem = DMELEMENT_HANDLE_INVALID,
  50. DmAttributeHandle_t hAttr = DMATTRIBUTE_HANDLE_INVALID,
  51. int idx = -1 )
  52. : hElement( hElem ), hAttribute( hAttr ), nIndex( idx )
  53. {
  54. }
  55. // only uses hElement so that it can be used to search for elements
  56. bool operator==( const ElementPathItem_t &that ) const
  57. {
  58. return hElement == that.hElement;
  59. }
  60. DmElementHandle_t hElement;
  61. DmAttributeHandle_t hAttribute;
  62. int nIndex;
  63. };
  64. //-----------------------------------------------------------------------------
  65. // singly-linked attribute list
  66. //-----------------------------------------------------------------------------
  67. struct DmAttributeList_t
  68. {
  69. DmAttributeList_t() : m_hAttribute( DMATTRIBUTE_HANDLE_INVALID ), m_pNext( NULL ) {}
  70. DmAttributeHandle_t m_hAttribute;
  71. DmAttributeList_t *m_pNext;
  72. private:
  73. DECLARE_FIXEDSIZE_ALLOCATOR( DmAttributeList_t );
  74. };
  75. //-----------------------------------------------------------------------------
  76. // helper class to allow CDmeHandle access to g_pDataModelImp
  77. //-----------------------------------------------------------------------------
  78. enum HandleType_t
  79. {
  80. HT_WEAK,
  81. HT_STRONG,
  82. HT_UNDO,
  83. };
  84. class CDmeElementRefHelper
  85. {
  86. protected:
  87. void Ref ( DmElementHandle_t hElement, HandleType_t handleType );
  88. void Unref( DmElementHandle_t hElement, HandleType_t handleType );
  89. };
  90. //-----------------------------------------------------------------------------
  91. // element reference struct - containing attribute referrers and handle refcount
  92. //-----------------------------------------------------------------------------
  93. struct DmElementReference_t
  94. {
  95. explicit DmElementReference_t( DmElementHandle_t hElement = DMELEMENT_HANDLE_INVALID ) :
  96. m_hElement( hElement ), m_nWeakHandleCount( 0 ), m_nStrongHandleCount( 0 ), m_nUndoHandleCount( 0 ), m_bHasEverBeenReferenced( false )
  97. {
  98. }
  99. DmElementReference_t( const DmElementReference_t &that ) :
  100. m_hElement( that.m_hElement ), m_nWeakHandleCount( that.m_nWeakHandleCount ),
  101. m_nStrongHandleCount( that.m_nStrongHandleCount ), m_nUndoHandleCount( that.m_nUndoHandleCount ),
  102. m_bHasEverBeenReferenced( that.m_bHasEverBeenReferenced ), m_attributes( that.m_attributes )
  103. {
  104. }
  105. DmElementReference_t &operator=( const DmElementReference_t &that )
  106. {
  107. m_hElement = that.m_hElement;
  108. m_nWeakHandleCount = that.m_nWeakHandleCount;
  109. m_nStrongHandleCount = that.m_nStrongHandleCount;
  110. m_nUndoHandleCount = that.m_nUndoHandleCount;
  111. m_bHasEverBeenReferenced = that.m_bHasEverBeenReferenced;
  112. m_attributes.m_hAttribute = that.m_attributes.m_hAttribute;
  113. m_attributes.m_pNext = that.m_attributes.m_pNext;
  114. return *this;
  115. }
  116. ~DmElementReference_t()
  117. {
  118. // Assert( !IsStronglyReferenced() );
  119. }
  120. void AddAttribute( CDmAttribute *pAttribute );
  121. void RemoveAttribute( CDmAttribute *pAttribute );
  122. bool FindAttribute( CDmAttribute *pAttribute );
  123. bool IsStronglyReferenced() // should this element be kept around (even if it's DmElementHandle_t is invalidated)
  124. {
  125. return m_attributes.m_hAttribute != DMATTRIBUTE_HANDLE_INVALID || m_nStrongHandleCount > 0;
  126. }
  127. bool IsWeaklyReferenced() // should we keep this element's DmElementHandle_t mapped to it's id (even if the element is deleted)
  128. {
  129. return IsStronglyReferenced() || IsReferencedByUndo() || m_nWeakHandleCount > 0;
  130. }
  131. bool IsReferencedByUndo()
  132. {
  133. return m_nUndoHandleCount > 0;
  134. }
  135. int EstimateMemoryOverhead()
  136. {
  137. int nBytes = 0;
  138. for ( DmAttributeList_t *pLink = m_attributes.m_pNext; pLink; pLink = pLink->m_pNext )
  139. {
  140. nBytes += sizeof( DmAttributeList_t );
  141. }
  142. return nBytes;
  143. }
  144. DmElementHandle_t m_hElement;
  145. unsigned int m_nWeakHandleCount : 10; // CDmeHandle<T> - for auto-hookup once the element comes back, mainly used by UI
  146. unsigned int m_nStrongHandleCount : 10; // CDmeCountedElementRef - for preventing elements from being truly deleted, mainly used by undo and file root
  147. unsigned int m_nUndoHandleCount : 10; // CDmeUndoHandle<T> - for undo only, to allow it to keep handles to elements that may be conceptually deleted
  148. bool m_bHasEverBeenReferenced : 1;
  149. DmAttributeList_t m_attributes;
  150. };
  151. //-----------------------------------------------------------------------------
  152. // Base DmElement we inherit from in higher-level classes
  153. //-----------------------------------------------------------------------------
  154. class CDmElement
  155. {
  156. public:
  157. // Can be overridden by derived classes
  158. virtual void OnAttributeChanged( CDmAttribute *pAttribute ) {}
  159. virtual void OnAttributeArrayElementAdded( CDmAttribute *pAttribute, int nFirstElem, int nLastElem ) {}
  160. virtual void OnAttributeArrayElementRemoved( CDmAttribute *pAttribute, int nFirstElem, int nLastElem ) {}
  161. virtual void Resolve() {}
  162. virtual bool IsA( CUtlSymbolLarge typeSymbol ) const;
  163. virtual int GetInheritanceDepth( CUtlSymbolLarge typeSymbol ) const;
  164. virtual void OnElementUnserialized() {}
  165. virtual void OnElementSerialized() {}
  166. virtual int AllocatedSize() const { return sizeof( CDmElement ); }
  167. // Returns the element handle
  168. DmElementHandle_t GetHandle() const;
  169. // Attribute iteration, finding
  170. // NOTE: Passing a type into GetAttribute will return NULL if the attribute exists but isn't that type
  171. bool HasAttribute( const char *pAttributeName, DmAttributeType_t type = AT_UNKNOWN ) const;
  172. CDmAttribute *GetAttribute( const char *pAttributeName, DmAttributeType_t type = AT_UNKNOWN );
  173. const CDmAttribute *GetAttribute( const char *pAttributeName, DmAttributeType_t type = AT_UNKNOWN ) const;
  174. int AttributeCount() const;
  175. CDmAttribute* FirstAttribute();
  176. const CDmAttribute* FirstAttribute() const;
  177. // Element name, type, ID
  178. // WARNING: SetType() should only be used by format conversion methods (dmxconvert)
  179. CUtlSymbolLarge GetType() const;
  180. const char * GetTypeString() const;
  181. const char * GetName() const;
  182. const DmObjectId_t& GetId() const;
  183. void SetType( const char *pType );
  184. void SetName( const char* pName );
  185. // Attribute management
  186. CDmAttribute * AddAttribute( const char *pAttributeName, DmAttributeType_t type );
  187. template< class E > CDmAttribute* AddAttributeElement( const char *pAttributeName );
  188. template< class E > CDmAttribute* AddAttributeElementArray( const char *pAttributeName );
  189. void RemoveAttribute( const char *pAttributeName );
  190. void RemoveAttributeByPtr( CDmAttribute *pAttributeName );
  191. void RenameAttribute( const char *pAttributeName, const char *pNewName );
  192. // get attribute value
  193. template< class T > const T& GetValue( const char *pAttributeName ) const;
  194. template< class T > const T& GetValue( const char *pAttributeName, const T& defaultValue ) const;
  195. const char * GetValueString( const char *pAttributeName ) const;
  196. template< class E > E* GetValueElement( const char *pAttributeName ) const;
  197. // set attribute value
  198. CDmAttribute* SetValue( const char *pAttributeName, const void *value, size_t size, bool bCreateIfNotFound = true );
  199. template< class T > CDmAttribute* SetValue( const char *pAttributeName, const T& value, bool bCreateIfNotFound = true );
  200. template< class E > CDmAttribute* SetValue( const char *pAttributeName, E* value, bool bCreateIfNotFound = true );
  201. // set attribute value if the attribute doesn't already exist
  202. CDmAttribute* InitValue( const char *pAttributeName, const void *value, size_t size );
  203. template< class T > CDmAttribute* InitValue( const char *pAttributeName, const T& value );
  204. template< class E > CDmAttribute* InitValue( const char *pAttributeName, E* value );
  205. // Parses an attribute from a string
  206. // Doesn't create an attribute if it doesn't exist and always preserves attribute type
  207. void SetValueFromString( const char *pAttributeName, const char *value );
  208. const char *GetValueAsString( const char *pAttributeName, char *pBuffer, size_t buflen ) const;
  209. // Helpers for our RTTI
  210. template< class E > bool IsA() const;
  211. bool IsA( const char *pTypeName ) const;
  212. int GetInheritanceDepth( const char *pTypeName ) const;
  213. static CUtlSymbolLarge GetStaticTypeSymbol();
  214. // Indicates whether this element should be copied or not
  215. void SetShared( bool bShared );
  216. bool IsShared() const;
  217. // Copies an element and all its attributes
  218. CDmElement* Copy( TraversalDepth_t depth = TD_DEEP ) const;
  219. // Copies attributes from a specified element
  220. void CopyAttributesTo( CDmElement *pCopy, TraversalDepth_t depth = TD_DEEP ) const;
  221. // recursively set fileid's, with option to only change elements in the matched file
  222. void SetFileId( DmFileId_t fileid, TraversalDepth_t depth, bool bOnlyIfMatch = false );
  223. DmFileId_t GetFileId() const;
  224. bool GetParity( int bit = 0 ) const;
  225. void SetParity( bool bParity, int bit = 0 );
  226. void SetParity( bool bParity, TraversalDepth_t depth, int bit = 0 ); // assumes that all elements that should be traversed have a parity of !bParity
  227. bool IsOnlyInUndo() const;
  228. void SetOnlyInUndo( bool bOnlyInUndo );
  229. // returns the first path to the element found traversing all element/element
  230. // array attributes - not necessarily the shortest.
  231. // cycle-safe (skips any references to elements in the current path)
  232. // but may re-traverse elements via different paths
  233. bool FindElement( const CDmElement *pElement, CUtlVector< ElementPathItem_t > &elementPath, TraversalDepth_t depth ) const;
  234. bool FindReferer( DmElementHandle_t hElement, CUtlVector< ElementPathItem_t > &elementPath, TraversalDepth_t depth ) const;
  235. void RemoveAllReferencesToElement( CDmElement *pElement );
  236. bool IsStronglyReferenced() { return m_ref.IsStronglyReferenced(); }
  237. // Estimates the memory usage of the element, its attributes, and child elements
  238. int EstimateMemoryUsage( TraversalDepth_t depth = TD_DEEP );
  239. // mostly used for internal stuff, but it's occasionally useful to mark yourself dirty...
  240. bool IsDirty() const;
  241. void MarkDirty( bool dirty = true );
  242. protected:
  243. // NOTE: These are protected to ensure that the factory is the only thing that can create these
  244. CDmElement( DmElementHandle_t handle, const char *objectType, const DmObjectId_t &id, const char *objectName, DmFileId_t fileid );
  245. virtual ~CDmElement();
  246. // Used by derived classes to do construction and setting up CDmaVars
  247. void OnConstruction() { }
  248. void OnDestruction() { }
  249. virtual void PerformConstruction();
  250. virtual void PerformDestruction();
  251. virtual void OnAdoptedFromUndo() {}
  252. virtual void OnOrphanedToUndo() {}
  253. // Internal methods related to RTII
  254. static void SetTypeSymbol( CUtlSymbolLarge sym );
  255. static bool IsA_Implementation( CUtlSymbolLarge typeSymbol );
  256. static int GetInheritanceDepth_Implementation( CUtlSymbolLarge typeSymbol, int nCurrentDepth );
  257. // Internal method for creating a copy of this element
  258. CDmElement* CopyInternal( TraversalDepth_t depth = TD_DEEP ) const;
  259. // helper for making attributevarelementarray cleanup easier
  260. template< class T > static void DeleteAttributeVarElementArray( T &array );
  261. private:
  262. typedef CUtlMap< DmElementHandle_t, DmElementHandle_t, int > CRefMap;
  263. // Bogus constructor
  264. CDmElement();
  265. // internal recursive copy method - builds refmap of old element's handle -> copy's handle, and uses it to fixup references
  266. void CopyAttributesTo( CDmElement *pCopy, CRefMap &refmap, TraversalDepth_t depth ) const;
  267. void CopyElementAttribute( const CDmAttribute *pAttr, CDmAttribute *pCopyAttr, CRefMap &refmap, TraversalDepth_t depth ) const;
  268. void CopyElementArrayAttribute( const CDmAttribute *pAttr, CDmAttribute *pCopyAttr, CRefMap &refmap, TraversalDepth_t depth ) const;
  269. void FixupReferences( CUtlHashFast< DmElementHandle_t > &visited, const CRefMap &refmap, TraversalDepth_t depth );
  270. void SetFileId( DmFileId_t fileid );
  271. void SetFileId_R( CUtlHashFast< DmElementHandle_t > &visited, DmFileId_t fileid, TraversalDepth_t depth, DmFileId_t match, bool bOnlyIfMatch );
  272. CDmAttribute* CreateAttribute( const char *pAttributeName, DmAttributeType_t type );
  273. void RemoveAttribute( CDmAttribute **pAttrRef );
  274. CDmAttribute* AddExternalAttribute( const char *pAttributeName, DmAttributeType_t type, void *pMemory );
  275. CDmAttribute *FindAttribute( const char *pAttributeName ) const;
  276. void Purge();
  277. void SetId( const DmObjectId_t &id );
  278. void MarkAttributesClean();
  279. void DisableOnChangedCallbacks();
  280. void EnableOnChangedCallbacks();
  281. bool AreOnChangedCallbacksEnabled();
  282. void FinishUnserialization();
  283. // Used by the undo system only.
  284. void AddAttributeByPtr( CDmAttribute *ptr );
  285. void RemoveAttributeByPtrNoDelete( CDmAttribute *ptr );
  286. // Should only be called from datamodel, who will take care of changing the fileset entry as well
  287. void ChangeHandle( DmElementHandle_t handle );
  288. // returns element reference struct w/ list of referrers and handle count
  289. DmElementReference_t* GetReference();
  290. void SetReference( const DmElementReference_t &ref );
  291. // Estimates memory usage
  292. int EstimateMemoryUsage( CUtlHash< DmElementHandle_t > &visited, TraversalDepth_t depth, int *pCategories );
  293. private:
  294. DmObjectId_t m_Id; // UUID's like to be quad-aligned
  295. protected:
  296. CDmaString m_Name;
  297. private:
  298. DmElementReference_t m_ref;
  299. CDmAttribute *m_pAttributes;
  300. CUtlSymbolLarge m_Type;
  301. DmFileId_t m_fileId;
  302. bool m_bDirty : 1;
  303. bool m_bOnChangedCallbacksEnabled : 1;
  304. bool m_bOnlyInUndo : 1; // only accessibly from the undo system
  305. uint m_nParityBits : 28; // used as temporary state during traversal to avoid searching
  306. // Stores the type symbol
  307. static CUtlSymbolLarge m_classType;
  308. // Factories can access our constructors
  309. template <class T> friend class CDmElementFactory;
  310. template <class T> friend class CDmAbstractElementFactory;
  311. template< class T > friend class CDmaVar;
  312. template< class T > friend class CDmaArray;
  313. template< class T > friend class CDmaElementArray;
  314. template< class T, class B > friend class CDmaDecorator;
  315. template< class T > friend class CDmrElementArray;
  316. friend class CDmElementFactoryDefault;
  317. friend class CDmeElementAccessor;
  318. friend class CDmeOperator;
  319. template< class T >
  320. friend void CopyElements( const CUtlVector< T* > &from, CUtlVector< T* > &to, TraversalDepth_t depth );
  321. DECLARE_FIXEDSIZE_ALLOCATOR( CDmElement );
  322. typedef CDmElement BaseClass; // only CDmElement has itself as it's BaseClass - this lets us know we're at the top of the hierarchy
  323. };
  324. //-----------------------------------------------------------------------------
  325. // Fast dynamic cast
  326. //-----------------------------------------------------------------------------
  327. template< class E >
  328. inline E *CastElement( CDmElement *pElement )
  329. {
  330. if ( pElement && pElement->IsA( E::GetStaticTypeSymbol() ) )
  331. return static_cast< E* >( pElement );
  332. return NULL;
  333. }
  334. template< class E >
  335. inline const E *CastElement( const CDmElement *pElement )
  336. {
  337. if ( pElement && pElement->IsA( E::GetStaticTypeSymbol() ) )
  338. return static_cast< const E* >( pElement );
  339. return NULL;
  340. }
  341. //-----------------------------------------------------------------------------
  342. // Constant fast dynamic cast
  343. //-----------------------------------------------------------------------------
  344. template< class E >
  345. const inline E *CastElementConst( const CDmElement *pElement )
  346. {
  347. if ( pElement && pElement->IsA( E::GetStaticTypeSymbol() ) )
  348. return static_cast< const E* >( pElement );
  349. return NULL;
  350. }
  351. //-----------------------------------------------------------------------------
  352. // type-safe element creation and accessor helpers - infers type name string from actual type
  353. //-----------------------------------------------------------------------------
  354. template< class E >
  355. inline E *GetElement( DmElementHandle_t hElement )
  356. {
  357. CDmElement *pElement = g_pDataModel->GetElement( hElement );
  358. return CastElement< E >( pElement );
  359. }
  360. //-----------------------------------------------------------------------------
  361. // Typesafe element creation + destruction
  362. //-----------------------------------------------------------------------------
  363. template< class E >
  364. inline E *CreateElement( const char *pObjectName, DmFileId_t fileid, const DmObjectId_t *pObjectID = NULL )
  365. {
  366. return GetElement< E >( g_pDataModel->CreateElement( E::GetStaticTypeSymbol(), pObjectName, fileid, pObjectID ) );
  367. }
  368. template< class E >
  369. inline E *CreateElement( const char *pElementType, const char *pObjectName, DmFileId_t fileid, const DmObjectId_t *pObjectID = NULL )
  370. {
  371. return GetElement< E >( g_pDataModel->CreateElement( pElementType, pObjectName, fileid, pObjectID ) );
  372. }
  373. inline void DestroyElement( CDmElement *pElement )
  374. {
  375. if ( pElement )
  376. {
  377. g_pDataModel->DestroyElement( pElement->GetHandle() );
  378. }
  379. }
  380. void DestroyElement( CDmElement *pElement, TraversalDepth_t depth );
  381. //-----------------------------------------------------------------------------
  382. // allows elements to chain OnAttributeChanged up to their parents (or at least, referrers)
  383. //-----------------------------------------------------------------------------
  384. void InvokeOnAttributeChangedOnReferrers( DmElementHandle_t hElement, CDmAttribute *pChangedAttr );
  385. //-----------------------------------------------------------------------------
  386. // Gets attributes
  387. //-----------------------------------------------------------------------------
  388. inline CDmAttribute *CDmElement::GetAttribute( const char *pAttributeName, DmAttributeType_t type )
  389. {
  390. CDmAttribute *pAttribute = FindAttribute( pAttributeName );
  391. if ( ( type != AT_UNKNOWN ) && pAttribute && ( pAttribute->GetType() != type ) )
  392. return NULL;
  393. return pAttribute;
  394. }
  395. inline const CDmAttribute *CDmElement::GetAttribute( const char *pAttributeName, DmAttributeType_t type ) const
  396. {
  397. CDmAttribute *pAttribute = FindAttribute( pAttributeName );
  398. if ( ( type != AT_UNKNOWN ) && pAttribute && ( pAttribute->GetType() != type ) )
  399. return NULL;
  400. return pAttribute;
  401. }
  402. //-----------------------------------------------------------------------------
  403. // AddAttribute calls
  404. //-----------------------------------------------------------------------------
  405. inline CDmAttribute *CDmElement::AddAttribute( const char *pAttributeName, DmAttributeType_t type )
  406. {
  407. CDmAttribute *pAttribute = FindAttribute( pAttributeName );
  408. if ( pAttribute )
  409. return ( pAttribute->GetType() == type ) ? pAttribute : NULL;
  410. pAttribute = CreateAttribute( pAttributeName, type );
  411. return pAttribute;
  412. }
  413. template< class E > inline CDmAttribute *CDmElement::AddAttributeElement( const char *pAttributeName )
  414. {
  415. CDmAttribute *pAttribute = AddAttribute( pAttributeName, AT_ELEMENT );
  416. if ( !pAttribute )
  417. return NULL;
  418. // FIXME: If the attribute exists but has a different element type symbol, should we complain?
  419. pAttribute->SetElementTypeSymbol( E::GetStaticTypeSymbol() );
  420. return pAttribute;
  421. }
  422. template< class E > inline CDmAttribute *CDmElement::AddAttributeElementArray( const char *pAttributeName )
  423. {
  424. CDmAttribute *pAttribute = AddAttribute( pAttributeName, AT_ELEMENT_ARRAY );
  425. if ( !pAttribute )
  426. return NULL;
  427. // FIXME: If the attribute exists but has a different element type symbol, should we complain?
  428. pAttribute->SetElementTypeSymbol( E::GetStaticTypeSymbol() );
  429. return pAttribute;
  430. }
  431. //-----------------------------------------------------------------------------
  432. // GetValue methods
  433. //-----------------------------------------------------------------------------
  434. template< class T >
  435. inline const T& CDmElement::GetValue( const char *pAttributeName, const T& defaultVal ) const
  436. {
  437. const CDmAttribute *pAttribute = FindAttribute( pAttributeName );
  438. if ( pAttribute != NULL )
  439. return pAttribute->GetValue<T>();
  440. return defaultVal;
  441. }
  442. template< class T >
  443. inline const T& CDmElement::GetValue( const char *pAttributeName ) const
  444. {
  445. static CDmaVar<T> defaultVal;
  446. return GetValue( pAttributeName, defaultVal.Get() );
  447. }
  448. inline const char *CDmElement::GetValueString( const char *pAttributeName ) const
  449. {
  450. CUtlSymbolLarge symbol = GetValue<CUtlSymbolLarge>( pAttributeName );
  451. if ( symbol == UTL_INVAL_SYMBOL_LARGE )
  452. return NULL;
  453. return symbol.String();
  454. }
  455. template< class E >
  456. inline E* CDmElement::GetValueElement( const char *pAttributeName ) const
  457. {
  458. DmElementHandle_t h = GetValue< DmElementHandle_t >( pAttributeName );
  459. return GetElement<E>( h );
  460. }
  461. //-----------------------------------------------------------------------------
  462. // SetValue methods
  463. //-----------------------------------------------------------------------------
  464. template< class T >
  465. inline CDmAttribute* CDmElement::SetValue( const char *pAttributeName, const T& value, bool bCreateIfNotFound /*= true*/ )
  466. {
  467. CDmAttribute *pAttribute = FindAttribute( pAttributeName );
  468. if ( !pAttribute && bCreateIfNotFound )
  469. {
  470. pAttribute = CreateAttribute( pAttributeName, CDmAttributeInfo<T>::AttributeType() );
  471. }
  472. if ( pAttribute )
  473. {
  474. pAttribute->SetValue( value );
  475. return pAttribute;
  476. }
  477. return NULL;
  478. }
  479. template< class E >
  480. inline CDmAttribute* CDmElement::SetValue( const char *pAttributeName, E* pElement, bool bCreateIfNotFound /*= true*/ )
  481. {
  482. DmElementHandle_t hElement = pElement ? pElement->GetHandle() : DMELEMENT_HANDLE_INVALID;
  483. return SetValue( pAttributeName, hElement, bCreateIfNotFound );
  484. }
  485. template<>
  486. inline CDmAttribute* CDmElement::SetValue( const char *pAttributeName, const char *pValue, bool bCreateIfNotFound /*= true*/ )
  487. {
  488. // We don't want to add any extra entries into the string table so if bCreateIfNotFound is
  489. // false, then check to see if the attribute exists before adding the string to the table.
  490. if ( !bCreateIfNotFound )
  491. {
  492. if ( HasAttribute( pAttributeName, AT_STRING ) == false )
  493. return NULL;
  494. }
  495. CUtlSymbolLarge symbol = g_pDataModel->GetSymbol( pValue );
  496. return SetValue( pAttributeName, symbol );
  497. }
  498. template<>
  499. inline CDmAttribute* CDmElement::SetValue( const char *pAttributeName, char *pValue, bool bCreateIfNotFound /*= true*/ )
  500. {
  501. return SetValue( pAttributeName, (const char *)pValue, bCreateIfNotFound );
  502. }
  503. inline CDmAttribute* CDmElement::SetValue( const char *pAttributeName, const void *pValue, size_t nSize, bool bCreateIfNotFound /*= true*/ )
  504. {
  505. CUtlBinaryBlock buf( pValue, nSize );
  506. return SetValue( pAttributeName, buf, bCreateIfNotFound );
  507. }
  508. //-----------------------------------------------------------------------------
  509. // AddValue methods( set value if not found )
  510. //-----------------------------------------------------------------------------
  511. template< class T >
  512. inline CDmAttribute* CDmElement::InitValue( const char *pAttributeName, const T& value )
  513. {
  514. CDmAttribute *pAttribute = GetAttribute( pAttributeName );
  515. if ( !pAttribute )
  516. return SetValue( pAttributeName, value );
  517. return pAttribute;
  518. }
  519. template< class E >
  520. inline CDmAttribute* CDmElement::InitValue( const char *pAttributeName, E* pElement )
  521. {
  522. DmElementHandle_t hElement = pElement ? pElement->GetHandle() : DMELEMENT_HANDLE_INVALID;
  523. return InitValue( pAttributeName, hElement );
  524. }
  525. template<>
  526. inline CDmAttribute* CDmElement::InitValue( const char *pAttributeName, const char *pValue )
  527. {
  528. CUtlSymbolLarge symbol = g_pDataModel->GetSymbol( pValue );
  529. return InitValue( pAttributeName, symbol );
  530. }
  531. inline CDmAttribute* CDmElement::InitValue( const char *pAttributeName, const void *pValue, size_t size )
  532. {
  533. CDmAttribute *pAttribute = GetAttribute( pAttributeName );
  534. if ( !pAttribute )
  535. return SetValue( pAttributeName, pValue, size );
  536. return pAttribute;
  537. }
  538. //-----------------------------------------------------------------------------
  539. // Returns the type, name, id, fileId
  540. //-----------------------------------------------------------------------------
  541. inline CUtlSymbolLarge CDmElement::GetType() const
  542. {
  543. return m_Type;
  544. }
  545. inline const char *CDmElement::GetTypeString() const
  546. {
  547. return m_Type.String();
  548. }
  549. inline const char *CDmElement::GetName() const
  550. {
  551. return m_Name.Get();
  552. }
  553. inline void CDmElement::SetName( const char* pName )
  554. {
  555. m_Name.Set( pName );
  556. }
  557. inline const DmObjectId_t& CDmElement::GetId() const
  558. {
  559. return m_Id;
  560. }
  561. inline DmFileId_t CDmElement::GetFileId() const
  562. {
  563. return m_fileId;
  564. }
  565. //-----------------------------------------------------------------------------
  566. // Controls whether the element should be copied by default
  567. //-----------------------------------------------------------------------------
  568. inline void CDmElement::SetShared( bool bShared )
  569. {
  570. if ( bShared )
  571. {
  572. SetValue< bool >( "shared", true );
  573. }
  574. else
  575. {
  576. RemoveAttribute( "shared" );
  577. }
  578. }
  579. inline bool CDmElement::IsShared() const
  580. {
  581. return GetValue< bool >( "shared" ); // if attribute doesn't exist, returns default bool value, which is false
  582. }
  583. //-----------------------------------------------------------------------------
  584. // Copies attributes from a specified element
  585. //-----------------------------------------------------------------------------
  586. inline CDmElement* CDmElement::Copy( TraversalDepth_t depth ) const
  587. {
  588. return CopyInternal( depth );
  589. }
  590. //-----------------------------------------------------------------------------
  591. // RTTI
  592. //-----------------------------------------------------------------------------
  593. inline bool CDmElement::IsA_Implementation( CUtlSymbolLarge typeSymbol )
  594. {
  595. return ( m_classType == typeSymbol ) || ( UTL_INVAL_SYMBOL_LARGE == typeSymbol );
  596. }
  597. inline int CDmElement::GetInheritanceDepth_Implementation( CUtlSymbolLarge typeSymbol, int nCurrentDepth )
  598. {
  599. return IsA_Implementation( typeSymbol ) ? nCurrentDepth : -1;
  600. }
  601. inline CUtlSymbolLarge CDmElement::GetStaticTypeSymbol()
  602. {
  603. return m_classType;
  604. }
  605. inline bool CDmElement::IsA( const char *pTypeName ) const
  606. {
  607. CUtlSymbolLarge typeSymbol = g_pDataModel->GetSymbol( pTypeName );
  608. return IsA( typeSymbol );
  609. }
  610. template< class E > inline bool CDmElement::IsA() const
  611. {
  612. return IsA( E::GetStaticTypeSymbol() );
  613. }
  614. //-----------------------------------------------------------------------------
  615. // Helper for finding elements that refer to this element
  616. //-----------------------------------------------------------------------------
  617. class CAttributeReferenceIterator
  618. {
  619. public:
  620. explicit CAttributeReferenceIterator( const CDmElement *pElement ) :
  621. m_curr ( pElement ? g_pDataModel->FirstAttributeReferencingElement( pElement->GetHandle() ) : DMATTRIBUTE_REFERENCE_ITERATOR_INVALID ),
  622. m_fileid( pElement ? pElement->GetFileId() : DMFILEID_INVALID )
  623. {
  624. }
  625. operator bool() const { return m_curr != DMATTRIBUTE_REFERENCE_ITERATOR_INVALID; }
  626. CDmAttribute* operator*() const { return GetAttribute(); }
  627. CDmAttribute *GetAttribute() const { return g_pDataModel->GetAttribute( m_curr ); }
  628. CDmElement *GetOwner() const { if ( CDmAttribute *pAttr = GetAttribute() ) return pAttr->GetOwner(); return NULL; }
  629. CAttributeReferenceIterator& operator++() // prefix
  630. {
  631. m_curr = g_pDataModel->NextAttributeReferencingElement( m_curr );
  632. return *this;
  633. }
  634. CAttributeReferenceIterator operator++( int ) // postfix
  635. {
  636. CAttributeReferenceIterator prev = *this;
  637. m_curr = g_pDataModel->NextAttributeReferencingElement( m_curr );
  638. return prev;
  639. }
  640. template< class T >
  641. T *FilterReference( CUtlSymbolLarge symAttrName = UTL_INVAL_SYMBOL_LARGE, bool bMustBeInSameFile = false, TraversalDepth_t depth = TD_ALL ) const
  642. {
  643. CDmAttribute *pAttribute = g_pDataModel->GetAttribute( m_curr );
  644. Assert( pAttribute );
  645. if ( !pAttribute )
  646. return NULL;
  647. if ( !ShouldTraverse( pAttribute, depth ) )
  648. return NULL;
  649. T *pParent = CastElement< T >( pAttribute->GetOwner() );
  650. if ( !pParent )
  651. return NULL;
  652. if ( symAttrName != UTL_INVAL_SYMBOL_LARGE && pAttribute->GetNameSymbol() != symAttrName )
  653. return NULL;
  654. if ( bMustBeInSameFile && ( pParent->GetFileId() != m_fileid ) )
  655. return NULL;
  656. return pParent;
  657. }
  658. private:
  659. DmAttributeReferenceIterator_t m_curr;
  660. DmFileId_t m_fileid;
  661. };
  662. template< class T >
  663. T *FindReferringElement( const CDmElement *pElement, const char *pAttrName = NULL, bool bMustBeInSameFile = true, TraversalDepth_t depth = TD_ALL )
  664. {
  665. CUtlSymbolLarge sym = pAttrName ? g_pDataModel->GetSymbol( pAttrName ) : (CUtlSymbolLarge)UTL_INVAL_SYMBOL_LARGE;
  666. return FindReferringElement< T >( pElement, sym, bMustBeInSameFile, depth );
  667. }
  668. template< class T >
  669. T *FindReferringElement( const CDmElement *pElement, CUtlSymbolLarge symAttrName = UTL_INVAL_SYMBOL_LARGE, bool bMustBeInSameFile = true, TraversalDepth_t depth = TD_ALL )
  670. {
  671. for ( CAttributeReferenceIterator it( pElement ); it; ++it )
  672. {
  673. if ( T *pParent = it.FilterReference< T >( symAttrName, bMustBeInSameFile, depth ) )
  674. return pParent;
  675. }
  676. return NULL;
  677. }
  678. template< class T >
  679. bool FindReferringElements( CUtlVector< T * >& list, const CDmElement *pElement, CUtlSymbolLarge symAttrName, bool bMustBeInSameFile = true, TraversalDepth_t depth = TD_ALL )
  680. {
  681. for ( CAttributeReferenceIterator it( pElement ); it; ++it )
  682. {
  683. if ( T *pParent = it.FilterReference< T >( symAttrName, bMustBeInSameFile, depth ) )
  684. {
  685. list.AddToTail( pParent );
  686. }
  687. }
  688. return list.Count() > 0;
  689. }
  690. void RemoveElementFromRefereringAttributes( CDmElement *pElement, bool bPreserveOrder = true );
  691. template< class T >
  692. void FindAncestorsReferencingElement( const CDmElement *target, CUtlVector< T* >& list )
  693. {
  694. FindReferringElements( list, target, UTL_INVAL_SYMBOL_LARGE, false );
  695. }
  696. template< class T >
  697. T *FindAncestorReferencingElement( const CDmElement *target )
  698. {
  699. return FindReferringElement< T >( target, UTL_INVAL_SYMBOL_LARGE, false );
  700. }
  701. template< class T >
  702. T *FindAncestorReferencingElement_R_Impl( CUtlRBTree< CDmElement * >& visited, CDmElement *check )
  703. {
  704. if ( visited.Find( check ) != visited.InvalidIndex() )
  705. return NULL;
  706. visited.Insert( check );
  707. // Pass one, see if it's in this ancestor list
  708. for ( CAttributeReferenceIterator it( check ); it; ++it )
  709. {
  710. if ( T *pParent = it.FilterReference< T >() )
  711. return pParent;
  712. }
  713. for ( CAttributeReferenceIterator it( check ); it; ++it )
  714. {
  715. if ( CDmElement *pParent = it.GetOwner() )
  716. {
  717. T *found = FindAncestorReferencingElement_R_Impl< T >( visited, pParent );
  718. if ( found )
  719. return found;
  720. }
  721. }
  722. return NULL;
  723. }
  724. template< class T >
  725. T *FindAncestorReferencingElement_R( CDmElement *target )
  726. {
  727. if ( !target )
  728. return NULL;
  729. CUtlRBTree< CDmElement * > visited( 0, 0, DefLessFunc( CDmElement * ) );
  730. return FindAncestorReferencingElement_R_Impl< T >( visited, target );
  731. }
  732. // finds elements of type T that indirectly reference pElement
  733. template< class T >
  734. void FindAncestorsOfElement_Impl( CUtlRBTree< CDmElement * >& visited, CDmElement *pElement, CUtlVector< T* > &ancestors, bool bRecursePastFoundAncestors )
  735. {
  736. // Pass one, see if it's in this ancestor list
  737. for ( CAttributeReferenceIterator it( pElement ); it; ++it )
  738. {
  739. if ( CDmElement *pParent = it.GetOwner() )
  740. {
  741. if ( visited.Find( pParent ) != visited.InvalidIndex() )
  742. continue;
  743. visited.Insert( pParent );
  744. if ( T *pT = CastElement< T >( pParent ) )
  745. {
  746. ancestors.AddToTail( pT );
  747. if ( !bRecursePastFoundAncestors )
  748. continue;
  749. }
  750. FindAncestorsOfElement_Impl( visited, pParent, ancestors, bRecursePastFoundAncestors );
  751. }
  752. }
  753. }
  754. // finds elements of type T that indirectly reference pElement
  755. template< class T >
  756. void FindAncestorsOfElement( CDmElement *pElement, CUtlVector< T* > &ancestors, bool bRecursePastFoundAncestors )
  757. {
  758. if ( !pElement )
  759. return;
  760. CUtlRBTree< CDmElement * > visited( 0, 0, DefLessFunc( CDmElement * ) );
  761. FindAncestorsOfElement_Impl< T >( visited, pElement, ancestors, bRecursePastFoundAncestors );
  762. }
  763. //-----------------------------------------------------------------------------
  764. //
  765. // generic element tree traversal helper class
  766. //
  767. //-----------------------------------------------------------------------------
  768. class CElementTreeTraversal
  769. {
  770. public:
  771. CElementTreeTraversal( CDmElement *pRoot, const char *pAttrName );
  772. enum { NOT_VISITED = -2, VISITING = -1 };
  773. void Reset( CDmElement *pRoot, const char *pAttrName );
  774. bool IsValid() { return m_state.Count() > 0; }
  775. CDmElement *Next( bool bSkipChildren = false );
  776. int CurrentDepth() { return m_state.Count() - 1; }
  777. CDmElement *GetElement();
  778. CDmElement *GetParent ( int i );
  779. int GetChildIndex( int i );
  780. private:
  781. struct State_t
  782. {
  783. State_t( CDmElement *p, int i ) : pElement( p ), nIndex( i ) {}
  784. CDmElement *pElement;
  785. int nIndex; // -2: not yet visited, -1: visiting self, 0+: visiting children
  786. };
  787. CUtlVector< State_t > m_state;
  788. const char *m_pAttrName;
  789. };
  790. //-----------------------------------------------------------------------------
  791. //
  792. // element-specific unique name generation methods
  793. //
  794. //-----------------------------------------------------------------------------
  795. template< class T >
  796. struct ElementArrayNameAccessor
  797. {
  798. ElementArrayNameAccessor( const CUtlVector< T > &array ) : m_array( array ) {}
  799. int Count() const
  800. {
  801. return m_array.Count();
  802. }
  803. const char *operator[]( int i ) const
  804. {
  805. CDmElement *pElement = GetElement< CDmElement >( m_array[ i ] );
  806. return pElement ? pElement->GetName() : NULL;
  807. }
  808. private:
  809. const CUtlVector< T > &m_array;
  810. };
  811. template< class E >
  812. struct ElementArrayNameAccessor< E* >
  813. {
  814. ElementArrayNameAccessor( const CUtlVector< E* > &array ) : m_array( array ) {}
  815. int Count() const
  816. {
  817. return m_array.Count();
  818. }
  819. const char *operator[]( int i ) const
  820. {
  821. E *pElement = m_array[ i ];
  822. return pElement ? pElement->GetName() : NULL;
  823. }
  824. private:
  825. const CUtlVector< E* > &m_array;
  826. };
  827. // returns startindex if none found, 2 if only "prefix" found, and n+1 if "prefixn" found
  828. int GenerateUniqueNameIndex( const char *prefix, const CUtlVector< DmElementHandle_t > &array, int startindex = 0 );
  829. bool GenerateUniqueName( char *name, int memsize, const char *prefix, const CUtlVector< DmElementHandle_t > &array );
  830. int SplitStringIntoBaseAndIntegerSuffix( const char *pName, int len, char *pBaseName );
  831. void MakeElementNameUnique( CDmElement *pElement, const CUtlVector< DmElementHandle_t > &array );
  832. //-----------------------------------------------------------------------------
  833. // helper for making attributevarelementarray cleanup easier
  834. //-----------------------------------------------------------------------------
  835. template< class T >
  836. inline void CDmElement::DeleteAttributeVarElementArray( T &array )
  837. {
  838. int nElements = array.Count();
  839. for ( int i = 0; i < nElements; ++i )
  840. {
  841. g_pDataModel->DestroyElement( array.GetHandle( i ) );
  842. }
  843. array.RemoveAll();
  844. }
  845. //-----------------------------------------------------------------------------
  846. // Default size computation
  847. //-----------------------------------------------------------------------------
  848. template< class T >
  849. int DmeEstimateMemorySize( T* pElement )
  850. {
  851. return sizeof( T );
  852. }
  853. //-----------------------------------------------------------------------------
  854. // copy groups of elements together so that references between them are maintained
  855. //-----------------------------------------------------------------------------
  856. template< class T >
  857. void CopyElements( const CUtlVector< T* > &from, CUtlVector< T* > &to, TraversalDepth_t depth = TD_DEEP )
  858. {
  859. CDisableUndoScopeGuard sg;
  860. CUtlMap< DmElementHandle_t, DmElementHandle_t, int > refmap( DefLessFunc( DmElementHandle_t ) );
  861. int c = from.Count();
  862. for ( int i = 0; i < c; ++i )
  863. {
  864. T *pCopy = NULL;
  865. if ( CDmElement *pFrom = from[ i ] )
  866. {
  867. int idx = refmap.Find( pFrom->GetHandle() );
  868. if ( idx != refmap.InvalidIndex() )
  869. {
  870. pCopy = GetElement< T >( refmap[ idx ] );
  871. }
  872. else
  873. {
  874. pCopy = GetElement< T >( g_pDataModel->CreateElement( pFrom->GetType(), pFrom->GetName(), pFrom->GetFileId() ) );
  875. if ( pCopy )
  876. {
  877. pFrom->CopyAttributesTo( pCopy, refmap, depth );
  878. }
  879. }
  880. }
  881. to.AddToTail( pCopy );
  882. }
  883. CUtlHashFast< DmElementHandle_t > visited;
  884. uint nPow2Size = 1;
  885. while( nPow2Size < refmap.Count() )
  886. {
  887. nPow2Size <<= 1;
  888. }
  889. visited.Init( nPow2Size );
  890. for ( int i = 0; i < c; ++i )
  891. {
  892. CDmElement *pTo = to[ i ];
  893. if ( !pTo )
  894. continue;
  895. to[ i ]->FixupReferences( visited, refmap, depth );
  896. }
  897. }
  898. //-----------------------------------------------------------------------------
  899. // Helper macro to create an element; this is used for elements that are helper base classes
  900. //-----------------------------------------------------------------------------
  901. #define DEFINE_UNINSTANCEABLE_ELEMENT( className, baseClassName ) \
  902. protected: \
  903. className( DmElementHandle_t handle, const char *pElementTypeName, const DmObjectId_t &id, const char *pElementName, DmFileId_t fileid ) : \
  904. baseClassName( handle, pElementTypeName, id, pElementName, fileid ) \
  905. { \
  906. } \
  907. virtual ~className() \
  908. { \
  909. } \
  910. void OnConstruction(); \
  911. void OnDestruction(); \
  912. virtual void PerformConstruction() \
  913. { \
  914. BaseClass::PerformConstruction(); \
  915. OnConstruction(); \
  916. } \
  917. virtual void PerformDestruction() \
  918. { \
  919. OnDestruction(); \
  920. BaseClass::PerformDestruction(); \
  921. } \
  922. virtual int AllocatedSize() const { return DmeEstimateMemorySize( this ); } \
  923. \
  924. private: \
  925. typedef baseClassName BaseClass; \
  926. //-----------------------------------------------------------------------------
  927. // Helper macro to create the class factory
  928. //-----------------------------------------------------------------------------
  929. #define DEFINE_ELEMENT( className, baseClassName ) \
  930. public: \
  931. virtual bool IsA( CUtlSymbolLarge typeSymbol ) const \
  932. { \
  933. return IsA_Implementation( typeSymbol );\
  934. } \
  935. \
  936. bool IsA( const char *pTypeName ) const \
  937. { \
  938. CUtlSymbolLarge typeSymbol = g_pDataModel->GetSymbol( pTypeName ); \
  939. return IsA( typeSymbol ); \
  940. } \
  941. \
  942. template< class T > bool IsA() const \
  943. { \
  944. return IsA( T::GetStaticTypeSymbol() ); \
  945. } \
  946. \
  947. virtual int GetInheritanceDepth( CUtlSymbolLarge typeSymbol ) const \
  948. { \
  949. return GetInheritanceDepth_Implementation( typeSymbol, 0 ); \
  950. } \
  951. \
  952. static CUtlSymbolLarge GetStaticTypeSymbol( ) \
  953. { \
  954. return m_classType; \
  955. } \
  956. \
  957. className* Copy( TraversalDepth_t depth = TD_DEEP ) const \
  958. { \
  959. return static_cast< className* >( CopyInternal( depth ) ); \
  960. } \
  961. protected: \
  962. className( DmElementHandle_t handle, const char *pElementTypeName, const DmObjectId_t &id, const char *pElementName, DmFileId_t fileid ) : \
  963. baseClassName( handle, pElementTypeName, id, pElementName, fileid ) \
  964. { \
  965. } \
  966. virtual ~className() \
  967. { \
  968. } \
  969. void OnConstruction(); \
  970. void OnDestruction(); \
  971. virtual void PerformConstruction() \
  972. { \
  973. BaseClass::PerformConstruction(); \
  974. OnConstruction(); \
  975. } \
  976. virtual void PerformDestruction() \
  977. { \
  978. OnDestruction(); \
  979. BaseClass::PerformDestruction(); \
  980. } \
  981. static void SetTypeSymbol( CUtlSymbolLarge typeSymbol ) \
  982. { \
  983. m_classType = typeSymbol; \
  984. } \
  985. \
  986. static bool IsA_Implementation( CUtlSymbolLarge typeSymbol ) \
  987. { \
  988. if ( typeSymbol == m_classType ) \
  989. return true; \
  990. return BaseClass::IsA_Implementation( typeSymbol ); \
  991. } \
  992. \
  993. static int GetInheritanceDepth_Implementation( CUtlSymbolLarge typeSymbol, int nCurrentDepth ) \
  994. { \
  995. if ( typeSymbol == m_classType ) \
  996. return nCurrentDepth; \
  997. return BaseClass::GetInheritanceDepth_Implementation( typeSymbol, nCurrentDepth+1 );\
  998. } \
  999. virtual int AllocatedSize() const { return DmeEstimateMemorySize( this ); } \
  1000. \
  1001. private: \
  1002. DECLARE_FIXEDSIZE_ALLOCATOR( className ); \
  1003. typedef baseClassName BaseClass; \
  1004. typedef className ThisClass; \
  1005. template <class T> friend class CDmElementFactory; \
  1006. template <class T> friend class CDmAbstractElementFactory; \
  1007. static CUtlSymbolLarge m_classType
  1008. #define IMPLEMENT_ELEMENT( className ) \
  1009. CUtlSymbolLarge className::m_classType = UTL_INVAL_SYMBOL_LARGE; \
  1010. DEFINE_FIXEDSIZE_ALLOCATOR( className, 1024, CUtlMemoryPool::GROW_SLOW );
  1011. #endif // DMELEMENT_H