THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 28/06/2012 at 00:54, xxxxxxxx wrote:
Hi Scott,
Getting back to your original question (if I understand it correctly), creating your own classes (having nothing to do with STL) is fairly straight-forward...
I recently needed to add some 'hash table' functionality to my plugins (optimized look-up capability for arrays/lists of items). I found one that is really easy to implement and seems to work quite well - http://uthash.sourceforge.net/
Basically, you just need to add a element/member to your class structure (used as a hash handle) and then include one header file. You can then use some macros from the header file to add/delete entries and iterate over the entries, etc.
I wanted to isolate these macros from the rest of my code - to condense them to a few files/implementations, making the actual implementation transparent to the rest of the code, so I created some classes to implement the hashing for various purposes.
One of the basic/root-level classes I created was a "unique name hash", which looks like this:
class nameNode
{
public:
char *m_pName;
size_t m_nameLen;
ULONG m_ID;
UT_hash_handle hh; // makes this structure hashable
ULONG GetID(void) { return m_ID; }
void SetID(ULONG ID) { m_ID = ID; }
char *GetName(void) { return m_pName; }
Bool SetName(const char *szName);
// void SetName(const String &strName);
nameNode(void);
~nameNode(void);
};
class nameHash
{
private:
nameNode *m_pHashTable;
ULONG m_count;
nameHash(void);
~nameHash(void);
public:
ULONG GetCount(void) { return m_count; }
Bool IsCloneName(const char *szName);
nameNode *AddName(const char *szName);
nameNode *AddName(const String &strName);
nameNode *FindName(const char *szName);
nameNode *FindName(const String &strName);
void Flush(void);
static nameHash *Alloc(void);
static void Free(nameHash *&pNameHash);
};
...the nameNode class only has a few methods not implemented in the declaration above...
// nameNode::nameNode() - Constructor
nameNode::nameNode(void)
{
m_pName = NULL;
m_nameLen = 0;
m_ID = 0;
}
// nameNode::~nameNode() - Destructor
nameNode::~nameNode(void)
{
if( m_pName ) GeFree(m_pName);
}
// nameNode::SetName()
Bool nameNode::SetName(const char *szName)
{
if( m_pName ) GeFree(m_pName);
m_nameLen = strlen(szName);
m_pName = (char * )GeAlloc(m_nameLen+2);
if( !m_pName )
{
m_nameLen = 0;
return false;
}
strcpy(m_pName, szName);
return true;
}
...then the nameHash class is the actual list/container that the rest of my code mostly deals with to access the nameNode(s)...
// nameHash::nameHash() - Constructor
nameHash::nameHash(void)
{
m_pHashTable = NULL;
m_count = 0;
}
// nameHash::~nameHash() - Destructor
nameHash::~nameHash(void)
{
this->Flush();
}
// nameHash::Flush() - free up the list
void nameHash::Flush(void)
{
nameNode *pName, *pTmp;
HASH_ITER(hh, m_pHashTable, pName, pTmp)
{
HASH_DEL(m_pHashTable, pName);
gDelete(pName);
}
m_pHashTable = NULL;
m_count = 0;
}
// nameHash::Alloc()
nameHash *nameHash::Alloc(void)
{
nameHash *pNameHash = gNew nameHash();
if( !pNameHash ) return NULL;
return pNameHash;
}
// nameHash::Free()
void nameHash::Free(nameHash *&pNameHash)
{
if( !pNameHash ) return;
gDelete(pNameHash); // <-- calls the Destructor, which in turn calls Flush()
}
// nameHash::IsCloneName() - Similar to AddName(), but return value is whether or not
// the name already existed instead of the nameNode pointer
Bool nameHash::IsCloneName(const char *szName)
{
nameNode *pNode;
HASH_FIND_STR( m_pHashTable, szName, pNode);
if( pNode ) return true;
pNode = gNew nameNode();
if( !pNode ) return false;
pNode->SetName(szName);
pNode->SetID(m_count++);
HASH_ADD_KEYPTR( hh, m_pHashTable, pNode->m_pName, pNode->m_nameLen, pNode );
return false;
}
// nameHash::AddName() - char * version
nameNode *nameHash::AddName(const char *szName)
{
nameNode *pNode;
HASH_FIND_STR( m_pHashTable, szName, pNode);
if( pNode ) return pNode;
pNode = gNew nameNode();
if( !pNode ) return NULL;
pNode->SetName(szName);
pNode->SetID(m_count++);
HASH_ADD_KEYPTR( hh, m_pHashTable, pNode->m_pName, pNode->m_nameLen, pNode );
return pNode;
}
// nameHash::AddName() - Cinema 4D String() version
nameNode *nameHash::AddName(const String &strName)
{
char chkName[MAX_MAPNAME_LEN+1];
cmpGetCString8(strName, chkName, MAX_MAPNAME_LEN);
chkName[MAX_MAPNAME_LEN] = 0;
return this->AddName(chkName);
}
// nameHash::FindName() - char * version
nameNode *nameHash::FindName(const char *chkName)
{
nameNode *pNode;
HASH_FIND_STR( m_pHashTable, chkName, pNode);
return pNode;
}
// nameHash::FindName() - Cinema 4D String() version
nameNode *nameHash::FindName(const String &strName)
{
char chkName[MAX_MAPNAME_LEN+1];
cmpGetCString8(strName, chkName, MAX_MAPNAME_LEN);
chkName[MAX_MAPNAME_LEN] = 0;
return this->FindName(chkName);
}
...so the nameHash class is used for various purposes in my code, but I also have some additional classes that derive from the basic nameNode, such as...
class tagNode : public nameNode
{
friend class tagHash;
private:
BaseTag *m_pTag;
tagNode(void) { m_pTag = NULL; }
~tagNode(void) { }
public:
void SetTag(BaseTag *pTag) { m_pTag = pTag; }
BaseTag *GetTag(void) { return m_pTag; }
};
class tagHash
{
private:
tagNode *m_pHashTable;
ULONG m_count;
tagHash(void);
~tagHash(void);
public:
ULONG GetCount(void) { return m_count; }
tagNode *AddTag(const char *szName, BaseTag *pTag);
tagNode *AddTag(const String &strName, BaseTag *pTag);
tagNode *FindTag(const char *szName);
tagNode *FindTag(const String &strName);
void Flush(void);
static tagHash *Alloc(void);
static void Free(tagHash *&pTagHash);
};
...the tagNode is derived from the nameNode, so it still has the SetName()/GetName()/GetID()/etc methods, but also adds a new member and method to store/retrieve a BaseTag pointer.
The tagHash class is used in a similar manor to the nameHash class (but to track tagNode(s)), but it's not derived from it.
Also note that both xxHash classes have methods for both C "char *" names as well as Cinema 4D String() names, so I just call them with whatever is handy.
I won't bother to post the code for the tagHash class - I'll leave that as an exercise for the user :).
I have dozens (hundreds?) of other classes that (for example) convert to/from .obj file mesh structure to Cinema 4D PolygonObject structure (I have my own internal ioMesh, ioGroup, ioMaterial, ioRegion and many other classes/sub-classes used for the conversion process).
I also use that tagHash class to gather/track lists of Texture Tags, Material Tags, Polygon Selection tags (used for Texture Tag restrictions), Polygon Selection tags (used for Group definitions), Polygon Selection tags (used for Region definitions), etc.
I hope this was helpful - Cheers.