diff options
Diffstat (limited to 'datamodel/datamodel.h')
| -rw-r--r-- | datamodel/datamodel.h | 527 |
1 files changed, 527 insertions, 0 deletions
diff --git a/datamodel/datamodel.h b/datamodel/datamodel.h new file mode 100644 index 0000000..129f1ee --- /dev/null +++ b/datamodel/datamodel.h @@ -0,0 +1,527 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef DATAMODEL_H +#define DATAMODEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "datamodel/dmattribute.h" +#include "datamodel/idatamodel.h" +#include "datamodel/dmelement.h" +#include "datamodel/dmehandle.h" +#include "tier1/uniqueid.h" +#include "tier1/utlsymbol.h" +#include "tier1/utllinkedlist.h" +#include "tier1/utldict.h" +#include "tier1/utlstring.h" +#include "tier1/utlhandletable.h" +#include "tier1/utlhash.h" +#include "tier2/tier2.h" +#include "clipboardmanager.h" +#include "undomanager.h" +#include "tier1/convar.h" +#include "tier0/vprof.h" + + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- +class IDmElementFramework; +class IUndoElement; +class CDmElement; + +enum DmHandleReleasePolicy +{ + HR_ALWAYS, + HR_NEVER, + HR_IF_NOT_REFERENCED, +}; + + +//----------------------------------------------------------------------------- +// memory categories +//----------------------------------------------------------------------------- +enum +{ + MEMORY_CATEGORY_OUTER, + MEMORY_CATEGORY_ELEMENT_INTERNAL, + MEMORY_CATEGORY_DATAMODEL, + MEMORY_CATEGORY_REFERENCES, + MEMORY_CATEGORY_ATTRIBUTE_TREE, + MEMORY_CATEGORY_ATTRIBUTE_OVERHEAD, + MEMORY_CATEGORY_ATTRIBUTE_DATA, + MEMORY_CATEGORY_ATTRIBUTE_COUNT, + + MEMORY_CATEGORY_COUNT, +}; + + +//----------------------------------------------------------------------------- +// hash map of id->element, with the id storage optimized out +//----------------------------------------------------------------------------- +class CElementIdHash : public CUtlHash< DmElementHandle_t > +{ +public: + CElementIdHash( int nBucketCount = 0, int nGrowCount = 0, int nInitCount = 0 ) + : CUtlHash< DmElementHandle_t >( nBucketCount, nGrowCount, nInitCount, CompareFunc, KeyFunc ) + { + } + +protected: + typedef CUtlHash< DmElementHandle_t > BaseClass; + + static bool CompareFunc( DmElementHandle_t const& a, DmElementHandle_t const& b ) { return a == b; } + static bool IdCompareFunc( DmElementHandle_t const& hElement, DmObjectId_t const& id ) + { + CDmElement *pElement = g_pDataModel->GetElement( hElement ); + Assert( pElement ); + if ( !pElement ) + return false; + + return IsUniqueIdEqual( id, pElement->GetId() ); + } + + static unsigned int KeyFunc( DmElementHandle_t const& hElement ) + { + CDmElement *pElement = g_pDataModel->GetElement( hElement ); + Assert( pElement ); + if ( !pElement ) + return 0; + + return *( unsigned int* )&pElement->GetId(); + } + static unsigned int IdKeyFunc( DmObjectId_t const &src ) + { + return *(unsigned int*)&src; + } + +protected: + bool DoFind( DmObjectId_t const &src, unsigned int *pBucket, int *pIndex ) + { + // generate the data "key" + unsigned int key = IdKeyFunc( src ); + + // hash the "key" - get the correct hash table "bucket" + unsigned int ndxBucket; + if( m_bPowerOfTwo ) + { + *pBucket = ndxBucket = ( key & m_ModMask ); + } + else + { + int bucketCount = m_Buckets.Count(); + *pBucket = ndxBucket = key % bucketCount; + } + + int ndxKeyData; + CUtlVector< DmElementHandle_t > &bucket = m_Buckets[ndxBucket]; + int keyDataCount = bucket.Count(); + for( ndxKeyData = 0; ndxKeyData < keyDataCount; ndxKeyData++ ) + { + if( IdCompareFunc( bucket.Element( ndxKeyData ), src ) ) + break; + } + + if( ndxKeyData == keyDataCount ) + return false; + + *pIndex = ndxKeyData; + return true; + } + +public: + UtlHashHandle_t Find( DmElementHandle_t const &src ) { return BaseClass::Find( src ); } + UtlHashHandle_t Find( DmObjectId_t const &src ) + { + unsigned int ndxBucket; + int ndxKeyData; + + if ( DoFind( src, &ndxBucket, &ndxKeyData ) ) + return BuildHandle( ndxBucket, ndxKeyData ); + + return InvalidHandle(); + } +}; + +//----------------------------------------------------------------------------- +// struct to hold the set of elements in any given file +//----------------------------------------------------------------------------- + +struct FileElementSet_t +{ + FileElementSet_t( UtlSymId_t filename = UTL_INVAL_SYMBOL, UtlSymId_t format = UTL_INVAL_SYMBOL ) : + m_filename( filename ), m_format( format ), + m_hRoot( DMELEMENT_HANDLE_INVALID ), + m_bLoaded( true ), + m_nElements( 0 ) + { + } + FileElementSet_t( const FileElementSet_t& that ) : m_filename( that.m_filename ), m_format( that.m_format ), m_hRoot( DMELEMENT_HANDLE_INVALID ), m_bLoaded( that.m_bLoaded ), m_nElements( that.m_nElements ) + { + // the only time this should be copy constructed is when passing in an empty set to the parent array + // otherwise it could get prohibitively expensive time and memory wise + Assert( that.m_nElements == 0 ); + } + + UtlSymId_t m_filename; + UtlSymId_t m_format; + CDmeCountedHandle m_hRoot; + bool m_bLoaded; + int m_nElements; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Versionable factor for element types +//----------------------------------------------------------------------------- +class CDataModel : public CBaseAppSystem< IDataModel > +{ + typedef CBaseAppSystem< IDataModel > BaseClass; + +public: + CDataModel(); + virtual ~CDataModel(); + +// External interface +public: + // Methods of IAppSystem + virtual bool Connect( CreateInterfaceFn factory ); + virtual void *QueryInterface( const char *pInterfaceName ); + virtual InitReturnVal_t Init(); + virtual void Shutdown(); + + // Methods of IDataModel + virtual void AddElementFactory( const char *pClassName, IDmElementFactory *pFactory ); + virtual bool HasElementFactory( const char *pElementType ) const; + virtual void SetDefaultElementFactory( IDmElementFactory *pFactory ); + virtual int GetFirstFactory() const; + virtual int GetNextFactory( int index ) const; + virtual bool IsValidFactory( int index ) const; + virtual char const *GetFactoryName( int index ) const; + virtual DmElementHandle_t CreateElement( UtlSymId_t typeSymbol, const char *pElementName, DmFileId_t fileid, const DmObjectId_t *pObjectID = NULL ); + virtual DmElementHandle_t CreateElement( const char *pTypeName, const char *pElementName, DmFileId_t fileid, const DmObjectId_t *pObjectID = NULL ); + virtual void DestroyElement( DmElementHandle_t hElement ); + virtual CDmElement* GetElement( DmElementHandle_t hElement ) const; + virtual UtlSymId_t GetElementType( DmElementHandle_t hElement ) const; + virtual const char* GetElementName( DmElementHandle_t hElement ) const; + virtual const DmObjectId_t& GetElementId( DmElementHandle_t hElement ) const; + virtual const char *GetAttributeNameForType( DmAttributeType_t attType ) const; + virtual DmAttributeType_t GetAttributeTypeForName( const char *name ) const; + + virtual void AddSerializer( IDmSerializer *pSerializer ); + virtual void AddLegacyUpdater( IDmLegacyUpdater *pUpdater ); + virtual void AddFormatUpdater( IDmFormatUpdater *pUpdater ); + virtual const char* GetFormatExtension( const char *pFormatName ); + virtual const char* GetFormatDescription( const char *pFormatName ); + virtual int GetFormatCount() const; + virtual const char * GetFormatName( int i ) const; + virtual const char * GetDefaultEncoding( const char *pFormatName ); + virtual int GetEncodingCount() const; + virtual const char * GetEncodingName( int i ) const; + virtual bool IsEncodingBinary( const char *pEncodingName ) const; + virtual bool DoesEncodingStoreVersionInFile( const char *pEncodingName ) const; + + virtual void SetSerializationDelimiter( CUtlCharConversion *pConv ); + virtual void SetSerializationArrayDelimiter( const char *pDelimiter ); + virtual bool IsUnserializing(); + virtual bool Serialize( CUtlBuffer &outBuf, const char *pEncodingName, const char *pFormatName, DmElementHandle_t hRoot ); + virtual bool Unserialize( CUtlBuffer &buf, const char *pEncodingName, const char *pSourceFormatName, const char *pFormatHint, + const char *pFileName, DmConflictResolution_t idConflictResolution, DmElementHandle_t &hRoot ); + virtual bool UpdateUnserializedElements( const char *pSourceFormatName, int nSourceFormatVersion, + DmFileId_t fileid, DmConflictResolution_t idConflictResolution, CDmElement **ppRoot ); + virtual IDmSerializer* FindSerializer( const char *pEncodingName ) const; + virtual IDmLegacyUpdater* FindLegacyUpdater( const char *pLegacyFormatName ) const; + virtual IDmFormatUpdater* FindFormatUpdater( const char *pFormatName ) const; + virtual bool SaveToFile( char const *pFileName, char const *pPathID, const char *pEncodingName, const char *pFormatName, CDmElement *pRoot ); + virtual DmFileId_t RestoreFromFile( char const *pFileName, char const *pPathID, const char *pFormatHint, CDmElement **ppRoot, DmConflictResolution_t idConflictResolution = CR_DELETE_NEW, DmxHeader_t *pHeaderOut = NULL ); + + virtual void SetKeyValuesElementCallback( IElementForKeyValueCallback *pCallbackInterface ); + virtual const char * GetKeyValuesElementName( const char *pszKeyName, int iNestingLevel ); + virtual UtlSymId_t GetSymbol( const char *pString ); + virtual const char * GetString( UtlSymId_t sym ) const; + virtual int GetElementsAllocatedSoFar(); + virtual int GetMaxNumberOfElements(); + virtual int GetAllocatedAttributeCount(); + virtual int GetAllocatedElementCount(); + virtual DmElementHandle_t FirstAllocatedElement(); + virtual DmElementHandle_t NextAllocatedElement( DmElementHandle_t hElement ); + virtual int EstimateMemoryUsage( DmElementHandle_t hElement, TraversalDepth_t depth = TD_DEEP ); + virtual void SetUndoEnabled( bool enable ); + virtual bool IsUndoEnabled() const; + virtual bool UndoEnabledForElement( const CDmElement *pElement ) const; + virtual bool IsDirty() const; + virtual bool CanUndo() const; + virtual bool CanRedo() const; + virtual void StartUndo( const char *undodesc, const char *redodesc, int nChainingID = 0 ); + virtual void FinishUndo(); + virtual void AbortUndoableOperation(); + virtual void ClearRedo(); + virtual const char *GetUndoDesc(); + virtual const char *GetRedoDesc(); + virtual void Undo(); + virtual void Redo(); + virtual void TraceUndo( bool state ); // if true, undo records spew as they are added + virtual void ClearUndo(); + virtual void GetUndoInfo( CUtlVector< UndoInfo_t >& list ); + virtual const char * GetUndoString( UtlSymId_t sym ); + virtual void AddUndoElement( IUndoElement *pElement ); + virtual UtlSymId_t GetUndoDescInternal( const char *context ); + virtual UtlSymId_t GetRedoDescInternal( const char *context ); + virtual void EmptyClipboard(); + virtual void SetClipboardData( CUtlVector< KeyValues * >& data, IClipboardCleanup *pfnOptionalCleanuFunction = 0 ); + virtual void AddToClipboardData( KeyValues *add ); + virtual void GetClipboardData( CUtlVector< KeyValues * >& data ); + virtual bool HasClipboardData() const; + + virtual CDmAttribute * GetAttribute( DmAttributeHandle_t h ); + virtual bool IsAttributeHandleValid( DmAttributeHandle_t h ) const; + virtual void OnlyCreateUntypedElements( bool bEnable ); + virtual int NumFileIds(); + virtual DmFileId_t GetFileId( int i ); + virtual DmFileId_t FindOrCreateFileId( const char *pFilename ); + virtual void RemoveFileId( DmFileId_t fileid ); + virtual DmFileId_t GetFileId( const char *pFilename ); + virtual const char * GetFileName( DmFileId_t fileid ); + virtual void SetFileName( DmFileId_t fileid, const char *pFileName ); + virtual const char * GetFileFormat( DmFileId_t fileid ); + virtual void SetFileFormat( DmFileId_t fileid, const char *pFormat ); + virtual DmElementHandle_t GetFileRoot( DmFileId_t fileid ); + virtual void SetFileRoot( DmFileId_t fileid, DmElementHandle_t hRoot ); + virtual bool IsFileLoaded( DmFileId_t fileid ); + virtual void MarkFileLoaded( DmFileId_t fileid ); + virtual void UnloadFile( DmFileId_t fileid ); + virtual int NumElementsInFile( DmFileId_t fileid ); + virtual void DontAutoDelete( DmElementHandle_t hElement ); + virtual void MarkHandleInvalid( DmElementHandle_t hElement ); + virtual void MarkHandleValid( DmElementHandle_t hElement ); + virtual DmElementHandle_t FindElement( const DmObjectId_t &id ); + virtual DmAttributeReferenceIterator_t FirstAttributeReferencingElement( DmElementHandle_t hElement ); + virtual DmAttributeReferenceIterator_t NextAttributeReferencingElement( DmAttributeReferenceIterator_t hAttrIter ); + virtual CDmAttribute * GetAttribute( DmAttributeReferenceIterator_t hAttrIter ); + virtual bool InstallNotificationCallback( IDmNotify *pNotify ); + virtual void RemoveNotificationCallback( IDmNotify *pNotify ); + virtual bool IsSuppressingNotify( ) const; + virtual void SetSuppressingNotify( bool bSuppress ); + virtual void PushNotificationScope( const char *pReason, int nNotifySource, int nNotifyFlags ); + virtual void PopNotificationScope( bool bAbort ); + virtual void SetUndoDepth( int nSize ); + virtual void DisplayMemoryStats(); + +public: + // Internal public methods + int GetCurrentFormatVersion( const char *pFormatName ); + + // CreateElement references the attribute list passed in via ref, so don't edit or purge ref's attribute list afterwards + CDmElement* CreateElement( const DmElementReference_t &ref, const char *pElementType, const char *pElementName, DmFileId_t fileid, const DmObjectId_t *pObjectID ); + void DeleteElement( DmElementHandle_t hElement, DmHandleReleasePolicy hrp = HR_ALWAYS ); + + // element handle related methods + DmElementHandle_t AcquireElementHandle(); + void ReleaseElementHandle( DmElementHandle_t hElement ); + + // Handles to attributes + DmAttributeHandle_t AcquireAttributeHandle( CDmAttribute *pAttribute ); + void ReleaseAttributeHandle( DmAttributeHandle_t hAttribute ); + + // remove orphaned element subtrees + void FindAndDeleteOrphanedElements(); + + // Event "mailing list" + DmMailingList_t CreateMailingList(); + void DestroyMailingList( DmMailingList_t list ); + void AddElementToMailingList( DmMailingList_t list, DmElementHandle_t h ); + + // Returns false if the mailing list is empty now + bool RemoveElementFromMailingList( DmMailingList_t list, DmElementHandle_t h ); + + // Returns false if the mailing list is empty now (can happen owing to stale attributes) + bool PostAttributeChanged( DmMailingList_t list, CDmAttribute *pAttribute ); + + void GetInvalidHandles( CUtlVector< DmElementHandle_t > &handles ); + void MarkHandlesValid( CUtlVector< DmElementHandle_t > &handles ); + void MarkHandlesInvalid( CUtlVector< DmElementHandle_t > &handles ); + + // 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 FindOrCreateElementHandle( const DmObjectId_t &id ); + + // changes an element's id and associated mappings - generally during unserialization + DmElementHandle_t ChangeElementId( DmElementHandle_t hElement, const DmObjectId_t &oldId, const DmObjectId_t &newId ); + + DmElementReference_t *FindElementReference( DmElementHandle_t hElement, DmObjectId_t **ppId = NULL ); + + void RemoveUnreferencedElements(); + + void RemoveElementFromFile( DmElementHandle_t hElement, DmFileId_t fileid ); + void AddElementToFile( DmElementHandle_t hElement, DmFileId_t fileid ); + + void NotifyState( int nNotifyFlags ); + + int EstimateMemoryOverhead() const; + + bool IsCreatingUntypedElements() const { return m_bOnlyCreateUntypedElements; } + + unsigned short GetSymbolCount() const; + +private: + struct MailingList_t + { + CUtlVector<DmElementHandle_t> m_Elements; + }; + + struct ElementIdHandlePair_t + { + DmObjectId_t m_id; + DmElementReference_t m_ref; + ElementIdHandlePair_t() {} + explicit ElementIdHandlePair_t( const DmObjectId_t &id ) : m_ref() + { + CopyUniqueId( id, &m_id ); + } + ElementIdHandlePair_t( const DmObjectId_t &id, const DmElementReference_t &ref ) : m_ref( ref ) + { + CopyUniqueId( id, &m_id ); + } + ElementIdHandlePair_t( const ElementIdHandlePair_t& that ) : m_ref( that.m_ref ) + { + CopyUniqueId( that.m_id, &m_id ); + } + ElementIdHandlePair_t &operator=( const ElementIdHandlePair_t &that ) + { + CopyUniqueId( that.m_id, &m_id ); + m_ref = that.m_ref; + return *this; + } + static unsigned int HashKey( const ElementIdHandlePair_t& that ) + { + return *( unsigned int* )&that.m_id.m_Value; + } + static bool Compare( const ElementIdHandlePair_t& a, const ElementIdHandlePair_t& b ) + { + return IsUniqueIdEqual( a.m_id, b.m_id ); + } + }; + +private: + CDmElement *Unserialize( CUtlBuffer& buf ); + void Serialize( CDmElement *element, CUtlBuffer& buf ); + + // Read the header, return the version (or false if it's not a DMX file) + bool ReadDMXHeader( CUtlBuffer &inBuf, DmxHeader_t *pHeader ) const; + const char *GetEncodingFromLegacyFormat( const char *pLegacyFormatName ) const; + bool IsValidNonDMXFormat( const char *pFormatName ) const; + bool IsLegacyFormat( const char *pFormatName ) const; + + // Returns the current undo manager + CUndoManager* GetUndoMgr(); + const CUndoManager* GetUndoMgr() const; + CClipboardManager *GetClipboardMgr(); + const CClipboardManager *GetClipboardMgr() const; + + void UnloadFile( DmFileId_t fileid, bool bDeleteElements ); + + friend class CDmeElementRefHelper; + friend class CDmAttribute; + template< class T > friend class CDmArrayAttributeOp; + + void OnElementReferenceAdded ( DmElementHandle_t hElement, CDmAttribute *pAttribute ); + void OnElementReferenceRemoved( DmElementHandle_t hElement, CDmAttribute *pAttribute ); + void OnElementReferenceAdded ( DmElementHandle_t hElement, bool bRefCount ); + void OnElementReferenceRemoved( DmElementHandle_t hElement, bool bRefCount ); + +private: + CUtlVector< IDmSerializer* > m_Serializers; + CUtlVector< IDmLegacyUpdater* > m_LegacyUpdaters; + CUtlVector< IDmFormatUpdater* > m_FormatUpdaters; + + IDmElementFactory *m_pDefaultFactory; + CUtlDict< IDmElementFactory*, int > m_Factories; + CUtlSymbolTable m_SymbolTable; + CUtlHandleTable< CDmElement, 20 > m_Handles; + CUtlHandleTable< CDmAttribute, 20 > m_AttributeHandles; + CUndoManager m_UndoMgr; + CUtlLinkedList< MailingList_t, DmMailingList_t > m_MailingLists; + + bool m_bIsUnserializing : 1; + bool m_bUnableToSetDefaultFactory : 1; + bool m_bOnlyCreateUntypedElements : 1; + bool m_bUnableToCreateOnlyUntypedElements : 1; + bool m_bDeleteOrphanedElements : 1; + + CUtlHandleTable< FileElementSet_t, 20 > m_openFiles; + + CElementIdHash m_elementIds; + CUtlHash< ElementIdHandlePair_t > m_unloadedIdElementMap; + CUtlVector< DmObjectId_t > m_unreferencedElementIds; + CUtlVector< DmElementHandle_t > m_unreferencedElementHandles; + + CClipboardManager m_ClipboardMgr; + IElementForKeyValueCallback *m_pKeyvaluesCallbackInterface; + + int m_nElementsAllocatedSoFar; + int m_nMaxNumberOfElements; +}; + +//----------------------------------------------------------------------------- +// Singleton +//----------------------------------------------------------------------------- +extern CDataModel *g_pDataModelImp; + + +//----------------------------------------------------------------------------- +// Inline methods +//----------------------------------------------------------------------------- +inline CUndoManager* CDataModel::GetUndoMgr() +{ + return &m_UndoMgr; +} + +inline const CUndoManager* CDataModel::GetUndoMgr() const +{ + return &m_UndoMgr; +} + +inline void CDataModel::NotifyState( int nNotifyFlags ) +{ + GetUndoMgr()->NotifyState( nNotifyFlags ); +} + +inline CClipboardManager *CDataModel::GetClipboardMgr() +{ + return &m_ClipboardMgr; +} + +inline const CClipboardManager *CDataModel::GetClipboardMgr() const +{ + return &m_ClipboardMgr; +} + + +//----------------------------------------------------------------------------- +// Methods of DmElement which are public to datamodel +//----------------------------------------------------------------------------- +class CDmeElementAccessor +{ +public: + static void Purge( CDmElement *pElement ) { pElement->Purge(); } + static void SetId( CDmElement *pElement, const DmObjectId_t &id ) { pElement->SetId( id ); } + static bool IsDirty( const CDmElement *pElement ) { return pElement->IsDirty(); } + static void MarkDirty( CDmElement *pElement, bool dirty = true ) { pElement->MarkDirty( dirty ); } + static void MarkAttributesClean( CDmElement *pElement ) { pElement->MarkAttributesClean(); } + static void MarkBeingUnserialized( CDmElement *pElement, bool beingUnserialized = true ) { pElement->MarkBeingUnserialized( beingUnserialized ); } + static bool IsBeingUnserialized( const CDmElement *pElement ) { return pElement->IsBeingUnserialized(); } + static void AddAttributeByPtr( CDmElement *pElement, CDmAttribute *ptr ) { pElement->AddAttributeByPtr( ptr ); } + static void RemoveAttributeByPtrNoDelete( CDmElement *pElement, CDmAttribute *ptr ) { pElement->RemoveAttributeByPtrNoDelete( ptr); } + static void ChangeHandle( CDmElement *pElement, DmElementHandle_t handle ) { pElement->ChangeHandle( handle ); } + static DmElementReference_t *GetReference( CDmElement *pElement ) { return pElement->GetReference(); } + static void SetReference( CDmElement *pElement, const DmElementReference_t &ref ) { pElement->SetReference( ref ); } + static int EstimateMemoryUsage( CDmElement *pElement, CUtlHash< DmElementHandle_t > &visited, TraversalDepth_t depth, int *pCategories ) { return pElement->EstimateMemoryUsage( visited, depth, pCategories ); } + static void PerformConstruction( CDmElement *pElement ) { pElement->PerformConstruction(); } + static void PerformDestruction( CDmElement *pElement ) { pElement->PerformDestruction(); } +}; + +#endif // DATAMODEL_H |