forked from hitmen047/Source-PlusPlus
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdmelement.h
618 lines (512 loc) · 23.2 KB
/
dmelement.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#ifndef DMELEMENT_H
#define DMELEMENT_H
#ifdef _WIN32
#pragma once
#endif
#include "tier1/utlmap.h"
#include "tier1/utlhash.h"
#include "tier1/utlvector.h"
#include "tier1/utlsymbol.h"
#include "datamodel/attributeflags.h"
#include "datamodel/idatamodel.h"
#include "datamodel/dmvar.h"
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
typedef bool (CDmElement::*pfnCommandMethod)( const char *command, const char *args );
// element/element array traversal path item - assumes the full path does NOT contain cycles
struct ElementPathItem_t
{
ElementPathItem_t( DmElementHandle_t hElem = DMELEMENT_HANDLE_INVALID,
DmAttributeHandle_t hAttr = DMATTRIBUTE_HANDLE_INVALID,
int idx = -1 )
: hElement( hElem ), hAttribute( hAttr ), nIndex( idx )
{
}
// only uses hElement so that it can be used to search for elements
bool operator==( const ElementPathItem_t &that ) const
{
return hElement == that.hElement;
}
DmElementHandle_t hElement;
DmAttributeHandle_t hAttribute;
int nIndex;
};
//-----------------------------------------------------------------------------
// singly-linked attribute list
//-----------------------------------------------------------------------------
struct DmAttributeList_t
{
DmAttributeList_t() : m_hAttribute( DMATTRIBUTE_HANDLE_INVALID ), m_pNext( NULL ) {}
DmAttributeHandle_t m_hAttribute;
DmAttributeList_t *m_pNext;
};
//-----------------------------------------------------------------------------
// helper class to allow CDmeHandle access to g_pDataModelImp
//-----------------------------------------------------------------------------
class CDmeElementRefHelper
{
protected:
void Ref ( DmElementHandle_t hElement, bool bStrong );
void Unref( DmElementHandle_t hElement, bool bStrong );
};
//-----------------------------------------------------------------------------
// element reference struct - containing attribute referrers and handle refcount
//-----------------------------------------------------------------------------
struct DmElementReference_t
{
explicit DmElementReference_t( DmElementHandle_t hElement = DMELEMENT_HANDLE_INVALID ) :
m_hElement( hElement ), m_nWeakHandleCount( 0 ), m_nStrongHandleCount( 0 )
{
}
DmElementReference_t( const DmElementReference_t &that ) :
m_hElement( that.m_hElement ), m_nWeakHandleCount( that.m_nWeakHandleCount ),
m_nStrongHandleCount( that.m_nStrongHandleCount ), m_attributes( that.m_attributes )
{
}
DmElementReference_t &operator=( const DmElementReference_t &that )
{
m_hElement = that.m_hElement;
m_nWeakHandleCount = that.m_nWeakHandleCount;
m_nStrongHandleCount = that.m_nStrongHandleCount;
m_attributes.m_hAttribute = that.m_attributes.m_hAttribute;
m_attributes.m_pNext = that.m_attributes.m_pNext;
return *this;
}
~DmElementReference_t()
{
// Assert( !IsStronglyReferenced() );
}
void AddAttribute( CDmAttribute *pAttribute );
void RemoveAttribute( CDmAttribute *pAttribute );
bool IsStronglyReferenced() // should this element be kept around (even if it's DmElementHandle_t is invalidated)
{
return m_attributes.m_hAttribute != DMATTRIBUTE_HANDLE_INVALID || m_nStrongHandleCount > 0;
}
bool IsWeaklyReferenced() // should we keep this element's DmElementHandle_t mapped to it's id (even if the element is deleted)
{
return IsStronglyReferenced() || m_nWeakHandleCount > 0;
}
int EstimateMemoryOverhead()
{
int nBytes = 0;
for ( DmAttributeList_t *pLink = m_attributes.m_pNext; pLink; pLink = pLink->m_pNext )
{
nBytes += sizeof( DmAttributeList_t );
}
return nBytes;
}
DmElementHandle_t m_hElement;
unsigned short m_nWeakHandleCount; // CDmeHandle<T> - for auto-hookup once the element comes back, mainly used by UI
unsigned short m_nStrongHandleCount; // CDmeCountedElementRef - for preventing elements from being truly deleted, mainly used by undo and file root
DmAttributeList_t m_attributes;
};
//-----------------------------------------------------------------------------
// Base DmElement we inherit from in higher-level classes
//-----------------------------------------------------------------------------
class CDmElement
{
public:
// Can be overridden by derived classes
virtual void OnAttributeChanged( CDmAttribute *pAttribute ) {}
virtual void PreAttributeChanged( CDmAttribute *pAttribute ) {}
virtual void OnAttributeArrayElementAdded( CDmAttribute *pAttribute, int nFirstElem, int nLastElem ) {}
virtual void OnAttributeArrayElementRemoved( CDmAttribute *pAttribute, int nFirstElem, int nLastElem ) {}
virtual void Resolve() {}
virtual bool IsA( UtlSymId_t typeSymbol ) const;
virtual int GetInheritanceDepth( UtlSymId_t typeSymbol ) const;
virtual void OnElementUnserialized() {}
virtual int AllocatedSize() const { return sizeof( CDmElement ); }
// Returns the element handle
DmElementHandle_t GetHandle() const;
// Attribute iteration, finding
// NOTE: Passing a type into GetAttribute will return NULL if the attribute exists but isn't that type
bool HasAttribute( const char *pAttributeName, DmAttributeType_t type = AT_UNKNOWN ) const;
CDmAttribute *GetAttribute( const char *pAttributeName, DmAttributeType_t type = AT_UNKNOWN );
const CDmAttribute *GetAttribute( const char *pAttributeName, DmAttributeType_t type = AT_UNKNOWN ) const;
int AttributeCount() const;
CDmAttribute* FirstAttribute();
const CDmAttribute* FirstAttribute() const;
// Element name, type, ID
// WARNING: SetType() should only be used by format conversion methods (dmxconvert)
UtlSymId_t GetType() const;
const char * GetTypeString() const;
const char * GetName() const;
const DmObjectId_t& GetId() const;
void SetType( const char *pType );
void SetName( const char* pName );
// Attribute management
CDmAttribute * AddAttribute( const char *pAttributeName, DmAttributeType_t type );
template< class E > CDmAttribute* AddAttributeElement( const char *pAttributeName );
template< class E > CDmAttribute* AddAttributeElementArray( const char *pAttributeName );
void RemoveAttribute( const char *pAttributeName );
void RemoveAttributeByPtr( CDmAttribute *pAttributeName );
void RenameAttribute( const char *pAttributeName, const char *pNewName );
// get attribute value
template< class T > const T& GetValue( const char *pAttributeName ) const;
template< class T > const T& GetValue( const char *pAttributeName, const T& defaultValue ) const;
const char * GetValueString( const char *pAttributeName ) const;
template< class E > E* GetValueElement( const char *pAttributeName ) const;
// set attribute value
CDmAttribute* SetValue( const char *pAttributeName, const void *value, size_t size );
template< class T > CDmAttribute* SetValue( const char *pAttributeName, const T& value );
template< class E > CDmAttribute* SetValue( const char *pAttributeName, E* value );
// set attribute value if the attribute doesn't already exist
CDmAttribute* InitValue( const char *pAttributeName, const void *value, size_t size );
template< class T > CDmAttribute* InitValue( const char *pAttributeName, const T& value );
template< class E > CDmAttribute* InitValue( const char *pAttributeName, E* value );
// Parses an attribute from a string
// Doesn't create an attribute if it doesn't exist and always preserves attribute type
void SetValueFromString( const char *pAttributeName, const char *value );
const char *GetValueAsString( const char *pAttributeName, char *pBuffer, size_t buflen ) const;
// Helpers for our RTTI
template< class E > bool IsA() const;
bool IsA( const char *pTypeName ) const;
int GetInheritanceDepth( const char *pTypeName ) const;
static CUtlSymbol GetStaticTypeSymbol();
// Indicates whether this element should be copied or not
void SetShared( bool bShared );
bool IsShared() const;
// Copies an element and all its attributes
CDmElement* Copy( TraversalDepth_t depth = TD_DEEP ) const;
// Copies attributes from a specified element
void CopyAttributesTo( CDmElement *pCopy, TraversalDepth_t depth = TD_DEEP ) const;
// recursively set fileid's, with option to only change elements in the matched file
void SetFileId( DmFileId_t fileid, TraversalDepth_t depth, bool bOnlyIfMatch = false );
DmFileId_t GetFileId() const;
bool IsAccessible() const;
void MarkAccessible( bool bAccessible );
void MarkAccessible( TraversalDepth_t depth = TD_ALL );
// returns the first path to the element found traversing all element/element
// array attributes - not necessarily the shortest.
// cycle-safe (skips any references to elements in the current path)
// but may re-traverse elements via different paths
bool FindElement( const CDmElement *pElement, CUtlVector< ElementPathItem_t > &elementPath, TraversalDepth_t depth ) const;
bool FindReferer( DmElementHandle_t hElement, CUtlVector< ElementPathItem_t > &elementPath, TraversalDepth_t depth ) const;
void RemoveAllReferencesToElement( CDmElement *pElement );
bool IsStronglyReferenced() { return m_ref.IsStronglyReferenced(); }
// Estimates the memory usage of the element, its attributes, and child elements
int EstimateMemoryUsage( TraversalDepth_t depth = TD_DEEP );
protected:
// NOTE: These are protected to ensure that the factory is the only thing that can create these
CDmElement( DmElementHandle_t handle, const char *objectType, const DmObjectId_t &id, const char *objectName, DmFileId_t fileid );
virtual ~CDmElement();
// Used by derived classes to do construction and setting up CDmaVars
void OnConstruction() { }
void OnDestruction() { }
virtual void PerformConstruction();
virtual void PerformDestruction();
// Internal methods related to RTII
static void SetTypeSymbol( CUtlSymbol sym );
static bool IsA_Implementation( CUtlSymbol typeSymbol );
static int GetInheritanceDepth_Implementation( CUtlSymbol typeSymbol, int nCurrentDepth );
// Internal method for creating a copy of this element
CDmElement* CopyInternal( TraversalDepth_t depth = TD_DEEP ) const;
// helper for making attributevarelementarray cleanup easier
template< class T > static void DeleteAttributeVarElementArray( T &array );
private:
typedef CUtlMap< DmElementHandle_t, DmElementHandle_t, int > CRefMap;
// Bogus constructor
CDmElement();
// internal recursive copy method - builds refmap of old element's handle -> copy's handle, and uses it to fixup references
void CopyAttributesTo( CDmElement *pCopy, CRefMap &refmap, TraversalDepth_t depth ) const;
void CopyElementAttribute( const CDmAttribute *pAttr, CDmAttribute *pCopyAttr, CRefMap &refmap, TraversalDepth_t depth ) const;
void CopyElementArrayAttribute( const CDmAttribute *pAttr, CDmAttribute *pCopyAttr, CRefMap &refmap, TraversalDepth_t depth ) const;
void FixupReferences( CUtlHashFast< DmElementHandle_t > &visited, const CRefMap &refmap, TraversalDepth_t depth );
void SetFileId( DmFileId_t fileid );
void SetFileId_R( CUtlHashFast< DmElementHandle_t > &visited, DmFileId_t fileid, TraversalDepth_t depth, DmFileId_t match, bool bOnlyIfMatch );
CDmAttribute* CreateAttribute( const char *pAttributeName, DmAttributeType_t type );
void RemoveAttribute( CDmAttribute **pAttrRef );
CDmAttribute* AddExternalAttribute( const char *pAttributeName, DmAttributeType_t type, void *pMemory );
CDmAttribute *FindAttribute( const char *pAttributeName ) const;
void Purge();
void SetId( const DmObjectId_t &id );
bool IsDirty() const;
void MarkDirty( bool dirty = true );
void MarkAttributesClean();
void MarkBeingUnserialized( bool beingUnserialized = true );
bool IsBeingUnserialized() const;
// Used by the undo system only.
void AddAttributeByPtr( CDmAttribute *ptr );
void RemoveAttributeByPtrNoDelete( CDmAttribute *ptr );
// Should only be called from datamodel, who will take care of changing the fileset entry as well
void ChangeHandle( DmElementHandle_t handle );
// returns element reference struct w/ list of referrers and handle count
DmElementReference_t* GetReference();
void SetReference( const DmElementReference_t &ref );
// Estimates memory usage
int EstimateMemoryUsage( CUtlHash< DmElementHandle_t > &visited, TraversalDepth_t depth, int *pCategories );
protected:
CDmaString m_Name;
private:
CDmAttribute *m_pAttributes;
DmElementReference_t m_ref;
UtlSymId_t m_Type;
bool m_bDirty : 1;
bool m_bBeingUnserialized : 1;
bool m_bIsAcessible : 1;
unsigned char m_nReserved; // Makes Id be quad aligned
DmObjectId_t m_Id;
DmFileId_t m_fileId;
// Stores the type symbol
static CUtlSymbol m_classType;
// Factories can access our constructors
template <class T> friend class CDmElementFactory;
template <class T> friend class CDmAbstractElementFactory;
template< class T > friend class CDmaVar;
template< class T > friend class CDmaArray;
template< class T > friend class CDmaElementArray;
template< class T, class B > friend class CDmaDecorator;
template< class T > friend class CDmrElementArray;
friend class CDmElementFactoryDefault;
friend class CDmeElementAccessor;
friend class CDmeOperator;
friend void CopyElements( const CUtlVector< CDmElement* > &from, CUtlVector< CDmElement* > &to, TraversalDepth_t depth );
};
inline void DestroyElement( CDmElement *pElement )
{
if ( pElement )
{
g_pDataModel->DestroyElement( pElement->GetHandle() );
}
}
void DestroyElement( CDmElement *pElement, TraversalDepth_t depth );
//-----------------------------------------------------------------------------
// copy groups of elements together so that references between them are maintained
//-----------------------------------------------------------------------------
void CopyElements( const CUtlVector< CDmElement* > &from, CUtlVector< CDmElement* > &to, TraversalDepth_t depth = TD_DEEP );
//-----------------------------------------------------------------------------
// allows elements to chain OnAttributeChanged up to their parents (or at least, referrers)
//-----------------------------------------------------------------------------
void InvokeOnAttributeChangedOnReferrers( DmElementHandle_t hElement, CDmAttribute *pChangedAttr );
//-----------------------------------------------------------------------------
// Returns the type, name, id, fileId
//-----------------------------------------------------------------------------
inline UtlSymId_t CDmElement::GetType() const
{
return m_Type;
}
inline const char *CDmElement::GetTypeString() const
{
return g_pDataModel->GetString( m_Type );
}
inline const char *CDmElement::GetName() const
{
return m_Name.Get();
}
inline void CDmElement::SetName( const char* pName )
{
m_Name.Set( pName );
}
inline const DmObjectId_t& CDmElement::GetId() const
{
return m_Id;
}
inline DmFileId_t CDmElement::GetFileId() const
{
return m_fileId;
}
//-----------------------------------------------------------------------------
// Controls whether the element should be copied by default
//-----------------------------------------------------------------------------
inline void CDmElement::SetShared( bool bShared )
{
if ( bShared )
{
SetValue< bool >( "shared", true );
}
else
{
RemoveAttribute( "shared" );
}
}
inline bool CDmElement::IsShared() const
{
return GetValue< bool >( "shared" ); // if attribute doesn't exist, returns default bool value, which is false
}
//-----------------------------------------------------------------------------
// Copies attributes from a specified element
//-----------------------------------------------------------------------------
inline CDmElement* CDmElement::Copy( TraversalDepth_t depth ) const
{
return CopyInternal( depth );
}
//-----------------------------------------------------------------------------
// RTTI
//-----------------------------------------------------------------------------
inline bool CDmElement::IsA_Implementation( CUtlSymbol typeSymbol )
{
return ( m_classType == typeSymbol ) || ( UTL_INVAL_SYMBOL == typeSymbol );
}
inline int CDmElement::GetInheritanceDepth_Implementation( CUtlSymbol typeSymbol, int nCurrentDepth )
{
return IsA_Implementation( typeSymbol ) ? nCurrentDepth : -1;
}
inline CUtlSymbol CDmElement::GetStaticTypeSymbol()
{
return m_classType;
}
inline bool CDmElement::IsA( const char *pTypeName ) const
{
CUtlSymbol typeSymbol = g_pDataModel->GetSymbol( pTypeName );
return IsA( typeSymbol );
}
template< class E > inline bool CDmElement::IsA() const
{
return IsA( E::GetStaticTypeSymbol() );
}
//-----------------------------------------------------------------------------
// Helper for finding elements that refer to this element
//-----------------------------------------------------------------------------
template< class T >
T *FindReferringElement( CDmElement *pElement, const char *pAttrName, bool bMustBeInSameFile = true )
{
return FindReferringElement< T >( pElement, g_pDataModel->GetSymbol( pAttrName ), bMustBeInSameFile );
}
void RemoveElementFromRefereringAttributes( CDmElement *pElement, bool bPreserveOrder = true );
//-----------------------------------------------------------------------------
//
// element-specific unique name generation methods
//
//-----------------------------------------------------------------------------
// returns startindex if none found, 2 if only "prefix" found, and n+1 if "prefixn" found
int GenerateUniqueNameIndex( const char *prefix, const CUtlVector< DmElementHandle_t > &array, int startindex = -1 );
bool GenerateUniqueName( char *name, int memsize, const char *prefix, const CUtlVector< DmElementHandle_t > &array );
void MakeElementNameUnique( CDmElement *pElement, const char *prefix, const CUtlVector< DmElementHandle_t > &array, bool forceIndex = false );
//-----------------------------------------------------------------------------
// helper for making attributevarelementarray cleanup easier
//-----------------------------------------------------------------------------
template< class T >
inline void CDmElement::DeleteAttributeVarElementArray( T &array )
{
int nElements = array.Count();
for ( int i = 0; i < nElements; ++i )
{
g_pDataModel->DestroyElement( array.GetHandle( i ) );
}
array.RemoveAll();
}
//-----------------------------------------------------------------------------
// Default size computation
//-----------------------------------------------------------------------------
template< class T >
int DmeEstimateMemorySize( T* pElement )
{
return sizeof( T );
}
//-----------------------------------------------------------------------------
// Helper macro to create an element; this is used for elements that are helper base classes
//-----------------------------------------------------------------------------
#define DEFINE_UNINSTANCEABLE_ELEMENT( className, baseClassName ) \
protected: \
className( DmElementHandle_t handle, const char *pElementTypeName, const DmObjectId_t &id, const char *pElementName, DmFileId_t fileid ) : \
baseClassName( handle, pElementTypeName, id, pElementName, fileid ) \
{ \
} \
virtual ~className() \
{ \
} \
void OnConstruction(); \
void OnDestruction(); \
virtual void PerformConstruction() \
{ \
BaseClass::PerformConstruction(); \
OnConstruction(); \
} \
virtual void PerformDestruction() \
{ \
OnDestruction(); \
BaseClass::PerformDestruction(); \
} \
virtual int AllocatedSize() const { return DmeEstimateMemorySize( this ); } \
\
private: \
typedef baseClassName BaseClass; \
//-----------------------------------------------------------------------------
// Helper macro to create the class factory
//-----------------------------------------------------------------------------
#define DEFINE_ELEMENT( className, baseClassName ) \
public: \
virtual bool IsA( UtlSymId_t typeSymbol ) const \
{ \
return IsA_Implementation( typeSymbol );\
} \
\
bool IsA( const char *pTypeName ) const \
{ \
CUtlSymbol typeSymbol = g_pDataModel->GetSymbol( pTypeName ); \
return IsA( typeSymbol ); \
} \
\
template< class T > bool IsA() const \
{ \
return IsA( T::GetStaticTypeSymbol() ); \
} \
\
virtual int GetInheritanceDepth( UtlSymId_t typeSymbol ) const \
{ \
return GetInheritanceDepth_Implementation( typeSymbol, 0 ); \
} \
\
static CUtlSymbol GetStaticTypeSymbol( ) \
{ \
return m_classType; \
} \
\
className* Copy( TraversalDepth_t depth = TD_DEEP ) const \
{ \
return static_cast< className* >( CopyInternal( depth ) ); \
} \
protected: \
className( DmElementHandle_t handle, const char *pElementTypeName, const DmObjectId_t &id, const char *pElementName, DmFileId_t fileid ) : \
baseClassName( handle, pElementTypeName, id, pElementName, fileid ) \
{ \
} \
virtual ~className() \
{ \
} \
void OnConstruction(); \
void OnDestruction(); \
virtual void PerformConstruction() \
{ \
BaseClass::PerformConstruction(); \
OnConstruction(); \
} \
virtual void PerformDestruction() \
{ \
OnDestruction(); \
BaseClass::PerformDestruction(); \
} \
static void SetTypeSymbol( CUtlSymbol typeSymbol ) \
{ \
m_classType = typeSymbol; \
} \
\
static bool IsA_Implementation( CUtlSymbol typeSymbol ) \
{ \
if ( typeSymbol == m_classType ) \
return true; \
return BaseClass::IsA_Implementation( typeSymbol ); \
} \
\
static int GetInheritanceDepth_Implementation( CUtlSymbol typeSymbol, int nCurrentDepth ) \
{ \
if ( typeSymbol == m_classType ) \
return nCurrentDepth; \
return BaseClass::GetInheritanceDepth_Implementation( typeSymbol, nCurrentDepth+1 );\
} \
virtual int AllocatedSize() const { return DmeEstimateMemorySize( this ); } \
\
private: \
typedef baseClassName BaseClass; \
template <class T> friend class CDmElementFactory; \
template <class T> friend class CDmAbstractElementFactory; \
static CUtlSymbol m_classType
#define IMPLEMENT_ELEMENT( className ) \
CUtlSymbol className::m_classType = UTL_INVAL_SYMBOL;
#endif // DMELEMENT_H