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.

472 lines
16 KiB

  1. //====== Copyright � 1996-2004, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "dmelementdictionary.h"
  7. #include "datamodel/dmelement.h"
  8. #include "datamodel/dmattribute.h"
  9. #include "datamodel/dmattributevar.h"
  10. #include "datamodel/idatamodel.h"
  11. #include "datamodel.h"
  12. //-----------------------------------------------------------------------------
  13. // Constructor
  14. //-----------------------------------------------------------------------------
  15. CDmElementDictionary::CDmElementDictionary()
  16. : m_idmap( 1024, 0, 0, DmIdPair_t::Compare, DmIdPair_t::HashKey )
  17. {
  18. }
  19. //-----------------------------------------------------------------------------
  20. // Clears the dictionary
  21. //-----------------------------------------------------------------------------
  22. void CDmElementDictionary::Clear()
  23. {
  24. m_Dict.Purge();
  25. m_Attributes.Purge();
  26. m_ArrayAttributes.Purge();
  27. m_elementsToDelete.Purge();
  28. m_idmap.Purge();
  29. }
  30. //-----------------------------------------------------------------------------
  31. // Inserts an element into the table
  32. //-----------------------------------------------------------------------------
  33. DmElementDictHandle_t CDmElementDictionary::InsertElement( CDmElement *pElement )
  34. {
  35. // Insert it into the reconnection table
  36. return m_Dict.AddToTail( pElement ? pElement->GetHandle() : DMELEMENT_HANDLE_INVALID );
  37. }
  38. //-----------------------------------------------------------------------------
  39. // Returns a particular element
  40. //-----------------------------------------------------------------------------
  41. CDmElement *CDmElementDictionary::GetElement( DmElementDictHandle_t handle )
  42. {
  43. if ( handle == ELEMENT_DICT_HANDLE_INVALID )
  44. return NULL;
  45. return g_pDataModel->GetElement( m_Dict[ handle ] );
  46. }
  47. //-----------------------------------------------------------------------------
  48. // Adds an attribute to the fixup list
  49. //-----------------------------------------------------------------------------
  50. void CDmElementDictionary::AddAttribute( CDmAttribute *pAttribute, const DmObjectId_t &objectId )
  51. {
  52. if ( m_elementsToDelete.Find( pAttribute->GetOwner()->GetHandle() ) != m_elementsToDelete.InvalidIndex() )
  53. return; // don't add attributes if their element is being deleted
  54. int i = m_Attributes.AddToTail();
  55. m_Attributes[i].m_bId = true;
  56. m_Attributes[i].m_pAttribute = pAttribute;
  57. CopyUniqueId( objectId, &m_Attributes[i].m_ObjectId );
  58. }
  59. //-----------------------------------------------------------------------------
  60. // Adds an element of an attribute array to the fixup list
  61. //-----------------------------------------------------------------------------
  62. void CDmElementDictionary::AddArrayAttribute( CDmAttribute *pAttribute, DmElementDictHandle_t hElement )
  63. {
  64. if ( m_elementsToDelete.Find( pAttribute->GetOwner()->GetHandle() ) != m_elementsToDelete.InvalidIndex() )
  65. return; // don't add attributes if their element is being deleted
  66. int i = m_ArrayAttributes.AddToTail();
  67. m_ArrayAttributes[i].m_bId = false;
  68. m_ArrayAttributes[i].m_pAttribute = pAttribute;
  69. m_ArrayAttributes[i].m_hElement = hElement;
  70. }
  71. void CDmElementDictionary::AddArrayAttribute( CDmAttribute *pAttribute, const DmObjectId_t &objectId )
  72. {
  73. if ( m_elementsToDelete.Find( pAttribute->GetOwner()->GetHandle() ) != m_elementsToDelete.InvalidIndex() )
  74. return; // don't add attributes if their element is being deleted
  75. int i = m_ArrayAttributes.AddToTail();
  76. m_ArrayAttributes[i].m_bId = true;
  77. m_ArrayAttributes[i].m_pAttribute = pAttribute;
  78. CopyUniqueId( objectId, &m_ArrayAttributes[i].m_ObjectId );
  79. }
  80. //-----------------------------------------------------------------------------
  81. //
  82. //-----------------------------------------------------------------------------
  83. void CDmElementDictionary::RemoveAttributeInfosOfElement( AttributeList_t &attributes, DmElementHandle_t hElement )
  84. {
  85. while ( attributes.Count() > 0 && attributes.Tail().m_pAttribute->GetOwner()->GetHandle() == hElement )
  86. {
  87. attributes.Remove( attributes.Count() - 1 );
  88. }
  89. }
  90. DmElementHandle_t CDmElementDictionary::SetElementId( DmElementDictHandle_t hDictHandle, const DmObjectId_t &newId, DmConflictResolution_t idConflictResolution )
  91. {
  92. DmElementHandle_t hElement = m_Dict[ hDictHandle ];
  93. CDmElement *pElement = g_pDataModel->GetElement( hElement );
  94. Assert( pElement );
  95. if ( !pElement )
  96. return DMELEMENT_HANDLE_INVALID;
  97. const DmObjectId_t &oldId = pElement->GetId();
  98. if ( idConflictResolution == CR_FORCE_COPY )
  99. {
  100. m_idmap.Insert( DmIdPair_t( newId, oldId ) ); // map the newId back to the old id, and keep the old id
  101. return hElement;
  102. }
  103. DmElementHandle_t newHandle = g_pDataModelImp->ChangeElementId( hElement, oldId, newId );
  104. if ( newHandle != DMELEMENT_HANDLE_INVALID )
  105. {
  106. // if ChangeElementId returns a handle, the id has been changed
  107. if ( newHandle != hElement )
  108. {
  109. int i = m_Dict.Find( hElement );
  110. if ( i != m_Dict.InvalidIndex() )
  111. {
  112. m_Dict[ i ] = newHandle;
  113. }
  114. }
  115. return newHandle; // either keeping the old handle, with the new id, or found a new handle associated with that new id
  116. }
  117. // id not changed because that id is already in use
  118. if ( idConflictResolution == CR_DELETE_NEW )
  119. {
  120. DmElementHandle_t hExistingElement = g_pDataModel->FindElement( newId );
  121. int i = m_elementsToDelete.AddToTail( );
  122. m_elementsToDelete[i].m_hDictHandle = hDictHandle;
  123. m_elementsToDelete[i].m_hElementToDelete = hElement;
  124. m_elementsToDelete[i].m_hReplacementElement = hExistingElement;
  125. // remove all element ref attributes read in before the id (typically none)
  126. RemoveAttributeInfosOfElement( m_Attributes, hElement );
  127. RemoveAttributeInfosOfElement( m_ArrayAttributes, hElement );
  128. return DMELEMENT_HANDLE_INVALID;
  129. }
  130. if ( idConflictResolution == CR_DELETE_OLD )
  131. {
  132. DmElementHandle_t hExistingElement = g_pDataModel->FindElement( newId );
  133. Assert( hExistingElement != DMELEMENT_HANDLE_INVALID );
  134. if ( hExistingElement == DMELEMENT_HANDLE_INVALID )
  135. return DMELEMENT_HANDLE_INVALID; // unexpected error in ChangeElementId (failed due to something other than a conflict)
  136. g_pDataModelImp->DeleteElement( hExistingElement, HR_NEVER ); // need to keep the handle around until ChangeElemendId
  137. newHandle = g_pDataModelImp->ChangeElementId( hElement, oldId, newId );
  138. Assert( newHandle == hExistingElement );
  139. int i = m_Dict.Find( hElement );
  140. if ( i != m_Dict.InvalidIndex() )
  141. {
  142. m_Dict[ i ] = newHandle;
  143. }
  144. return newHandle;
  145. }
  146. if ( idConflictResolution == CR_COPY_NEW )
  147. {
  148. m_idmap.Insert( DmIdPair_t( newId, oldId ) ); // map the newId back to the old id, and keep the old id
  149. return hElement;
  150. }
  151. Assert( 0 );
  152. return DMELEMENT_HANDLE_INVALID;
  153. }
  154. //-----------------------------------------------------------------------------
  155. // Finds an element into the table
  156. //-----------------------------------------------------------------------------
  157. DmElementDictHandle_t CDmElementDictionary::FindElement( CDmElement *pElement )
  158. {
  159. return m_Dict.Find( pElement ? pElement->GetHandle() : DMELEMENT_HANDLE_INVALID );
  160. }
  161. //-----------------------------------------------------------------------------
  162. // Hook up all element references (which were unserialized as object ids)
  163. //-----------------------------------------------------------------------------
  164. void CDmElementDictionary::HookUpElementAttributes()
  165. {
  166. int n = m_Attributes.Count();
  167. for ( int i = 0; i < n; ++i )
  168. {
  169. Assert( m_Attributes[i].m_pAttribute->GetType() == AT_ELEMENT );
  170. Assert( m_Attributes[i].m_bId );
  171. UtlHashHandle_t h = m_idmap.Find( DmIdPair_t( m_Attributes[i].m_ObjectId ) );
  172. DmObjectId_t &id = h == m_idmap.InvalidHandle() ? m_Attributes[i].m_ObjectId : m_idmap[ h ].m_newId;
  173. // search id->handle table (both loaded and unloaded) for id, and if not found, create a new handle, map it to the id and return it
  174. DmElementHandle_t hElement = g_pDataModelImp->FindOrCreateElementHandle( id );
  175. m_Attributes[i].m_pAttribute->SetValue<DmElementHandle_t>( hElement );
  176. }
  177. }
  178. //-----------------------------------------------------------------------------
  179. // Hook up all element array references
  180. //-----------------------------------------------------------------------------
  181. void CDmElementDictionary::HookUpElementArrayAttributes()
  182. {
  183. // Find unique array attributes; we need to clear them all before adding stuff.
  184. // This clears them of stuff added during their construction phase.
  185. int n = m_ArrayAttributes.Count();
  186. CUtlRBTree< CDmAttribute*, unsigned short > lookup( 0, n, DefLessFunc(CDmAttribute*) );
  187. for ( int i = 0; i < n; ++i )
  188. {
  189. Assert( m_ArrayAttributes[i].m_pAttribute->GetType() == AT_ELEMENT_ARRAY );
  190. CDmAttribute *pElementArray = m_ArrayAttributes[i].m_pAttribute;
  191. CDmrElementArray<> array( pElementArray );
  192. if ( lookup.Find( pElementArray ) == lookup.InvalidIndex() )
  193. {
  194. array.RemoveAll();
  195. lookup.Insert( pElementArray );
  196. }
  197. }
  198. for ( int i = 0; i < n; ++i )
  199. {
  200. Assert( m_ArrayAttributes[i].m_pAttribute->GetType() == AT_ELEMENT_ARRAY );
  201. CDmrElementArray<> array( m_ArrayAttributes[i].m_pAttribute );
  202. if ( !m_ArrayAttributes[i].m_bId )
  203. {
  204. CDmElement *pElement = GetElement( m_ArrayAttributes[i].m_hElement );
  205. array.AddToTail( pElement );
  206. }
  207. else
  208. {
  209. UtlHashHandle_t h = m_idmap.Find( DmIdPair_t( m_ArrayAttributes[i].m_ObjectId ) );
  210. DmObjectId_t &id = ( h == m_idmap.InvalidHandle() ) ? m_ArrayAttributes[i].m_ObjectId : m_idmap[ h ].m_newId;
  211. // search id->handle table (both loaded and unloaded) for id, and if not found, create a new handle, map it to the id and return it
  212. DmElementHandle_t hElement = g_pDataModelImp->FindOrCreateElementHandle( id );
  213. int nIndex = array.AddToTail();
  214. array.SetHandle( nIndex, hElement );
  215. }
  216. }
  217. }
  218. //-----------------------------------------------------------------------------
  219. // Hook up all element references (which were unserialized as object ids)
  220. //-----------------------------------------------------------------------------
  221. void CDmElementDictionary::HookUpElementReferences()
  222. {
  223. int nElementsToDelete = m_elementsToDelete.Count();
  224. for ( int i = 0; i < nElementsToDelete; ++i )
  225. {
  226. DmElementDictHandle_t hDictIndex = m_elementsToDelete[i].m_hDictHandle;
  227. DmElementHandle_t hElement = m_Dict[ hDictIndex ];
  228. g_pDataModelImp->DeleteElement( hElement );
  229. m_Dict[ hDictIndex ] = m_elementsToDelete[i].m_hReplacementElement;
  230. }
  231. HookUpElementArrayAttributes();
  232. HookUpElementAttributes();
  233. }
  234. //-----------------------------------------------------------------------------
  235. //
  236. // Element dictionary used in serialization
  237. //
  238. //-----------------------------------------------------------------------------
  239. CDmElementSerializationDictionary::CDmElementSerializationDictionary() :
  240. m_Dict( 1024, 0, CDmElementSerializationDictionary::LessFunc )
  241. {
  242. }
  243. //-----------------------------------------------------------------------------
  244. // Used to sort the list of elements
  245. //-----------------------------------------------------------------------------
  246. bool CDmElementSerializationDictionary::LessFunc( const ElementInfo_t &lhs, const ElementInfo_t &rhs )
  247. {
  248. return lhs.m_pElement < rhs.m_pElement;
  249. }
  250. //-----------------------------------------------------------------------------
  251. // Finds the handle of the element
  252. //-----------------------------------------------------------------------------
  253. DmElementDictHandle_t CDmElementSerializationDictionary::Find( CDmElement *pElement )
  254. {
  255. ElementInfo_t find;
  256. find.m_pElement = pElement;
  257. return m_Dict.Find( find );
  258. }
  259. //-----------------------------------------------------------------------------
  260. // Creates the list of all things to serialize
  261. //-----------------------------------------------------------------------------
  262. void CDmElementSerializationDictionary::BuildElementList_R( CDmElement *pElement, bool bFlatMode, bool bIsRoot )
  263. {
  264. if ( !pElement )
  265. return;
  266. // FIXME: Right here we should ask the element if it's an external
  267. // file reference and exit immediately if so.
  268. // This means we've already encountered this guy.
  269. // Therefore, he can never be a root element
  270. DmElementDictHandle_t h = Find( pElement );
  271. if ( h != m_Dict.InvalidIndex() )
  272. {
  273. m_Dict[h].m_bRoot = true;
  274. return;
  275. }
  276. ElementInfo_t info;
  277. info.m_bRoot = bFlatMode || bIsRoot;
  278. info.m_pElement = pElement;
  279. m_Dict.Insert( info );
  280. // Tell the element we're about to serialize it
  281. pElement->OnElementSerialized();
  282. for ( CDmAttribute *pAttribute = pElement->FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() )
  283. {
  284. if ( pAttribute->IsFlagSet( FATTRIB_DONTSAVE ) )
  285. continue;
  286. switch( pAttribute->GetType() )
  287. {
  288. case AT_ELEMENT:
  289. {
  290. CDmElement *pChild = pAttribute->GetValueElement<CDmElement>();
  291. if ( !pChild || pChild->GetFileId() != pElement->GetFileId() )
  292. break;
  293. BuildElementList_R( pChild, bFlatMode, false );
  294. }
  295. break;
  296. case AT_ELEMENT_ARRAY:
  297. {
  298. CDmrElementArray<> array( pAttribute );
  299. int nCount = array.Count();
  300. for ( int i = 0; i < nCount; ++i )
  301. {
  302. CDmElement *pChild = array[i];
  303. if ( !pChild || pChild->GetFileId() != pElement->GetFileId() )
  304. continue;
  305. BuildElementList_R( pChild, bFlatMode, false );
  306. }
  307. }
  308. break;
  309. }
  310. }
  311. }
  312. void CDmElementSerializationDictionary::BuildElementList( CDmElement *pElement, bool bFlatMode )
  313. {
  314. BuildElementList_R( pElement, bFlatMode, true );
  315. }
  316. //-----------------------------------------------------------------------------
  317. // Should I inline the serialization of this element?
  318. //-----------------------------------------------------------------------------
  319. bool CDmElementSerializationDictionary::ShouldInlineElement( CDmElement *pElement )
  320. {
  321. // This means we've already encountered this guy.
  322. // Therefore, he can never be a root element
  323. DmElementDictHandle_t h = Find( pElement );
  324. if ( h != m_Dict.InvalidIndex() )
  325. return !m_Dict[h].m_bRoot;
  326. // If we didn't find the element, it means it's a reference to an external
  327. // element (or it's NULL), so don't inline ie.
  328. return false;
  329. }
  330. //-----------------------------------------------------------------------------
  331. // Clears the dictionary
  332. //-----------------------------------------------------------------------------
  333. void CDmElementSerializationDictionary::Clear()
  334. {
  335. m_Dict.RemoveAll();
  336. }
  337. //-----------------------------------------------------------------------------
  338. // How many root elements do we have?
  339. //-----------------------------------------------------------------------------
  340. int CDmElementSerializationDictionary::RootElementCount() const
  341. {
  342. int nCount = 0;
  343. DmElementDictHandle_t h = m_Dict.FirstInorder();
  344. while( h != m_Dict.InvalidIndex() )
  345. {
  346. if ( m_Dict[h].m_bRoot )
  347. {
  348. ++nCount;
  349. }
  350. h = m_Dict.NextInorder( h );
  351. }
  352. return nCount;
  353. }
  354. //-----------------------------------------------------------------------------
  355. // Iterates over all root elements to serialize
  356. //-----------------------------------------------------------------------------
  357. DmElementDictHandle_t CDmElementSerializationDictionary::FirstRootElement() const
  358. {
  359. // NOTE - this code only works with BlockMemory or Memory (NOT FixedMemory)
  360. // NOTE: I don't have to use First/NextInorder here because there
  361. // are guaranteed to be no removals from the dictionary.
  362. // Also, using inorder traversal won't get my actual root element to be first in the file
  363. int nCount = m_Dict.Count();
  364. for ( DmElementDictHandle_t h = 0; h < nCount; ++h )
  365. {
  366. if ( m_Dict[h].m_bRoot )
  367. return h;
  368. }
  369. return ELEMENT_DICT_HANDLE_INVALID;
  370. }
  371. DmElementDictHandle_t CDmElementSerializationDictionary::NextRootElement( DmElementDictHandle_t h ) const
  372. {
  373. // NOTE - this code only works with BlockMemory or Memory (NOT FixedMemory)
  374. // NOTE: I don't have to use First/NextInorder here because there
  375. // are guaranteed to be no removals from the dictionary.
  376. // Also, using inorder traversal won't get my actual root element to be first in the file
  377. ++h;
  378. int nCount = m_Dict.Count();
  379. for ( ; h < nCount; ++h )
  380. {
  381. if ( m_Dict[h].m_bRoot )
  382. return h;
  383. }
  384. return ELEMENT_DICT_HANDLE_INVALID;
  385. }
  386. CDmElement *CDmElementSerializationDictionary::GetRootElement( DmElementDictHandle_t h )
  387. {
  388. Assert( m_Dict[h].m_bRoot );
  389. return m_Dict[h].m_pElement;
  390. }