718 lines
25 KiB
C++
718 lines
25 KiB
C++
//========= Copyright Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose:
|
|
//
|
|
//=============================================================================
|
|
|
|
#ifndef DMATTRIBUTE_H
|
|
#define DMATTRIBUTE_H
|
|
#ifdef _WIN32
|
|
#pragma once
|
|
#endif
|
|
|
|
#include "datamodel/attributeflags.h"
|
|
#include "datamodel/dmattributetypes.h"
|
|
#include "datamodel/dmelement.h"
|
|
#include "datamodel/dmvar.h"
|
|
#include "datamodel/idatamodel.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
|