#include "StringManager.h" // Note: The memory buffer CANNOT be resized since it's memory location can change // Subsequently, the pointers in the hashtable will all be invalid! StringManager::StringManager() { m_CurrentSize = STRING_MEMORY_SIZE; m_HashTable.Size = STRING_TABLE_SIZE; m_HashTable.Table = new StringHashElement[STRING_TABLE_SIZE * sizeof(StringHashElement)]; memset(m_HashTable.Table,0,STRING_TABLE_SIZE * sizeof(StringHashElement)); m_Memory = new char[m_CurrentSize]; // Set the very first byte to be the null string *m_Memory = 0; m_CurLoc = m_Memory + 1; printf("String manager initialized\n"); } StringManager::~StringManager() { if (m_Memory != 0) { delete [] m_Memory; } if (m_HashTable.Table != 0) { delete [] m_HashTable.Table; } } char * StringManager::NullStr() { // The first byte of m_Memory is 0, and is therefore a null string return m_Memory; } char * StringManager::GetStr(const char *ConstStr) { return GetStr((char *) ConstStr); } char * StringManager::GetStr(char *Str) { // Not sure if the mutex needs to be placed around this entire function or just the add function // If the pointer is null, or the string is null, return a null string if (Str == 0 || *Str == 0) { return NullStr(); } // Do the initial hash on the string unsigned long Hash = HashStr(Str); // Check if this location is busy if (m_HashTable.Table[Hash].Busy == STRING_BUSY) { // If the location is busy, check to see if its the correct string if (strcmp(m_HashTable.Table[Hash].Str, Str) != 0) { // If its not the correct string, run the collision function if ((Hash = HashCollision(Hash,Str)) == m_HashTable.Size) { // If the collision function returns the size of the hash, we cannot find/place string LogMessage("StringManager - Fatal error locating/placing string: %s\n",Str); return NullStr(); } else { // The collision function found either an empty slot or the string itself if (m_HashTable.Table[Hash].Busy == STRING_BUSY) { // We found the string! return m_HashTable.Table[Hash].Str; } else { // We found an empty spot to place the string return AddStr(Hash, Str); } } } else { // This is the correct string return m_HashTable.Table[Hash].Str; } } else { // This location is empty, place the string here return AddStr(Hash, Str); } // If for some reason we have not returned, print an error LogMessage("StringManager - Critical Error, GetStr did not return!\n"); return NullStr(); } unsigned long StringManager::HashStr(char *Str) { // This is the djb2 hash function unsigned long Char, Hash = 5381; while (Char = *Str++) Hash = ((Hash << 5) + Hash) + Char; return Hash % m_HashTable.Size; } unsigned long StringManager::HashCollision(unsigned long Hash, char *Str) { // This functions returns a location if an initial collision exists // For now do some simple linear probing with step size 1 for (unsigned long i=1;i STRING_MEMORY_SIZE) { LogMessage("StringManager - There is less than 1Kb available in the string manager!\n"); } m_Mutex.Unlock(); return m_HashTable.Table[Hash].Str; } // This is for debugging only and should NEVER be used on a live server void StringManager::PrintOut() { unsigned long i,Count = 0; printf("\nStringManager Dump\n"); m_Mutex.Lock(); for (i=0;i