mirror of
https://github.com/celisej567/source-engine.git
synced 2026-01-05 22:09:59 +03:00
1
This commit is contained in:
468
datamodel/dmelementdictionary.cpp
Normal file
468
datamodel/dmelementdictionary.cpp
Normal file
@@ -0,0 +1,468 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "dmelementdictionary.h"
|
||||
#include "datamodel/dmelement.h"
|
||||
#include "datamodel/dmattribute.h"
|
||||
#include "datamodel/dmattributevar.h"
|
||||
#include "datamodel/idatamodel.h"
|
||||
#include "datamodel.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CDmElementDictionary::CDmElementDictionary()
|
||||
: m_idmap( 1024, 0, 0, DmIdPair_t::Compare, DmIdPair_t::HashKey )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Clears the dictionary
|
||||
//-----------------------------------------------------------------------------
|
||||
void CDmElementDictionary::Clear()
|
||||
{
|
||||
m_Dict.Purge();
|
||||
m_Attributes.Purge();
|
||||
m_ArrayAttributes.Purge();
|
||||
m_elementsToDelete.Purge();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Inserts an element into the table
|
||||
//-----------------------------------------------------------------------------
|
||||
DmElementDictHandle_t CDmElementDictionary::InsertElement( CDmElement *pElement )
|
||||
{
|
||||
// Insert it into the reconnection table
|
||||
return m_Dict.AddToTail( pElement ? pElement->GetHandle() : DMELEMENT_HANDLE_INVALID );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Returns a particular element
|
||||
//-----------------------------------------------------------------------------
|
||||
CDmElement *CDmElementDictionary::GetElement( DmElementDictHandle_t handle )
|
||||
{
|
||||
if ( handle == ELEMENT_DICT_HANDLE_INVALID )
|
||||
return NULL;
|
||||
|
||||
return g_pDataModel->GetElement( m_Dict[ handle ] );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Adds an attribute to the fixup list
|
||||
//-----------------------------------------------------------------------------
|
||||
void CDmElementDictionary::AddAttribute( CDmAttribute *pAttribute, const DmObjectId_t &objectId )
|
||||
{
|
||||
if ( m_elementsToDelete.Find( pAttribute->GetOwner()->GetHandle() ) != m_elementsToDelete.InvalidIndex() )
|
||||
return; // don't add attributes if their element is being deleted
|
||||
|
||||
int i = m_Attributes.AddToTail();
|
||||
m_Attributes[i].m_nType = AT_OBJECTID;
|
||||
m_Attributes[i].m_pAttribute = pAttribute;
|
||||
CopyUniqueId( objectId, &m_Attributes[i].m_ObjectId );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Adds an element of an attribute array to the fixup list
|
||||
//-----------------------------------------------------------------------------
|
||||
void CDmElementDictionary::AddArrayAttribute( CDmAttribute *pAttribute, DmElementDictHandle_t hElement )
|
||||
{
|
||||
if ( m_elementsToDelete.Find( pAttribute->GetOwner()->GetHandle() ) != m_elementsToDelete.InvalidIndex() )
|
||||
return; // don't add attributes if their element is being deleted
|
||||
|
||||
int i = m_ArrayAttributes.AddToTail();
|
||||
m_ArrayAttributes[i].m_nType = AT_ELEMENT;
|
||||
m_ArrayAttributes[i].m_pAttribute = pAttribute;
|
||||
m_ArrayAttributes[i].m_hElement = hElement;
|
||||
}
|
||||
|
||||
void CDmElementDictionary::AddArrayAttribute( CDmAttribute *pAttribute, const DmObjectId_t &objectId )
|
||||
{
|
||||
if ( m_elementsToDelete.Find( pAttribute->GetOwner()->GetHandle() ) != m_elementsToDelete.InvalidIndex() )
|
||||
return; // don't add attributes if their element is being deleted
|
||||
|
||||
int i = m_ArrayAttributes.AddToTail();
|
||||
m_ArrayAttributes[i].m_nType = AT_OBJECTID;
|
||||
m_ArrayAttributes[i].m_pAttribute = pAttribute;
|
||||
CopyUniqueId( objectId, &m_ArrayAttributes[i].m_ObjectId );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
void CDmElementDictionary::RemoveAttributeInfosOfElement( AttributeList_t &attributes, DmElementHandle_t hElement )
|
||||
{
|
||||
while ( attributes.Count() > 0 && attributes.Tail().m_pAttribute->GetOwner()->GetHandle() == hElement )
|
||||
{
|
||||
attributes.Remove( attributes.Count() - 1 );
|
||||
}
|
||||
}
|
||||
|
||||
DmElementHandle_t CDmElementDictionary::SetElementId( DmElementDictHandle_t hDictHandle, const DmObjectId_t &newId, DmConflictResolution_t idConflictResolution )
|
||||
{
|
||||
DmElementHandle_t hElement = m_Dict[ hDictHandle ];
|
||||
CDmElement *pElement = g_pDataModel->GetElement( hElement );
|
||||
Assert( pElement );
|
||||
if ( !pElement )
|
||||
return DMELEMENT_HANDLE_INVALID;
|
||||
|
||||
const DmObjectId_t &oldId = pElement->GetId();
|
||||
|
||||
if ( idConflictResolution == CR_FORCE_COPY )
|
||||
{
|
||||
m_idmap.Insert( DmIdPair_t( newId, oldId ) ); // map the newId back to the old id, and keep the old id
|
||||
return hElement;
|
||||
}
|
||||
|
||||
DmElementHandle_t newHandle = g_pDataModelImp->ChangeElementId( hElement, oldId, newId );
|
||||
if ( newHandle != DMELEMENT_HANDLE_INVALID )
|
||||
{
|
||||
// if ChangeElementId returns a handle, the id has been changed
|
||||
if ( newHandle != hElement )
|
||||
{
|
||||
int i = m_Dict.Find( hElement );
|
||||
if ( i != m_Dict.InvalidIndex() )
|
||||
{
|
||||
m_Dict[ i ] = newHandle;
|
||||
}
|
||||
}
|
||||
return newHandle; // either keeping the old handle, with the new id, or found a new handle associated with that new id
|
||||
}
|
||||
|
||||
// id not changed because that id is already in use
|
||||
if ( idConflictResolution == CR_DELETE_NEW )
|
||||
{
|
||||
DmElementHandle_t hExistingElement = g_pDataModel->FindElement( newId );
|
||||
|
||||
int i = m_elementsToDelete.AddToTail( );
|
||||
m_elementsToDelete[i].m_hDictHandle = hDictHandle;
|
||||
m_elementsToDelete[i].m_hElementToDelete = hElement;
|
||||
m_elementsToDelete[i].m_hReplacementElement = hExistingElement;
|
||||
|
||||
// remove all element ref attributes read in before the id (typically none)
|
||||
RemoveAttributeInfosOfElement( m_Attributes, hElement );
|
||||
RemoveAttributeInfosOfElement( m_ArrayAttributes, hElement );
|
||||
|
||||
return DMELEMENT_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
if ( idConflictResolution == CR_DELETE_OLD )
|
||||
{
|
||||
DmElementHandle_t hExistingElement = g_pDataModel->FindElement( newId );
|
||||
Assert( hExistingElement != DMELEMENT_HANDLE_INVALID );
|
||||
if ( hExistingElement == DMELEMENT_HANDLE_INVALID )
|
||||
return DMELEMENT_HANDLE_INVALID; // unexpected error in ChangeElementId (failed due to something other than a conflict)
|
||||
|
||||
g_pDataModelImp->DeleteElement( hExistingElement, HR_NEVER ); // need to keep the handle around until ChangeElemendId
|
||||
newHandle = g_pDataModelImp->ChangeElementId( hElement, oldId, newId );
|
||||
Assert( newHandle == hExistingElement );
|
||||
|
||||
int i = m_Dict.Find( hElement );
|
||||
if ( i != m_Dict.InvalidIndex() )
|
||||
{
|
||||
m_Dict[ i ] = newHandle;
|
||||
}
|
||||
|
||||
return newHandle;
|
||||
}
|
||||
|
||||
if ( idConflictResolution == CR_COPY_NEW )
|
||||
{
|
||||
m_idmap.Insert( DmIdPair_t( newId, oldId ) ); // map the newId back to the old id, and keep the old id
|
||||
return hElement;
|
||||
}
|
||||
|
||||
Assert( 0 );
|
||||
return DMELEMENT_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Finds an element into the table
|
||||
//-----------------------------------------------------------------------------
|
||||
DmElementDictHandle_t CDmElementDictionary::FindElement( CDmElement *pElement )
|
||||
{
|
||||
return m_Dict.Find( pElement ? pElement->GetHandle() : DMELEMENT_HANDLE_INVALID );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Hook up all element references (which were unserialized as object ids)
|
||||
//-----------------------------------------------------------------------------
|
||||
void CDmElementDictionary::HookUpElementAttributes()
|
||||
{
|
||||
int n = m_Attributes.Count();
|
||||
for ( int i = 0; i < n; ++i )
|
||||
{
|
||||
Assert( m_Attributes[i].m_pAttribute->GetType() == AT_ELEMENT );
|
||||
Assert( m_Attributes[i].m_nType == AT_OBJECTID );
|
||||
|
||||
UtlHashHandle_t h = m_idmap.Find( DmIdPair_t( m_Attributes[i].m_ObjectId ) );
|
||||
DmObjectId_t &id = h == m_idmap.InvalidHandle() ? m_Attributes[i].m_ObjectId : m_idmap[ h ].m_newId;
|
||||
|
||||
// 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
|
||||
DmElementHandle_t hElement = g_pDataModelImp->FindOrCreateElementHandle( id );
|
||||
m_Attributes[i].m_pAttribute->SetValue<DmElementHandle_t>( hElement );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Hook up all element array references
|
||||
//-----------------------------------------------------------------------------
|
||||
void CDmElementDictionary::HookUpElementArrayAttributes()
|
||||
{
|
||||
// Find unique array attributes; we need to clear them all before adding stuff.
|
||||
// This clears them of stuff added during their construction phase.
|
||||
int n = m_ArrayAttributes.Count();
|
||||
CUtlRBTree< CDmAttribute*, unsigned short > lookup( 0, n, DefLessFunc(CDmAttribute*) );
|
||||
for ( int i = 0; i < n; ++i )
|
||||
{
|
||||
Assert( m_ArrayAttributes[i].m_pAttribute->GetType() == AT_ELEMENT_ARRAY );
|
||||
CDmAttribute *pElementArray = m_ArrayAttributes[i].m_pAttribute;
|
||||
CDmrElementArray<> array( pElementArray );
|
||||
if ( lookup.Find( pElementArray ) == lookup.InvalidIndex() )
|
||||
{
|
||||
array.RemoveAll();
|
||||
lookup.Insert( pElementArray );
|
||||
}
|
||||
}
|
||||
|
||||
for ( int i = 0; i < n; ++i )
|
||||
{
|
||||
Assert( m_ArrayAttributes[i].m_pAttribute->GetType() == AT_ELEMENT_ARRAY );
|
||||
|
||||
CDmrElementArray<> array( m_ArrayAttributes[i].m_pAttribute );
|
||||
|
||||
if ( m_ArrayAttributes[i].m_nType == AT_ELEMENT )
|
||||
{
|
||||
CDmElement *pElement = GetElement( m_ArrayAttributes[i].m_hElement );
|
||||
array.AddToTail( pElement );
|
||||
}
|
||||
else
|
||||
{
|
||||
UtlHashHandle_t h = m_idmap.Find( DmIdPair_t( m_ArrayAttributes[i].m_ObjectId ) );
|
||||
DmObjectId_t &id = ( h == m_idmap.InvalidHandle() ) ? m_ArrayAttributes[i].m_ObjectId : m_idmap[ h ].m_newId;
|
||||
|
||||
// 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
|
||||
DmElementHandle_t hElement = g_pDataModelImp->FindOrCreateElementHandle( id );
|
||||
int nIndex = array.AddToTail();
|
||||
array.SetHandle( nIndex, hElement );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Hook up all element references (which were unserialized as object ids)
|
||||
//-----------------------------------------------------------------------------
|
||||
void CDmElementDictionary::HookUpElementReferences()
|
||||
{
|
||||
int nElementsToDelete = m_elementsToDelete.Count();
|
||||
for ( int i = 0; i < nElementsToDelete; ++i )
|
||||
{
|
||||
DmElementDictHandle_t hDictIndex = m_elementsToDelete[i].m_hDictHandle;
|
||||
DmElementHandle_t hElement = m_Dict[ hDictIndex ];
|
||||
g_pDataModelImp->DeleteElement( hElement );
|
||||
m_Dict[ hDictIndex ] = m_elementsToDelete[i].m_hReplacementElement;
|
||||
}
|
||||
|
||||
HookUpElementArrayAttributes();
|
||||
HookUpElementAttributes();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Element dictionary used in serialization
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
CDmElementSerializationDictionary::CDmElementSerializationDictionary() :
|
||||
m_Dict( 1024, 0, CDmElementSerializationDictionary::LessFunc )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Used to sort the list of elements
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CDmElementSerializationDictionary::LessFunc( const ElementInfo_t &lhs, const ElementInfo_t &rhs )
|
||||
{
|
||||
return lhs.m_pElement < rhs.m_pElement;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Finds the handle of the element
|
||||
//-----------------------------------------------------------------------------
|
||||
DmElementDictHandle_t CDmElementSerializationDictionary::Find( CDmElement *pElement )
|
||||
{
|
||||
ElementInfo_t find;
|
||||
find.m_pElement = pElement;
|
||||
return m_Dict.Find( find );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Creates the list of all things to serialize
|
||||
//-----------------------------------------------------------------------------
|
||||
void CDmElementSerializationDictionary::BuildElementList_R( CDmElement *pElement, bool bFlatMode, bool bIsRoot )
|
||||
{
|
||||
if ( !pElement )
|
||||
return;
|
||||
|
||||
// FIXME: Right here we should ask the element if it's an external
|
||||
// file reference and exit immediately if so.
|
||||
|
||||
// This means we've already encountered this guy.
|
||||
// Therefore, he can never be a root element
|
||||
DmElementDictHandle_t h = Find( pElement );
|
||||
if ( h != m_Dict.InvalidIndex() )
|
||||
{
|
||||
m_Dict[h].m_bRoot = true;
|
||||
return;
|
||||
}
|
||||
|
||||
ElementInfo_t info;
|
||||
info.m_bRoot = bFlatMode || bIsRoot;
|
||||
info.m_pElement = pElement;
|
||||
m_Dict.Insert( info );
|
||||
|
||||
for ( CDmAttribute *pAttribute = pElement->FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() )
|
||||
{
|
||||
if ( pAttribute->IsFlagSet( FATTRIB_DONTSAVE ) )
|
||||
continue;
|
||||
|
||||
switch( pAttribute->GetType() )
|
||||
{
|
||||
case AT_ELEMENT:
|
||||
{
|
||||
CDmElement *pChild = pAttribute->GetValueElement<CDmElement>();
|
||||
if ( !pChild || pChild->GetFileId() != pElement->GetFileId() )
|
||||
break;
|
||||
|
||||
BuildElementList_R( pChild, bFlatMode, false );
|
||||
}
|
||||
break;
|
||||
|
||||
case AT_ELEMENT_ARRAY:
|
||||
{
|
||||
CDmrElementArray<> array( pAttribute );
|
||||
int nCount = array.Count();
|
||||
for ( int i = 0; i < nCount; ++i )
|
||||
{
|
||||
CDmElement *pChild = array[i];
|
||||
if ( !pChild || pChild->GetFileId() != pElement->GetFileId() )
|
||||
break;
|
||||
|
||||
BuildElementList_R( pChild, bFlatMode, false );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CDmElementSerializationDictionary::BuildElementList( CDmElement *pElement, bool bFlatMode )
|
||||
{
|
||||
BuildElementList_R( pElement, bFlatMode, true );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Should I inline the serialization of this element?
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CDmElementSerializationDictionary::ShouldInlineElement( CDmElement *pElement )
|
||||
{
|
||||
// This means we've already encountered this guy.
|
||||
// Therefore, he can never be a root element
|
||||
DmElementDictHandle_t h = Find( pElement );
|
||||
if ( h != m_Dict.InvalidIndex() )
|
||||
return !m_Dict[h].m_bRoot;
|
||||
|
||||
// If we didn't find the element, it means it's a reference to an external
|
||||
// element (or it's NULL), so don't inline ie.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Clears the dictionary
|
||||
//-----------------------------------------------------------------------------
|
||||
void CDmElementSerializationDictionary::Clear()
|
||||
{
|
||||
m_Dict.RemoveAll();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// How many root elements do we have?
|
||||
//-----------------------------------------------------------------------------
|
||||
int CDmElementSerializationDictionary::RootElementCount() const
|
||||
{
|
||||
int nCount = 0;
|
||||
DmElementDictHandle_t h = m_Dict.FirstInorder();
|
||||
while( h != m_Dict.InvalidIndex() )
|
||||
{
|
||||
if ( m_Dict[h].m_bRoot )
|
||||
{
|
||||
++nCount;
|
||||
}
|
||||
h = m_Dict.NextInorder( h );
|
||||
}
|
||||
return nCount;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Iterates over all root elements to serialize
|
||||
//-----------------------------------------------------------------------------
|
||||
DmElementDictHandle_t CDmElementSerializationDictionary::FirstRootElement() const
|
||||
{
|
||||
// NOTE - this code only works with BlockMemory or Memory (NOT FixedMemory)
|
||||
|
||||
// NOTE: I don't have to use First/NextInorder here because there
|
||||
// are guaranteed to be no removals from the dictionary.
|
||||
// Also, using inorder traversal won't get my actual root element to be first in the file
|
||||
int nCount = m_Dict.Count();
|
||||
for ( DmElementDictHandle_t h = 0; h < nCount; ++h )
|
||||
{
|
||||
if ( m_Dict[h].m_bRoot )
|
||||
return h;
|
||||
}
|
||||
return ELEMENT_DICT_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
DmElementDictHandle_t CDmElementSerializationDictionary::NextRootElement( DmElementDictHandle_t h ) const
|
||||
{
|
||||
// NOTE - this code only works with BlockMemory or Memory (NOT FixedMemory)
|
||||
|
||||
// NOTE: I don't have to use First/NextInorder here because there
|
||||
// are guaranteed to be no removals from the dictionary.
|
||||
// Also, using inorder traversal won't get my actual root element to be first in the file
|
||||
++h;
|
||||
int nCount = m_Dict.Count();
|
||||
for ( ; h < nCount; ++h )
|
||||
{
|
||||
if ( m_Dict[h].m_bRoot )
|
||||
return h;
|
||||
}
|
||||
return ELEMENT_DICT_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
CDmElement *CDmElementSerializationDictionary::GetRootElement( DmElementDictHandle_t h )
|
||||
{
|
||||
Assert( m_Dict[h].m_bRoot );
|
||||
return m_Dict[h].m_pElement;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user