162 lines
3 KiB
C
162 lines
3 KiB
C
|
// Notes
|
||
|
// Make sure extension is stripped if it needs to be
|
||
|
|
||
|
// Template class must have
|
||
|
// 1. A GetName() accessor - a null terminated string case insensitive
|
||
|
// 2. A Destroy() function - normally "delete this"
|
||
|
// 3. SetNext(T *) and T *GetNext() functions
|
||
|
|
||
|
#define HASH_SIZE 1024
|
||
|
|
||
|
template <class T, int TSize = HASH_SIZE, int (*TCompare)(const char *, const char *) = strcmp>
|
||
|
|
||
|
class CHash
|
||
|
{
|
||
|
private:
|
||
|
T *mHashTable[TSize];
|
||
|
T *mNext;
|
||
|
int mCount;
|
||
|
T *mPrevious; // Internal work variable
|
||
|
long mHash; // Internal work variable
|
||
|
|
||
|
// Creates the hash value and sets the mHash member
|
||
|
void CreateHash(const char *key)
|
||
|
{
|
||
|
int i = 0;
|
||
|
char letter;
|
||
|
|
||
|
mHash = 0;
|
||
|
letter = *key++;
|
||
|
while (letter)
|
||
|
{
|
||
|
mHash += (long)(letter) * (i + 119);
|
||
|
|
||
|
i++;
|
||
|
letter = *key++;
|
||
|
}
|
||
|
mHash &= TSize - 1;
|
||
|
}
|
||
|
public:
|
||
|
// Constructor
|
||
|
CHash(void)
|
||
|
{
|
||
|
memset(mHashTable, NULL, sizeof(mHashTable));
|
||
|
mNext = NULL;
|
||
|
mCount = 0;
|
||
|
mPrevious = NULL;
|
||
|
mHash = 0;
|
||
|
}
|
||
|
// Destructor
|
||
|
~CHash(void)
|
||
|
{
|
||
|
#ifdef _DEBUG
|
||
|
// Com_OPrintf("Shutting down %s hash table .....", typeid(T).name());
|
||
|
#endif
|
||
|
clear();
|
||
|
#ifdef _DEBUG
|
||
|
Com_OPrintf(" done\n");
|
||
|
#endif
|
||
|
}
|
||
|
// Returns the total number of entries in the hash table
|
||
|
int count(void) const { return(mCount); }
|
||
|
|
||
|
// Inserts an item into the hash table
|
||
|
void insert(T *item)
|
||
|
{
|
||
|
CreateHash(item->GetName());
|
||
|
item->SetNext(mHashTable[mHash]);
|
||
|
mHashTable[mHash] = item;
|
||
|
mCount++;
|
||
|
}
|
||
|
// Finds an item in the hash table (sets the mPrevious member)
|
||
|
T *find(const char *key)
|
||
|
{
|
||
|
CreateHash(key);
|
||
|
T *item = mHashTable[mHash];
|
||
|
mPrevious = NULL;
|
||
|
while(item)
|
||
|
{
|
||
|
mNext = item->GetNext();
|
||
|
if(!TCompare(item->GetName(), key))
|
||
|
{
|
||
|
return(item);
|
||
|
}
|
||
|
mPrevious = item;
|
||
|
item = mNext;
|
||
|
}
|
||
|
return(NULL);
|
||
|
}
|
||
|
// Remove item from the hash table referenced by key
|
||
|
bool remove(const char *key)
|
||
|
{
|
||
|
T *item = find(key);
|
||
|
if(item)
|
||
|
{
|
||
|
T *next = item->GetNext();
|
||
|
if(mPrevious)
|
||
|
{
|
||
|
mPrevious->SetNext(next);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
mHashTable[mHash] = next;
|
||
|
}
|
||
|
item->Destroy();
|
||
|
mCount--;
|
||
|
return(true);
|
||
|
}
|
||
|
return(false);
|
||
|
}
|
||
|
// Remove item from hash referenced by item
|
||
|
bool remove(T *item)
|
||
|
{
|
||
|
return(remove(item->GetName()));
|
||
|
}
|
||
|
// Returns the first valid entry
|
||
|
T *head(void)
|
||
|
{
|
||
|
mHash = -1;
|
||
|
mNext = NULL;
|
||
|
return(next());
|
||
|
}
|
||
|
// Returns the next entry in the hash table
|
||
|
T *next(void)
|
||
|
{
|
||
|
T *item;
|
||
|
|
||
|
assert(mHash < TSize);
|
||
|
|
||
|
if(mNext)
|
||
|
{
|
||
|
item = mNext;
|
||
|
mNext = item->GetNext();
|
||
|
return(item);
|
||
|
}
|
||
|
mHash++;
|
||
|
|
||
|
for( ; mHash < TSize; mHash++)
|
||
|
{
|
||
|
item = mHashTable[mHash];
|
||
|
if(item)
|
||
|
{
|
||
|
mNext = item->GetNext();
|
||
|
return(item);
|
||
|
}
|
||
|
}
|
||
|
return(NULL);
|
||
|
}
|
||
|
// Destroy all entries in the hash table
|
||
|
void clear(void)
|
||
|
{
|
||
|
T *item = head();
|
||
|
while(item)
|
||
|
{
|
||
|
remove(item);
|
||
|
item = next();
|
||
|
}
|
||
|
}
|
||
|
// Override the [] operator
|
||
|
T *operator[](const char *key) { return(find(key)); }
|
||
|
};
|
||
|
|
||
|
// end
|