summaryrefslogtreecommitdiff
path: root/public/datamodel/dmattribute.h
diff options
context:
space:
mode:
Diffstat (limited to 'public/datamodel/dmattribute.h')
-rw-r--r--public/datamodel/dmattribute.h768
1 files changed, 768 insertions, 0 deletions
diff --git a/public/datamodel/dmattribute.h b/public/datamodel/dmattribute.h
new file mode 100644
index 0000000..e383eab
--- /dev/null
+++ b/public/datamodel/dmattribute.h
@@ -0,0 +1,768 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#ifndef DMATTRIBUTE_H
+#define DMATTRIBUTE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "datamodel/attributeflags.h"
+#include "datamodel/idatamodel.h"
+#include "datamodel/dmattributetypes.h"
+#include "datamodel/dmelement.h"
+#include "datamodel/dmvar.h"
+#include "tier1/utlhash.h"
+
+//-----------------------------------------------------------------------------
+// Fast dynamic cast
+//-----------------------------------------------------------------------------
+template< class E >
+inline E *CastElement( CDmElement *pElement )
+{
+ if ( pElement && pElement->IsA( E::GetStaticTypeSymbol() ) )
+ return static_cast< E* >( pElement );
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// type-safe element creation and accessor helpers - infers type name string from actual type
+//-----------------------------------------------------------------------------
+template< class E >
+inline E *GetElement( DmElementHandle_t hElement )
+{
+ CDmElement *pElement = g_pDataModel->GetElement( hElement );
+ return CastElement< E >( pElement );
+}
+
+//-----------------------------------------------------------------------------
+// Typesafe element creation + destruction
+//-----------------------------------------------------------------------------
+template< class E >
+inline E *CreateElement( const char *pObjectName, DmFileId_t fileid = DMFILEID_INVALID, const DmObjectId_t *pObjectID = NULL )
+{
+ return GetElement< E >( g_pDataModel->CreateElement( E::GetStaticTypeSymbol(), pObjectName, fileid, pObjectID ) );
+}
+
+template< class E >
+inline E *CreateElement( const char *pElementType, const char *pObjectName, DmFileId_t fileid = DMFILEID_INVALID, const DmObjectId_t *pObjectID = NULL )
+{
+ return GetElement< E >( g_pDataModel->CreateElement( pElementType, pObjectName, fileid, pObjectID ) );
+}
+
+
+//-----------------------------------------------------------------------------
+// Used for attribute change callbacks
+//-----------------------------------------------------------------------------
+typedef unsigned short DmMailingList_t;
+enum
+{
+ DMMAILINGLIST_INVALID = (DmMailingList_t)~0
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: A general purpose pAttribute. Eventually will be extensible to arbitrary user types
+//-----------------------------------------------------------------------------
+class CDmAttribute
+{
+public:
+ // Returns the type
+ DmAttributeType_t GetType() const;
+ const char *GetTypeString() const;
+ template< class T > bool IsA() const;
+
+ // Returns the name. NOTE: The utlsymbol
+ // can be turned into a string by using g_pDataModel->String();
+ const char *GetName() const;
+ UtlSymId_t GetNameSymbol() const;
+ void SetName( const char *newName );
+
+ // Gets the attribute value
+ // NOTE: GetValueUntyped is used with GetType() for use w/ SetValue( type, void* )
+ template< class T > const T& GetValue() const;
+ template< class T > const T& GetValue( const T& defaultValue ) const;
+ const char *GetValueString() const;
+ template< class E > E *GetValueElement() const;
+ const void *GetValueUntyped() const;
+
+ // Sets the attribute value
+ template< class T > void SetValue( const T &value );
+ template< class E > void SetValue( E* pValue );
+ void SetValue( const void *pValue, size_t nSize );
+
+ // Copies w/ type conversion (if possible) from another attribute
+ void SetValue( const CDmAttribute *pAttribute );
+ void SetValue( CDmAttribute *pAttribute );
+ void SetValue( DmAttributeType_t valueType, const void *pValue );
+
+ // Sets the attribute to its default value based on its type
+ void SetToDefaultValue();
+
+ // Convert to and from string
+ void SetValueFromString( const char *pValue );
+ const char *GetValueAsString( char *pBuffer, size_t nBufLen ) const;
+
+ // Used for element and element array attributes; it specifies which type of
+ // elements are valid to be referred to by this attribute
+ void SetElementTypeSymbol( UtlSymId_t typeSymbol );
+ UtlSymId_t GetElementTypeSymbol() const;
+
+ // Returns the next attribute
+ CDmAttribute *NextAttribute();
+ const CDmAttribute *NextAttribute() const;
+
+ // Returns the owner
+ CDmElement *GetOwner();
+
+ // Methods related to flags
+ void AddFlag( int flags );
+ void RemoveFlag( int flags );
+ void ClearFlags();
+ int GetFlags() const;
+ bool IsFlagSet( int flags ) const;
+
+ // Serialization
+ bool Serialize( CUtlBuffer &buf ) const;
+ bool Unserialize( CUtlBuffer &buf );
+
+ // Serialization of a single element.
+ // First version of UnserializeElement adds to tail if it worked
+ // Second version overwrites, but does not add, the element at the specified index
+ bool SerializeElement( int nElement, CUtlBuffer &buf ) const;
+ bool UnserializeElement( CUtlBuffer &buf );
+ bool UnserializeElement( int nElement, CUtlBuffer &buf );
+
+ // Does this attribute serialize on multiple lines?
+ bool SerializesOnMultipleLines() const;
+
+ // Get the attribute/create an attribute handle
+ DmAttributeHandle_t GetHandle( bool bCreate = true );
+
+ // Notify external elements upon change ( Calls OnAttributeChanged )
+ // Pass false here to stop notification
+ void NotifyWhenChanged( DmElementHandle_t h, bool bNotify );
+
+ // estimate memory overhead
+ int EstimateMemoryUsage( TraversalDepth_t depth ) const;
+
+private:
+ // Class factory
+ static CDmAttribute *CreateAttribute( CDmElement *pOwner, DmAttributeType_t type, const char *pAttributeName );
+ static CDmAttribute *CreateExternalAttribute( CDmElement *pOwner, DmAttributeType_t type, const char *pAttributeName, void *pExternalMemory );
+ static void DestroyAttribute( CDmAttribute *pAttribute );
+
+ // Constructor, destructor
+ CDmAttribute( CDmElement *pOwner, DmAttributeType_t type, const char *pAttributeName );
+ CDmAttribute( CDmElement *pOwner, DmAttributeType_t type, const char *pAttributeName, void *pMemory );
+ ~CDmAttribute();
+
+ // Used when constructing CDmAttributes
+ void Init( CDmElement *pOwner, DmAttributeType_t type, const char *pAttributeName );
+
+ // Used when shutting down, indicates DmAttributeHandle_t referring to this are invalid
+ void InvalidateHandle();
+
+ // Used when shutting down, indicates no more change notifications will be sent to listening elements
+ void CleanupMailingList();
+
+ // Called when the attribute changes
+ void PreChanged();
+ void OnChanged( bool bArrayCountChanged = false, bool bIsTopological = false );
+
+ // Is modification allowed in this phase?
+ bool ModificationAllowed() const;
+
+ // Mark the attribute as being dirty
+ bool MarkDirty();
+
+ // Is the data inline in a containing element class?
+ bool IsDataInline() const;
+
+ // Allocates, frees internal data storage
+ void CreateAttributeData();
+ void DeleteAttributeData();
+
+ // Gets at the internal data storage
+ void* GetAttributeData();
+ const void* GetAttributeData() const;
+ template < class T > typename CDmAttributeInfo< T >::StorageType_t* GetData();
+ template < class T > const typename CDmAttributeInfo< T >::StorageType_t* GetData() const;
+ template < class T > typename CDmAttributeInfo< CUtlVector< T > >::StorageType_t* GetArrayData();
+ template < class T > const typename CDmAttributeInfo< CUtlVector< T > >::StorageType_t* GetArrayData() const;
+
+ // Used by CDmElement to manage the list of attributes it owns
+ CDmAttribute **GetNextAttributeRef();
+
+ // Implementational function used for memory consumption estimation computation
+ int EstimateMemoryUsageInternal( CUtlHash< DmElementHandle_t > &visited, TraversalDepth_t depth, int *pCategories ) const;
+
+ // Called by elements after unserialization of their attributes is complete
+ void OnUnserializationFinished();
+
+ template< class T > bool IsTypeConvertable() const;
+ template< class T > bool ShouldModify( const T& src );
+ template< class T > void CopyData( const T& src );
+ template< class T > void CopyDataOut( T& dest ) const;
+
+private:
+ CDmAttribute *m_pNext;
+ void *m_pData;
+ CDmElement *m_pOwner;
+ int m_nFlags;
+ DmAttributeHandle_t m_Handle;
+ CUtlSymbol m_Name;
+ DmMailingList_t m_hMailingList;
+
+ friend class CDmElement;
+ friend class CDmAttributeAccessor;
+ template< class T > friend class CDmrElementArray;
+ template< class E > friend class CDmrElementArrayConst;
+ template< class T > friend class CDmaArrayAccessor;
+ template< class T, class B > friend class CDmrDecorator;
+ template< class T, class B > friend class CDmrDecoratorConst;
+ template< class T > friend class CDmArrayAttributeOp;
+};
+
+
+//-----------------------------------------------------------------------------
+// Inline methods
+//-----------------------------------------------------------------------------
+inline DmAttributeType_t CDmAttribute::GetType() const
+{
+ return (DmAttributeType_t)( m_nFlags & FATTRIB_TYPEMASK );
+}
+
+template< class T > inline bool CDmAttribute::IsA() const
+{
+ return GetType() == CDmAttributeInfo< T >::AttributeType();
+}
+
+inline const char *CDmAttribute::GetName() const
+{
+ return g_pDataModel->GetString( m_Name );
+}
+
+inline UtlSymId_t CDmAttribute::GetNameSymbol() const
+{
+ return m_Name;
+}
+
+
+//-----------------------------------------------------------------------------
+// Iteration
+//-----------------------------------------------------------------------------
+inline CDmAttribute *CDmAttribute::NextAttribute()
+{
+ return m_pNext;
+}
+
+inline const CDmAttribute *CDmAttribute::NextAttribute() const
+{
+ return m_pNext;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the owner
+//-----------------------------------------------------------------------------
+inline CDmElement *CDmAttribute::GetOwner()
+{
+ return m_pOwner;
+}
+
+
+//-----------------------------------------------------------------------------
+// Value getting methods
+//-----------------------------------------------------------------------------
+template< class T >
+inline const T& CDmAttribute::GetValue( const T& defaultValue ) const
+{
+ if ( GetType() == ( DmAttributeType_t )( CDmAttributeInfo< T >::ATTRIBUTE_TYPE ) )
+ return *reinterpret_cast< const T* >( m_pData );
+
+ if ( IsTypeConvertable< T >() )
+ {
+ static T tempVal;
+ CopyDataOut( tempVal );
+ return tempVal;
+ }
+
+ Assert( 0 );
+ return defaultValue;
+}
+
+template< class T >
+inline const T& CDmAttribute::GetValue() const
+{
+ static CDmaVar< T > defaultVal;
+ return GetValue( defaultVal.Get() );
+}
+
+inline const char *CDmAttribute::GetValueString() const
+{
+ Assert( GetType() == AT_STRING );
+ if ( GetType() != AT_STRING )
+ return NULL;
+
+ return GetValue< CUtlString >();
+}
+
+// used with GetType() for use w/ SetValue( type, void* )
+inline const void* CDmAttribute::GetValueUntyped() const
+{
+ return m_pData;
+}
+
+template< class E >
+inline E* CDmAttribute::GetValueElement() const
+{
+ Assert( GetType() == AT_ELEMENT );
+ if ( GetType() == AT_ELEMENT )
+ return GetElement<E>( this->GetValue< DmElementHandle_t >() );
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Value setting methods
+//-----------------------------------------------------------------------------
+template< class E >
+inline void CDmAttribute::SetValue( E* pValue )
+{
+ Assert( GetType() == AT_ELEMENT );
+ if ( GetType() == AT_ELEMENT )
+ {
+ SetValue( pValue ? pValue->GetHandle() : DMELEMENT_HANDLE_INVALID );
+ }
+}
+
+template<>
+inline void CDmAttribute::SetValue( const char *pValue )
+{
+ int nLen = pValue ? Q_strlen( pValue ) + 1 : 0;
+ CUtlString str( pValue, nLen );
+ return SetValue( str );
+}
+
+template<>
+inline void CDmAttribute::SetValue( char *pValue )
+{
+ return SetValue( (const char *)pValue );
+}
+
+inline void CDmAttribute::SetValue( const void *pValue, size_t nSize )
+{
+ CUtlBinaryBlock buf( pValue, (int)nSize );
+ return SetValue( buf );
+}
+
+
+//-----------------------------------------------------------------------------
+// Methods related to flags
+//-----------------------------------------------------------------------------
+inline void CDmAttribute::AddFlag( int nFlags )
+{
+ m_nFlags |= nFlags;
+}
+
+inline void CDmAttribute::RemoveFlag( int nFlags )
+{
+ m_nFlags &= ~nFlags;
+}
+
+inline void CDmAttribute::ClearFlags()
+{
+ m_nFlags = 0;
+}
+
+inline int CDmAttribute::GetFlags() const
+{
+ return m_nFlags;
+}
+
+inline bool CDmAttribute::IsFlagSet( int nFlags ) const
+{
+ return ( nFlags & m_nFlags ) ? true : false;
+}
+
+inline bool CDmAttribute::IsDataInline() const
+{
+ return !IsFlagSet(FATTRIB_EXTERNAL);
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets at the internal data storage
+//-----------------------------------------------------------------------------
+inline void* CDmAttribute::GetAttributeData()
+{
+ return m_pData;
+}
+
+inline const void* CDmAttribute::GetAttributeData() const
+{
+ return m_pData;
+}
+
+template < class T >
+inline typename CDmAttributeInfo< T >::StorageType_t* CDmAttribute::GetData()
+{
+ return ( typename CDmAttributeInfo< T >::StorageType_t* )m_pData;
+}
+
+template < class T >
+inline typename CDmAttributeInfo< CUtlVector< T > >::StorageType_t* CDmAttribute::GetArrayData()
+{
+ return ( typename CDmAttributeInfo< CUtlVector< T > >::StorageType_t* )m_pData;
+}
+
+template < class T >
+inline const typename CDmAttributeInfo< T >::StorageType_t* CDmAttribute::GetData() const
+{
+ return ( const typename CDmAttributeInfo< T >::StorageType_t* )m_pData;
+}
+
+template < class T >
+inline const typename CDmAttributeInfo< CUtlVector< T > >::StorageType_t* CDmAttribute::GetArrayData() const
+{
+ return ( const typename CDmAttributeInfo< CUtlVector< T > >::StorageType_t* )m_pData;
+}
+
+
+//-----------------------------------------------------------------------------
+// Used by CDmElement to manage the list of attributes it owns
+//-----------------------------------------------------------------------------
+inline CDmAttribute **CDmAttribute::GetNextAttributeRef()
+{
+ return &m_pNext;
+}
+
+
+//-----------------------------------------------------------------------------
+// helper function for determining which attributes/elements to traverse during copy/find/save/etc.
+//-----------------------------------------------------------------------------
+inline bool ShouldTraverse( const CDmAttribute *pAttr, TraversalDepth_t depth )
+{
+ switch ( depth )
+ {
+ case TD_NONE:
+ return false;
+
+ case TD_SHALLOW:
+ if ( !pAttr->IsFlagSet( FATTRIB_MUSTCOPY ) )
+ return false;
+ // fall-through intentional
+ case TD_DEEP:
+ if ( pAttr->IsFlagSet( FATTRIB_NEVERCOPY ) )
+ return false;
+ // fall-through intentional
+ case TD_ALL:
+ return true;
+ }
+
+ Assert( 0 );
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets attributes
+//-----------------------------------------------------------------------------
+inline CDmAttribute *CDmElement::GetAttribute( const char *pAttributeName, DmAttributeType_t type )
+{
+ CDmAttribute *pAttribute = FindAttribute( pAttributeName );
+ if ( ( type != AT_UNKNOWN ) && pAttribute && ( pAttribute->GetType() != type ) )
+ return NULL;
+ return pAttribute;
+}
+
+inline const CDmAttribute *CDmElement::GetAttribute( const char *pAttributeName, DmAttributeType_t type ) const
+{
+ CDmAttribute *pAttribute = FindAttribute( pAttributeName );
+ if ( ( type != AT_UNKNOWN ) && pAttribute && ( pAttribute->GetType() != type ) )
+ return NULL;
+ return pAttribute;
+}
+
+
+//-----------------------------------------------------------------------------
+// AddAttribute calls
+//-----------------------------------------------------------------------------
+inline CDmAttribute *CDmElement::AddAttribute( const char *pAttributeName, DmAttributeType_t type )
+{
+ CDmAttribute *pAttribute = FindAttribute( pAttributeName );
+ if ( pAttribute )
+ return ( pAttribute->GetType() == type ) ? pAttribute : NULL;
+ pAttribute = CreateAttribute( pAttributeName, type );
+ return pAttribute;
+}
+
+template< class E > inline CDmAttribute *CDmElement::AddAttributeElement( const char *pAttributeName )
+{
+ CDmAttribute *pAttribute = AddAttribute( pAttributeName, AT_ELEMENT );
+ if ( !pAttribute )
+ return NULL;
+
+ // FIXME: If the attribute exists but has a different element type symbol, should we complain?
+ pAttribute->SetElementTypeSymbol( E::GetStaticTypeSymbol() );
+ return pAttribute;
+}
+
+template< class E > inline CDmAttribute *CDmElement::AddAttributeElementArray( const char *pAttributeName )
+{
+ CDmAttribute *pAttribute = AddAttribute( pAttributeName, AT_ELEMENT_ARRAY );
+ if ( !pAttribute )
+ return NULL;
+
+ // FIXME: If the attribute exists but has a different element type symbol, should we complain?
+ pAttribute->SetElementTypeSymbol( E::GetStaticTypeSymbol() );
+ return pAttribute;
+}
+
+//-----------------------------------------------------------------------------
+// GetValue methods
+//-----------------------------------------------------------------------------
+
+template< class T >
+inline const T& CDmElement::GetValue( const char *pAttributeName ) const
+{
+ static CDmaVar<T> defaultVal;
+ return GetValue( pAttributeName, defaultVal.Get() );
+}
+
+inline const char *CDmElement::GetValueString( const char *pAttributeName ) const
+{
+ return GetValue<CUtlString>( pAttributeName ).Get();
+}
+
+template< class E >
+inline E* CDmElement::GetValueElement( const char *pAttributeName ) const
+{
+ DmElementHandle_t h = GetValue< DmElementHandle_t >( pAttributeName );
+ return GetElement<E>( h );
+}
+
+
+template< class T >
+inline const T& CDmElement::GetValue( const char *pAttributeName, const T& defaultVal ) const
+{
+ const CDmAttribute *pAttribute = FindAttribute( pAttributeName );
+ if ( pAttribute != NULL )
+ return pAttribute->GetValue<T>();
+ return defaultVal;
+}
+
+//-----------------------------------------------------------------------------
+// SetValue methods
+//-----------------------------------------------------------------------------
+template< class T >
+inline CDmAttribute* CDmElement::SetValue( const char *pAttributeName, const T& value )
+{
+ CDmAttribute *pAttribute = FindAttribute( pAttributeName );
+ if ( !pAttribute )
+ {
+ pAttribute = CreateAttribute( pAttributeName, CDmAttributeInfo<T>::AttributeType() );
+ }
+ if ( pAttribute )
+ {
+ pAttribute->SetValue( value );
+ return pAttribute;
+ }
+ return NULL;
+}
+
+template< class E >
+inline CDmAttribute* CDmElement::SetValue( const char *pAttributeName, E* pElement )
+{
+ DmElementHandle_t hElement = pElement ? pElement->GetHandle() : DMELEMENT_HANDLE_INVALID;
+ return SetValue( pAttributeName, hElement );
+}
+
+template<>
+inline CDmAttribute* CDmElement::SetValue( const char *pAttributeName, const char *pValue )
+{
+ int nLen = pValue ? Q_strlen( pValue ) + 1 : 0;
+ CUtlString str( pValue, nLen );
+ return SetValue( pAttributeName, str );
+}
+
+template<>
+inline CDmAttribute* CDmElement::SetValue( const char *pAttributeName, char *pValue )
+{
+ return SetValue( pAttributeName, (const char *)pValue );
+}
+
+inline CDmAttribute* CDmElement::SetValue( const char *pAttributeName, const void *pValue, size_t nSize )
+{
+ CUtlBinaryBlock buf( pValue, (int)nSize );
+ return SetValue( pAttributeName, buf );
+}
+
+
+//-----------------------------------------------------------------------------
+// AddValue methods( set value if not found )
+//-----------------------------------------------------------------------------
+template< class T >
+inline CDmAttribute* CDmElement::InitValue( const char *pAttributeName, const T& value )
+{
+ CDmAttribute *pAttribute = GetAttribute( pAttributeName );
+ if ( !pAttribute )
+ return SetValue( pAttributeName, value );
+ return pAttribute;
+}
+
+template< class E >
+inline CDmAttribute* CDmElement::InitValue( const char *pAttributeName, E* pElement )
+{
+ DmElementHandle_t hElement = pElement ? pElement->GetHandle() : DMELEMENT_HANDLE_INVALID;
+ return InitValue( pAttributeName, hElement );
+}
+
+inline CDmAttribute* CDmElement::InitValue( const char *pAttributeName, const void *pValue, size_t size )
+{
+ CDmAttribute *pAttribute = GetAttribute( pAttributeName );
+ if ( !pAttribute )
+ return SetValue( pAttributeName, pValue, size );
+ return pAttribute;
+}
+
+template< class T >
+T *FindReferringElement( CDmElement *pElement, UtlSymId_t symAttrName, bool bMustBeInSameFile = true )
+{
+ DmAttributeReferenceIterator_t i = g_pDataModel->FirstAttributeReferencingElement( pElement->GetHandle() );
+ while ( i != DMATTRIBUTE_REFERENCE_ITERATOR_INVALID )
+ {
+ CDmAttribute *pAttribute = g_pDataModel->GetAttribute( i );
+ CDmElement *pDmeParent = pAttribute->GetOwner();
+ if ( pDmeParent && pAttribute->GetNameSymbol() == symAttrName )
+ {
+ T *pParent = CastElement< T >( pDmeParent );
+ if ( pParent )
+ {
+ if ( !bMustBeInSameFile || ( pParent->GetFileId() == pElement->GetFileId() ) )
+ return pParent;
+ }
+ }
+ i = g_pDataModel->NextAttributeReferencingElement( i );
+ }
+
+ return NULL;
+}
+
+template< class T >
+T *FindAncestorReferencingElement( CDmElement *target )
+{
+ if ( !target )
+ return NULL;
+
+ for ( DmAttributeReferenceIterator_t it = g_pDataModel->FirstAttributeReferencingElement( target->GetHandle() );
+ it != DMATTRIBUTE_REFERENCE_ITERATOR_INVALID;
+ it = g_pDataModel->NextAttributeReferencingElement( it ) )
+ {
+ CDmAttribute *attr = g_pDataModel->GetAttribute( it );
+ Assert( attr );
+ CDmElement *element = attr->GetOwner();
+ Assert( element );
+ if ( !element )
+ continue;
+ T *t = CastElement< T >( element );
+ if ( !t )
+ continue;
+
+ return t;
+ }
+ return NULL;
+}
+
+template< class T >
+T *FindAncestorReferencingElement_R_Impl( CUtlRBTree< CDmElement * >& visited, CDmElement *check )
+{
+ if ( visited.Find( check ) != visited.InvalidIndex() )
+ return NULL;
+
+ visited.Insert( check );
+
+ // Pass one, see if it's in this ancestor list
+ DmAttributeReferenceIterator_t it;
+ for ( it = g_pDataModel->FirstAttributeReferencingElement( check->GetHandle() );
+ it != DMATTRIBUTE_REFERENCE_ITERATOR_INVALID;
+ it = g_pDataModel->NextAttributeReferencingElement( it ) )
+ {
+ CDmAttribute *attr = g_pDataModel->GetAttribute( it );
+ Assert( attr );
+ CDmElement *element = attr->GetOwner();
+ Assert( element );
+ if ( !element )
+ continue;
+ T *t = CastElement< T >( element );
+ if ( !t )
+ continue;
+
+ return t;
+ }
+
+ for ( it = g_pDataModel->FirstAttributeReferencingElement( check->GetHandle() );
+ it != DMATTRIBUTE_REFERENCE_ITERATOR_INVALID;
+ it = g_pDataModel->NextAttributeReferencingElement( it ) )
+ {
+ CDmAttribute *attr = g_pDataModel->GetAttribute( it );
+ Assert( attr );
+ CDmElement *element = attr->GetOwner();
+ Assert( element );
+ if ( !element )
+ continue;
+
+ T *found = FindAncestorReferencingElement_R_Impl< T >( visited, element );
+ if ( found )
+ return found;
+ }
+ return NULL;
+}
+
+
+template< class T >
+void FindAncestorsReferencingElement( CDmElement *target, CUtlVector< T* >& list )
+{
+ if ( !target )
+ return;
+
+ list.RemoveAll();
+ for ( DmAttributeReferenceIterator_t it = g_pDataModel->FirstAttributeReferencingElement( target->GetHandle() );
+ it != DMATTRIBUTE_REFERENCE_ITERATOR_INVALID;
+ it = g_pDataModel->NextAttributeReferencingElement( it ) )
+ {
+ CDmAttribute *attr = g_pDataModel->GetAttribute( it );
+ Assert( attr );
+ CDmElement *element = attr->GetOwner();
+ Assert( element );
+ if ( !element )
+ continue;
+ T* t = CastElement< T >( element );
+ if ( !t )
+ continue;
+
+ if ( list.Find( t ) != list.InvalidIndex() )
+ continue;
+
+ list.AddToTail( t );
+ }
+}
+
+
+template< class T >
+T *FindAncestorReferencingElement_R( CDmElement *target )
+{
+ if ( !target )
+ return NULL;
+
+ CUtlRBTree< CDmElement * > visited( 0, 0, DefLessFunc( CDmElement * ) );
+ return FindAncestorReferencingElement_R_Impl< T >( visited, target );
+}
+
+
+#endif // DMATTRIBUTE_H