Rewrote language backend for integrity checking and optimization

Replaced CRC32 system with real hash-map
This commit is contained in:
David Anderson 2005-11-21 01:35:37 +00:00
parent bb292d13ad
commit f13599177f
8 changed files with 1006 additions and 392 deletions

View File

@ -46,9 +46,9 @@
#define INSERT_STRING 3 #define INSERT_STRING 3
#define INSERT_NEWLINE 4 #define INSERT_NEWLINE 4
// dictionary format is Fast-Format-Hash-Lookup, v4 // dictionary format is Fast-Format-Hash-Lookup, v5
#define MAGIC_HDR 0x4646484C #define MAGIC_HDR 0x4646484C
#define FFHL_VERSION 4 #define FFHL_VERSION 5
#define FFHL_MIN_VERSION 4 #define FFHL_MIN_VERSION 4
/*version history: /*version history:
@ -56,6 +56,7 @@
* 2 (BAILOPAN) - One language per file with full reverse * 2 (BAILOPAN) - One language per file with full reverse
* 3 (PM OnoTo) - 2^32 languages per file with full reverse * 3 (PM OnoTo) - 2^32 languages per file with full reverse
* 4 (BAILOPAN) - Optimized by separating and relocating tables (normalization) * 4 (BAILOPAN) - Optimized by separating and relocating tables (normalization)
* 5 (BAILOPAN) - Removed hash storage
FORMAT: FORMAT:
Magic 4bytes Magic 4bytes
Version 1byte Version 1byte
@ -65,13 +66,11 @@ LANG INFO TABLE[]
Language Name 2bytes Language Name 2bytes
Offset 4bytes Offset 4bytes
KEY TABLE[] KEY TABLE[]
Key Hash 4bytes
Key Lookup Offset 4bytes Key Lookup Offset 4bytes
LANGUAGES TABLE[] LANGUAGES TABLE[]
Language[] Language[]
Definitions 4bytes Definitions 4bytes
Key Hash # 4bytes (virtual # in hash table, 0 indexed) Key # 4bytes (0-index into key table)
Def Hash 4bytes
Def Offset 4bytes Def Offset 4bytes
KEY LOOKUP TABLE[] KEY LOOKUP TABLE[]
Key length 1byte Key length 1byte
@ -81,70 +80,32 @@ DEF LOOKUP TABLE[]
Def string variable Def string variable
*/ */
/******** CRC & Strip *********/ template<>
const uint32_t CRCTable[256] = { int Compare<String>(const String &k1, const String &k2)
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d};
uint32_t CLangMngr::CLang::MakeHash(const char *src, bool makeLower)
{ {
uint32_t crc = 0xFFFFFFFF; return k1.compare(k2.c_str());
while (*src)
crc = ((crc>>8)&0xFFFFFFFF)^CRCTable[(crc^ (makeLower ? tolower(*src++) : *src++) )&0xFF];
return ~crc;
} }
uint32_t CLangMngr::MakeHash(const char *src, bool makeLower) template<>
int HashFunction<String>(const String &k)
{ {
uint32_t crc = 0xFFFFFFFF; unsigned long hash = 5381;
const char *str = k.c_str();
char c;
while (c = *str++) hash = ((hash << 5) + hash) + c; // hash*33 + c
return hash;
}
while (*src) template<>
crc = ((crc>>8)&0xFFFFFFFF)^CRCTable[(crc^ (makeLower ? tolower(*src++) : *src++) )&0xFF]; int HashFunction<int>(const int &k)
{
return k;
}
return ~crc; template<>
int Compare<int>(const int &k1, const int &k2)
{
return (k1-k2);
} }
// strip the whitespaces at the beginning and the end of a string // strip the whitespaces at the beginning and the end of a string
@ -188,86 +149,6 @@ size_t CLangMngr::strip(char *str, char *newstr, bool makelower)
return ptr - str + 1; return ptr - str + 1;
} }
/******** CLangMngr::CLang::LangEntry *********/
uint32_t CLangMngr::CLang::LangEntry::GetDefHash()
{
return m_DefHash;
}
void CLangMngr::CLang::LangEntry::SetCache(bool c)
{
m_isCache = c;
}
bool CLangMngr::CLang::LangEntry::GetCache()
{
return m_isCache;
}
const char *CLangMngr::CLang::LangEntry::GetDef()
{
return m_pDef.c_str();
}
int CLangMngr::CLang::LangEntry::GetDefLength()
{
return m_pDef.size();
}
int CLangMngr::CLang::LangEntry::GetKey()
{
return key;
}
CLangMngr::CLang::LangEntry::LangEntry()
{
Clear();
}
CLangMngr::CLang::LangEntry::LangEntry(int pKey)
{
Clear();
SetKey(pKey);
}
CLangMngr::CLang::LangEntry::LangEntry(int pKey, const char *pDef)
{
Clear();
SetKey(pKey);
SetDef(pDef);
}
CLangMngr::CLang::LangEntry::LangEntry(const LangEntry &other)
{
Clear();
SetKey(other.key);
SetDef(other.m_pDef.c_str());
}
CLangMngr::CLang::LangEntry::LangEntry(int pKey, uint32_t defHash, const char *pDef)
{
Clear();
key = pKey;
m_DefHash = defHash;
m_pDef.assign(pDef);
}
void CLangMngr::CLang::LangEntry::Clear()
{
m_pDef.clear();
key = -1;
}
void CLangMngr::CLang::LangEntry::SetKey(int pkey)
{
key = pkey;
}
void CLangMngr::CLang::LangEntry::SetDef(const char *pDef)
{
m_pDef.assign(pDef);
m_DefHash = MakeHash(pDef);
}
/******** CLangMngr::CLang *********/ /******** CLangMngr::CLang *********/
@ -283,15 +164,14 @@ CLangMngr::CLang::CLang(const char *lang)
m_LanguageName[2] = 0; m_LanguageName[2] = 0;
} }
CLangMngr::CLang::LangEntry *CLangMngr::CLang::AddEntry(int pKey, uint32_t defHash, const char *def, bool cache) void CLangMngr::CLang::AddEntry(int key, const char *definition)
{ {
LangEntry *p = new LangEntry(pKey, defHash, def); defentry &d = m_LookUpTable[key];
p->SetCache(cache); if (d.definition)
delete d.definition;
m_LookUpTable.push_back(p); d.definition = new String(definition);
return p;
} }
CLangMngr::CLang::~CLang() CLangMngr::CLang::~CLang()
@ -301,99 +181,66 @@ CLangMngr::CLang::~CLang()
void CLangMngr::CLang::Clear() void CLangMngr::CLang::Clear()
{ {
for (unsigned int i = 0; i < m_LookUpTable.size(); i++) THash<int, defentry>::iterator iter;
for (iter=m_LookUpTable.begin(); iter!=m_LookUpTable.end(); iter++)
{ {
if (m_LookUpTable[i]) if (iter->val.definition)
delete m_LookUpTable[i]; {
delete iter->val.definition;
iter->val.definition = NULL;
}
} }
m_LookUpTable.clear(); m_LookUpTable.clear();
} }
CLangMngr::CLang::LangEntry * CLangMngr::CLang::GetEntry(int pkey) void CLangMngr::CLang::MergeDefinitions(CQueue<sKeyDef> &vec)
{ {
unsigned int i; String *pDef;
for (i = 0; i < m_LookUpTable.size(); i++)
{
if (m_LookUpTable[i]->GetKey() == pkey)
{
return m_LookUpTable[i];
}
}
LangEntry *e = new LangEntry(pkey);
e->SetKey(pkey);
e->SetCache(true);
m_LookUpTable.push_back(e);
return e;
}
void CLangMngr::CLang::MergeDefinitions(CQueue<sKeyDef*> &vec)
{
const char *def = 0;
int key = -1; int key = -1;
while (!vec.empty()) while (!vec.empty())
{ {
key = vec.front()->key; key = vec.front().key;
def = vec.front()->def->c_str(); pDef = vec.front().definition;
LangEntry *entry = GetEntry(key);
if (entry->GetDefHash() != MakeHash(def)) AddEntry(key, pDef->c_str());
{
if (entry->GetCache()) delete vec.front().definition;
{
entry->SetDef(def);
entry->SetKey(key);
entry->SetCache(false);
} else {
//AMXXLOG_Log("[AMXX] Language key %s[%s] defined twice", m_LMan->GetKey(key), m_LanguageName);
}
}
delete vec.front();
vec.pop(); vec.pop();
} }
} }
const char * CLangMngr::CLang::GetDef(const char *key, int &status) const char * CLangMngr::CLang::GetDef(int key, int &status)
{ {
int ikey = m_LMan->GetKeyEntry(key); defentry &def = m_LookUpTable[key];
if (ikey == -1) if (!def.definition)
{ {
status = LANG_STATUS_KLNOTFOUND;
return NULL; return NULL;
} }
for (unsigned int i = 0; i < m_LookUpTable.size(); i++) return def.definition->c_str();
{
if (m_LookUpTable[i]->GetKey() == ikey)
return m_LookUpTable[i]->GetDef();
}
status = LANG_STATUS_KLNOTFOUND;
return NULL;
} }
struct OffsetPair
{
uint32_t defOffset;
uint32_t keyOffset;
};
// Assumes fp is set to the right position // Assumes fp is set to the right position
bool CLangMngr::CLang::SaveDefinitions(FILE *fp, uint32_t &curOffset) bool CLangMngr::CLang::SaveDefinitions(FILE *fp, uint32_t &curOffset)
{ {
unsigned short defLen = 0; unsigned short defLen = 0;
String *pdef;
String blank;
for (unsigned int i = 0; i < m_LookUpTable.size(); i++) THash<int, defentry>::iterator iter;
for (iter=m_LookUpTable.begin(); iter!=m_LookUpTable.end(); iter++)
{ {
defLen = m_LookUpTable[i]->GetDefLength(); pdef = iter->val.definition;
if (!pdef)
pdef = &blank;
defLen = pdef->size();
fwrite((void *)&defLen, sizeof(unsigned short), 1, fp); fwrite((void *)&defLen, sizeof(unsigned short), 1, fp);
curOffset += sizeof(unsigned short); curOffset += sizeof(unsigned short);
fwrite(m_LookUpTable[i]->GetDef(), sizeof(char), defLen, fp); fwrite(pdef->c_str(), sizeof(char), defLen, fp);
curOffset += defLen; curOffset += defLen;
} }
@ -404,24 +251,26 @@ bool CLangMngr::CLang::SaveDefinitions(FILE *fp, uint32_t &curOffset)
bool CLangMngr::CLang::Save(FILE *fp, int &defOffset, uint32_t &curOffset) bool CLangMngr::CLang::Save(FILE *fp, int &defOffset, uint32_t &curOffset)
{ {
uint32_t keynum = 0; uint32_t keynum = 0;
uint32_t defhash = 0;
uint32_t size = m_LookUpTable.size(); uint32_t size = m_LookUpTable.size();
String *pdef;
String blank;
fwrite((void*)&size, sizeof(uint32_t), 1, fp); fwrite((void*)&size, sizeof(uint32_t), 1, fp);
curOffset += sizeof(uint32_t); curOffset += sizeof(uint32_t);
for (unsigned int i = 0; i < m_LookUpTable.size(); i++) THash<int, defentry>::iterator iter;
for (iter=m_LookUpTable.begin(); iter!=m_LookUpTable.end(); iter++)
{ {
keynum = m_LookUpTable[i]->GetKey(); keynum = iter->key;
defhash = m_LookUpTable[i]->GetDefHash(); pdef = iter->val.definition;
if (!pdef)
pdef = &blank;
fwrite((void *)&keynum, sizeof(uint32_t), 1, fp); fwrite((void *)&keynum, sizeof(uint32_t), 1, fp);
curOffset += sizeof(uint32_t); curOffset += sizeof(uint32_t);
fwrite((void *)&defhash, sizeof(uint32_t), 1, fp);
curOffset += sizeof(uint32_t);
fwrite((void *)&defOffset, sizeof(uint32_t), 1, fp); fwrite((void *)&defOffset, sizeof(uint32_t), 1, fp);
curOffset += sizeof(uint32_t); curOffset += sizeof(uint32_t);
defOffset += sizeof(short); defOffset += sizeof(short);
defOffset += m_LookUpTable[i]->GetDefLength(); defOffset += pdef->size();
} }
return true; return true;
@ -443,69 +292,36 @@ CLangMngr::CLangMngr()
const char * CLangMngr::GetKey(int key) const char * CLangMngr::GetKey(int key)
{ {
if (key < 0 || key >= (int)KeyList.size()) if (key < 0 || key >= (int)KeyList.size())
return 0; return NULL;
return KeyList[key]->key.c_str(); return KeyList[key]->c_str();
}
int CLangMngr::GetKeyHash(int key)
{
if (key < 0 || key >= (int)KeyList.size())
return 0;
return KeyList[key]->hash;
} }
int CLangMngr::GetKeyEntry(const char *key) int CLangMngr::GetKeyEntry(const char *key)
{ {
uint32_t hKey = MakeHash(key, true); keytbl_val val = KeyTable[key];
uint32_t cmpKey = 0;
unsigned int i = 0;
if (hKey == 0) return val.index;
{
return -1;
}
for (i = 0; i < KeyList.size(); i++)
{
cmpKey = KeyList[i]->hash;
if (hKey == cmpKey)
{
return i;
}
}
return -1;
} }
int CLangMngr::AddKeyEntry(String &key) int CLangMngr::AddKeyEntry(String &key)
{ {
uint32_t hKey = MakeHash(key.c_str(), true); keytbl_val val;
val.index = static_cast<int>(KeyList.size());
keyEntry *e = new keyEntry; String *pString = new String(key);
e->key.assign(key); KeyList.push_back(pString);
e->hash = hKey;
KeyList.push_back(e);
return (KeyList.size() - 1); KeyTable[key] = val;
return val.index;
} }
int CLangMngr::GetKeyEntry(String &key) int CLangMngr::GetKeyEntry(String &key)
{ {
uint32_t hKey = MakeHash(key.c_str(), true); keytbl_val val = KeyTable[key];
unsigned int i = 0;
for (i = 0; i < KeyList.size(); i++) return val.index;
{
if (hKey == KeyList[i]->hash)
{
return i;
}
}
return -1;
} }
#define CHECK_PTR(ptr, start, bufsize) if ((ptr) - (start) >= (bufsize)) { \ #define CHECK_PTR(ptr, start, bufsize) if ((ptr) - (start) >= (bufsize)) { \
@ -993,7 +809,7 @@ char *CLangMngr::FormatString(const char *fmt, va_list &ap)
return outbuf; return outbuf;
} }
void CLangMngr::MergeDefinitions(const char *lang, CQueue<sKeyDef*> &tmpVec) void CLangMngr::MergeDefinitions(const char *lang, CQueue<sKeyDef> &tmpVec)
{ {
CLang * language = GetLang(lang); CLang * language = GetLang(lang);
if (language) if (language)
@ -1062,10 +878,10 @@ int CLangMngr::MergeDefinitionFile(const char *file)
// Allocate enough memory to store everything // Allocate enough memory to store everything
bool multiline = 0; bool multiline = 0;
int pos = 0, line = 0; int pos = 0, line = 0;
CQueue<sKeyDef*> Defq; CQueue<sKeyDef> Defq;
String buf; String buf;
char language[3]; char language[3];
sKeyDef *tmpEntry = NULL; sKeyDef tmpEntry;
while (!feof(fp)) while (!feof(fp))
{ {
@ -1082,9 +898,8 @@ int CLangMngr::MergeDefinitionFile(const char *file)
if (multiline) if (multiline)
{ {
AMXXLOG_Log("New section, multiline unterminated (file \"%s\" line %d)", file, line); AMXXLOG_Log("New section, multiline unterminated (file \"%s\" line %d)", file, line);
if (tmpEntry) tmpEntry.key = -1;
delete tmpEntry; tmpEntry.definition = NULL;
tmpEntry = 0;
} }
if (!Defq.empty()) if (!Defq.empty())
@ -1102,7 +917,6 @@ int CLangMngr::MergeDefinitionFile(const char *file)
if (pos > String::npos) if (pos > String::npos)
{ {
tmpEntry = new sKeyDef;
String key; String key;
key.assign(buf.substr(0, pos).c_str()); key.assign(buf.substr(0, pos).c_str());
String def; String def;
@ -1112,18 +926,18 @@ int CLangMngr::MergeDefinitionFile(const char *file)
int iKey = GetKeyEntry(key); int iKey = GetKeyEntry(key);
if (iKey == -1) if (iKey == -1)
iKey = AddKeyEntry(key); iKey = AddKeyEntry(key);
tmpEntry->key = iKey; tmpEntry.key = iKey;
tmpEntry->def = new String; tmpEntry.definition = new String;
tmpEntry->def->assign(def.c_str()); tmpEntry.definition->assign(def.c_str());
tmpEntry->def->trim(); tmpEntry.definition->trim();
Defq.push(tmpEntry); Defq.push(tmpEntry);
tmpEntry = 0; tmpEntry.key = -1;
tmpEntry.definition = NULL;
} else { } else {
pos = buf.find(':'); pos = buf.find(':');
if (pos > String::npos) if (pos > String::npos)
{ {
tmpEntry = new sKeyDef;
String key; String key;
key.assign(buf.substr(0, pos).c_str());; key.assign(buf.substr(0, pos).c_str());;
key.trim(); key.trim();
@ -1131,8 +945,8 @@ int CLangMngr::MergeDefinitionFile(const char *file)
int iKey = GetKeyEntry(key); int iKey = GetKeyEntry(key);
if (iKey == -1) if (iKey == -1)
iKey = AddKeyEntry(key); iKey = AddKeyEntry(key);
tmpEntry->key = iKey; tmpEntry.key = iKey;
tmpEntry->def = new String; tmpEntry.definition = new String;
multiline = true; multiline = true;
} else { } else {
//user typed a line with no directives //user typed a line with no directives
@ -1143,10 +957,13 @@ int CLangMngr::MergeDefinitionFile(const char *file)
if (buf[0] == ':') if (buf[0] == ':')
{ {
Defq.push(tmpEntry); Defq.push(tmpEntry);
tmpEntry = 0; tmpEntry.key = -1;
tmpEntry.definition = NULL;
multiline = false; multiline = false;
} else { } else {
tmpEntry->def->append(buf); if (!tmpEntry.definition)
tmpEntry.definition = new String();
tmpEntry.definition->append(buf);
} }
} // if !multiline } // if !multiline
} //if - main } //if - main
@ -1194,16 +1011,30 @@ CLangMngr::CLang * CLangMngr::GetLangR(const char *name)
const char *CLangMngr::GetDef(const char *langName, const char *key, int &status) const char *CLangMngr::GetDef(const char *langName, const char *key, int &status)
{ {
CLang *lang = GetLangR(langName); CLang *lang = GetLangR(langName);
if (lang) keytbl_val val = KeyTable[key];
if (lang == NULL)
{ {
//status = LANG_STATUS_OK;
return lang->GetDef(key, status);
} else {
status = LANG_STATUS_LNOTFOUND; status = LANG_STATUS_LNOTFOUND;
return NULL; return NULL;
} else if (val.index == -1) {
status = LANG_STATUS_KLNOTFOUND;
return NULL;
} else {
return lang->GetDef(val.index, status);
} }
} }
void CLangMngr::InvalidateCache()
{
for (size_t i = 0; i < FileList.size(); i++)
{
if (FileList[i])
delete FileList[i];
}
FileList.clear();
}
bool CLangMngr::Save(const char *filename) bool CLangMngr::Save(const char *filename)
{ {
FILE *fp = fopen(filename, "wb"); FILE *fp = fopen(filename, "wb");
@ -1217,7 +1048,7 @@ bool CLangMngr::Save(const char *filename)
const char *langName = 0; const char *langName = 0;
uint32_t curOffset = 0; uint32_t curOffset = 0;
uint32_t keyNum = KeyList.size(); uint32_t keyNum = KeyList.size();
uint32_t ktbSize = KeyList.size() * (sizeof(uint32_t) + sizeof(uint32_t)); uint32_t ktbSize = KeyList.size() * sizeof(uint32_t);
uint32_t ltbSize = m_Languages.size() * ((sizeof(char)*2) + sizeof(uint32_t)); uint32_t ltbSize = m_Languages.size() * ((sizeof(char)*2) + sizeof(uint32_t));
fwrite((void *)&magic, sizeof(uint32_t), 1, fp); fwrite((void *)&magic, sizeof(uint32_t), 1, fp);
@ -1237,7 +1068,7 @@ bool CLangMngr::Save(const char *filename)
fwrite(langName, sizeof(char), 2, fp); fwrite(langName, sizeof(char), 2, fp);
curOffset += sizeof(char) * 2; curOffset += sizeof(char) * 2;
fwrite((void *)&langOffset, sizeof(uint32_t), 1, fp); fwrite((void *)&langOffset, sizeof(uint32_t), 1, fp);
langOffset += sizeof(uint32_t) + (m_Languages[i]->Entries() * (sizeof(uint32_t) * 3)); langOffset += sizeof(uint32_t) + (m_Languages[i]->Entries() * (sizeof(uint32_t) * 2));
curOffset += sizeof(uint32_t); curOffset += sizeof(uint32_t);
} }
@ -1246,13 +1077,10 @@ bool CLangMngr::Save(const char *filename)
uint32_t keyOffset = langOffset; uint32_t keyOffset = langOffset;
for (unsigned int i = 0; i < KeyList.size(); i++) for (unsigned int i = 0; i < KeyList.size(); i++)
{ {
keyHash = KeyList[i]->hash;
fwrite((void*)&keyHash, sizeof(uint32_t), 1, fp);
curOffset += sizeof(uint32_t);
fwrite((void*)&keyOffset, sizeof(uint32_t), 1, fp); fwrite((void*)&keyOffset, sizeof(uint32_t), 1, fp);
curOffset += sizeof(uint32_t); curOffset += sizeof(uint32_t);
keyOffset += sizeof(char); keyOffset += sizeof(char);
keyOffset += KeyList[i]->key.size(); keyOffset += KeyList[i]->size();
} }
//Note - now keyOffset points toward the start of the def table //Note - now keyOffset points toward the start of the def table
@ -1267,10 +1095,10 @@ bool CLangMngr::Save(const char *filename)
unsigned char keyLen = 0; unsigned char keyLen = 0;
for (unsigned int i = 0; i < KeyList.size(); i++) for (unsigned int i = 0; i < KeyList.size(); i++)
{ {
keyLen = KeyList[i]->key.size(); keyLen = KeyList[i]->size();
fwrite((void*)&keyLen, sizeof(unsigned char), 1, fp); fwrite((void*)&keyLen, sizeof(unsigned char), 1, fp);
curOffset += sizeof(unsigned char); curOffset += sizeof(unsigned char);
fwrite(KeyList[i]->key.c_str(), sizeof(char), keyLen, fp); fwrite(KeyList[i]->c_str(), sizeof(char), keyLen, fp);
curOffset += sizeof(char) * keyLen; curOffset += sizeof(char) * keyLen;
} }
@ -1314,6 +1142,19 @@ bool CLangMngr::SaveCache(const char *filename)
return true; return true;
} }
#define CACHEREAD(expr, type) \
if (! (expr==sizeof(type)) ) { \
FileList.clear(); \
fclose(fp); \
return false; \
}
#define CACHEREAD_S(expr, size) \
if (! (expr==size) ) { \
FileList.clear(); \
fclose(fp); \
return false; \
}
bool CLangMngr::LoadCache(const char *filename) bool CLangMngr::LoadCache(const char *filename)
{ {
FILE *fp = fopen(filename, "rb"); FILE *fp = fopen(filename, "rb");
@ -1326,15 +1167,15 @@ bool CLangMngr::LoadCache(const char *filename)
char len = 0; char len = 0;
char buf[255]; char buf[255];
char md5[34]; char md5[34];
fread((void*)&dictCount, sizeof(short), 1, fp); CACHEREAD(fread((void*)&dictCount, sizeof(short), 1, fp), short);
md5Pair *p = 0; md5Pair *p = 0;
for (int i = 1; i <= dictCount; i++) for (int i = 1; i <= dictCount; i++)
{ {
fread((void*)&len, sizeof(char), 1, fp); CACHEREAD(fread((void*)&len, sizeof(char), 1, fp), char);
fread(buf, sizeof(char), len, fp); CACHEREAD_S(fread(buf, sizeof(char), len, fp), len);
buf[len] = 0; buf[len] = 0;
fread(md5, sizeof(char), 32, fp); CACHEREAD_S(fread(md5, sizeof(char), 32, fp), 32);
md5[32] = 0; md5[32] = 0;
p = new md5Pair; p = new md5Pair;
p->file.assign(buf); p->file.assign(buf);
@ -1348,6 +1189,19 @@ bool CLangMngr::LoadCache(const char *filename)
return true; return true;
} }
#define DATREAD(expr, type) \
if (! (expr==1) ) { \
Clear(); \
fclose(fp); \
return false; \
}
#define DATREAD_S(expr, size) \
if (! (expr==size) ) { \
Clear(); \
fclose(fp); \
return false; \
}
bool CLangMngr::Load(const char *filename) bool CLangMngr::Load(const char *filename)
{ {
Clear(); Clear();
@ -1362,75 +1216,93 @@ bool CLangMngr::Load(const char *filename)
uint32_t keycount = 0; uint32_t keycount = 0;
char version = 0; char version = 0;
fread((void*)&magic, sizeof(uint32_t), 1, fp); fseek(fp, 0, SEEK_END);
long size = ftell(fp);
rewind(fp);
DATREAD(fread((void*)&magic, sizeof(uint32_t), 1, fp), uint32_t);
if (magic != MAGIC_HDR) if (magic != MAGIC_HDR)
return false; return false;
fread((void*)&version, sizeof(char), 1, fp); DATREAD(fread((void*)&version, sizeof(char), 1, fp), char);
if (version > FFHL_VERSION || version < FFHL_MIN_VERSION) if (version > FFHL_VERSION || version < FFHL_MIN_VERSION)
return false; return false;
fread((void*)&keycount, sizeof(uint32_t), 1, fp); DATREAD(fread((void*)&keycount, sizeof(uint32_t), 1, fp), uint32_t);
fread((void*)&langCount, sizeof(uint32_t), 1, fp); DATREAD(fread((void*)&langCount, sizeof(uint32_t), 1, fp), uint32_t);
uint32_t *LangOffsets = new uint32_t[langCount]; uint32_t *LangOffsets = new uint32_t[langCount];
char langname[3]; char langname[3];
for (unsigned int i = 0; i < langCount; i++) for (unsigned int i = 0; i < langCount; i++)
{ {
fread(langname, sizeof(char), 2, fp); DATREAD_S(fread(langname, sizeof(char), 2, fp), 2);
langname[2] = 0; langname[2] = 0;
GetLang(langname); //this will initialize for us GetLang(langname); //this will initialize for us
fread((void *)&(LangOffsets[i]), sizeof(uint32_t), 1, fp); DATREAD(fread((void *)&(LangOffsets[i]), sizeof(uint32_t), 1, fp), uint32_t);
} }
//we should now be at the key table //we should now be at the key table
int ktbOffset = ftell(fp); int ktbOffset = ftell(fp);
keyEntry *e = 0;
unsigned char keylen; unsigned char keylen;
char keybuf[255];
uint32_t bogus;
uint32_t keyoffset, save; uint32_t keyoffset, save;
String _tmpkey;
for (unsigned i = 0; i < keycount; i++) for (unsigned i = 0; i < keycount; i++)
{ {
e = new keyEntry; if (version == 4)
fread((void*)&(e->hash), sizeof(uint32_t), 1, fp); fread((void*)&(bogus), sizeof(uint32_t), 1, fp);
fread((void*)&keyoffset, sizeof(uint32_t), 1, fp); DATREAD(fread((void*)&keyoffset, sizeof(uint32_t), 1, fp), uint32_t);
if (keyoffset > size-sizeof(uint32_t))
{
Clear();
fclose(fp);
return false;
}
save = ftell(fp); save = ftell(fp);
fseek(fp, keyoffset, SEEK_SET); fseek(fp, keyoffset, SEEK_SET);
fread((void*)&keylen, sizeof(char), 1, fp); DATREAD(fread((void*)&keylen, sizeof(char), 1, fp), char);
char *data = new char[keylen + 1]; DATREAD_S(fread(keybuf, sizeof(char), keylen, fp), keylen);
fread(data, sizeof(char), keylen, fp); keybuf[keylen] = 0;
data[keylen] = 0; _tmpkey.assign(keybuf);
e->key.assign(data); AddKeyEntry(_tmpkey);
delete [] data;
KeyList.push_back(e);
fseek(fp, save, SEEK_SET); //bring back to next key fseek(fp, save, SEEK_SET); //bring back to next key
} }
//we should now be at the languages table //we should now be at the languages table
uint32_t numentries; uint32_t numentries;
uint32_t keynum; uint32_t keynum;
uint32_t defhash;
uint32_t defoffset; uint32_t defoffset;
unsigned short deflen; unsigned short deflen;
char valbuf[4096];
for (unsigned int i = 0; i < langCount; i++) for (unsigned int i = 0; i < langCount; i++)
{ {
fread((void*)&numentries, sizeof(uint32_t), 1, fp); DATREAD(fread((void*)&numentries, sizeof(uint32_t), 1, fp), uint32_t);
for (unsigned int j = 0; j < numentries; j++) for (unsigned int j = 0; j < numentries; j++)
{ {
fread((void *)&keynum, sizeof(uint32_t), 1, fp); DATREAD(fread((void *)&keynum, sizeof(uint32_t), 1, fp), uint32_t);
fread((void *)&defhash, sizeof(uint32_t), 1, fp); if (version == 4)
fread((void *)&defoffset, sizeof(uint32_t), 1, fp); {
DATREAD(fread((void *)&bogus, sizeof(uint32_t), 1, fp), uint32_t);
}
DATREAD(fread((void *)&defoffset, sizeof(uint32_t), 1, fp), uint32_t);
if (defoffset > size-sizeof(uint32_t))
{
Clear();
fclose(fp);
return false;
}
save = ftell(fp); save = ftell(fp);
fseek(fp, defoffset, SEEK_SET); fseek(fp, defoffset, SEEK_SET);
fread((void *)&deflen, sizeof(unsigned short), 1, fp); DATREAD(fread((void *)&deflen, sizeof(unsigned short), 1, fp), short);
char *data = new char[deflen + 1]; //:TODO: possible string overflow here.
fread(data, sizeof(char), deflen, fp); DATREAD_S(fread(valbuf, sizeof(char), deflen, fp), deflen);
data[deflen] = 0; valbuf[deflen] = 0;
m_Languages[i]->AddEntry(keynum, defhash, data, true); m_Languages[i]->AddEntry(keynum, valbuf);
delete [] data;
fseek(fp, save, SEEK_SET); //bring back to next entry fseek(fp, save, SEEK_SET); //bring back to next entry
} }
} }
@ -1452,6 +1324,8 @@ void CLangMngr::Clear()
{ {
unsigned int i = 0; unsigned int i = 0;
KeyTable.clear();
for (i = 0; i < m_Languages.size(); i++) for (i = 0; i < m_Languages.size(); i++)
{ {
if (m_Languages[i]) if (m_Languages[i])

View File

@ -32,6 +32,8 @@
#ifndef _INCLUDE_CLANG_H #ifndef _INCLUDE_CLANG_H
#define _INCLUDE_CLANG_H #define _INCLUDE_CLANG_H
#include "sh_tinyhash.h"
#define LANG_SERVER 0 #define LANG_SERVER 0
#define LANG_PLAYER -1 #define LANG_PLAYER -1
@ -45,19 +47,35 @@ struct md5Pair
String val; String val;
}; };
struct keyEntry
{
String key;
uint32_t hash;
};
struct sKeyDef struct sKeyDef
{ {
sKeyDef() { key = -1; def = 0; } String *definition;
~sKeyDef() { if (def) delete def; }
int key; int key;
String *def; };
class defentry
{
public:
defentry() : definition(NULL)
{
};
~defentry()
{
if (definition)
{
delete definition;
definition = NULL;
}
}
String *definition;
};
struct keytbl_val
{
keytbl_val() : index(-1)
{
};
int index;
}; };
class CLangMngr class CLangMngr
@ -73,9 +91,9 @@ class CLangMngr
~CLang(); ~CLang();
// Get the definition // Get the definition
const char *GetDef(const char *key, int &status); const char *GetDef(int key, int &status);
// Add definitions to this language // Add definitions to this language
void MergeDefinitions(CQueue <sKeyDef*> & vec); void MergeDefinitions(CQueue <sKeyDef> & vec);
// Reset this language // Reset this language
void Clear(); void Clear();
@ -95,49 +113,9 @@ class CLangMngr
void SetMngr(CLangMngr *l) { m_LMan = l; } void SetMngr(CLangMngr *l) { m_LMan = l; }
// Get number of entries // Get number of entries
int Entries() { return m_LookUpTable.size(); } int Entries() { return m_LookUpTable.size(); }
// Make a hash from a string; convert to lowercase first if needed
static uint32_t MakeHash(const char *src, bool makeLower = false);
protected: protected:
// An entry in the language typedef THash<int, defentry> LookUpVec;
class LangEntry typedef LookUpVec::iterator LookUpVecIter;
{
// the definition hash
uint32_t m_DefHash;
// index into the lookup table?
int key;
// the definition
String m_pDef;
// is this from the cache or not?
bool m_isCache;
public:
// Set
void SetKey(int key);
void SetDef(const char *pDef);
void SetCache(bool c);
// Get
uint32_t GetDefHash();
int GetKey();
const char *GetDef();
int GetDefLength();
bool GetCache();
// Constructors / destructors
LangEntry();
LangEntry(int key);
LangEntry(int key, const char *pDef);
LangEntry(const LangEntry &other);
LangEntry(int pKey, uint32_t defHash, const char *pDef);
// Reset
void Clear();
};
// Get (construct if needed) an entry
LangEntry * GetEntry(int key);
typedef CVector<LangEntry*> LookUpVec;
typedef LookUpVec::iterator LookUpVecIter;
char m_LanguageName[3]; char m_LanguageName[3];
@ -145,11 +123,11 @@ class CLangMngr
LookUpVec m_LookUpTable; LookUpVec m_LookUpTable;
CLangMngr *m_LMan; CLangMngr *m_LMan;
public: public:
LangEntry *AddEntry(int pKey, uint32_t defHash, const char *def, bool cache); void AddEntry(int key, const char *definition);
}; };
// Merge definitions into a language // Merge definitions into a language
void MergeDefinitions(const char *lang, CQueue <sKeyDef*> &tmpVec); void MergeDefinitions(const char *lang, CQueue <sKeyDef> &tmpVec);
// strip lowercase; make lower if needed // strip lowercase; make lower if needed
static size_t strip(char *str, char *newstr, bool makelower = false); static size_t strip(char *str, char *newstr, bool makelower = false);
@ -159,7 +137,8 @@ class CLangMngr
LangVec m_Languages; LangVec m_Languages;
CVector<md5Pair *> FileList; CVector<md5Pair *> FileList;
CVector<keyEntry*> KeyList; CVector<String *> KeyList;
THash<String, keytbl_val> KeyTable;
// Get a lang object (construct if needed) // Get a lang object (construct if needed)
CLang * GetLang(const char *name); CLang * GetLang(const char *name);
@ -185,16 +164,15 @@ public:
// Cache // Cache
bool LoadCache(const char *filename); bool LoadCache(const char *filename);
bool SaveCache(const char *filename); bool SaveCache(const char *filename);
void InvalidateCache();
// Get index // Get index
int GetKeyEntry(String &key); int GetKeyEntry(String &key);
int GetKeyEntry(const char *key); int GetKeyEntry(const char *key);
int GetKeyHash(int key); int GetKeyIndex(const char *key);
// Get key from index // Get key from index
const char *GetKey(int key); const char *GetKey(int key);
// Add key // Add key
int AddKeyEntry(String &key); int AddKeyEntry(String &key);
// Make a hash from a string; convert to lowercase first if needed
uint32_t MakeHash(const char *src, bool makeLower);
// Get the number of languages // Get the number of languages
int GetLangsNum(); int GetLangsNum();

View File

@ -118,7 +118,7 @@ public:
v[0] = '\0'; v[0] = '\0';
} }
int compare (const char *d) int compare (const char *d) const
{ {
if (!v) if (!v)
return strcmp("", d); return strcmp("", d);

View File

@ -249,7 +249,10 @@ int C_Spawn(edict_t *pent)
// ###### Load lang // ###### Load lang
char file[256]; char file[256];
g_langMngr.LoadCache(build_pathname_r(file, sizeof(file) - 1, "%s/dictionary.cache", get_localinfo("amxx_datadir", "addons/amxmodx/data"))); g_langMngr.LoadCache(build_pathname_r(file, sizeof(file) - 1, "%s/dictionary.cache", get_localinfo("amxx_datadir", "addons/amxmodx/data")));
g_langMngr.Load(build_pathname_r(file, sizeof(file) - 1, "%s/languages.dat", get_localinfo("amxmodx_datadir", "addons/amxmodx/data"))); if (!g_langMngr.Load(build_pathname_r(file, sizeof(file) - 1, "%s/languages.dat", get_localinfo("amxmodx_datadir", "addons/amxmodx/data"))))
{
g_langMngr.InvalidateCache();
}
// ###### Initialize commands prefixes // ###### Initialize commands prefixes
g_commands.registerPrefix("amx"); g_commands.registerPrefix("amx");

View File

@ -257,7 +257,7 @@
LinkIncremental="1" LinkIncremental="1"
SuppressStartupBanner="TRUE" SuppressStartupBanner="TRUE"
AdditionalLibraryDirectories="..\extra\lib_win32" AdditionalLibraryDirectories="..\extra\lib_win32"
IgnoreDefaultLibraryNames="LIBC" IgnoreDefaultLibraryNames="MSVCRT"
ModuleDefinitionFile="" ModuleDefinitionFile=""
GenerateDebugInformation="TRUE" GenerateDebugInformation="TRUE"
ProgramDatabaseFile=".\memtestrelease/amxx_mm.pdb" ProgramDatabaseFile=".\memtestrelease/amxx_mm.pdb"
@ -822,9 +822,15 @@
<File <File
RelativePath="..\resource.h"> RelativePath="..\resource.h">
</File> </File>
<File
RelativePath="..\sh_list.h">
</File>
<File <File
RelativePath="..\sh_stack.h"> RelativePath="..\sh_stack.h">
</File> </File>
<File
RelativePath="..\sh_tinyhash.h">
</File>
<File <File
RelativePath="..\zlib\zconf.h"> RelativePath="..\zlib\zconf.h">
</File> </File>

View File

@ -32,7 +32,9 @@
#define _INCLUDE_NATIVES_H #define _INCLUDE_NATIVES_H
//only 16 for now sorry //only 16 for now sorry
#if !defined CALLFUNC_MAXPARAMS
#define CALLFUNC_MAXPARAMS 16 #define CALLFUNC_MAXPARAMS 16
#endif
#define CALLFUNC_FLAG_BYREF 1 #define CALLFUNC_FLAG_BYREF 1
#define CALLFUNC_FLAG_BYREF_REUSED 2 #define CALLFUNC_FLAG_BYREF_REUSED 2

268
amxmodx/sh_list.h Normal file
View File

@ -0,0 +1,268 @@
/* ======== SourceMM ========
* Copyright (C) 2004-2005 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
*
* Author(s): David "BAILOPAN" Anderson
* ============================
*/
#ifndef _INCLUDE_SMM_LIST_H
#define _INCLUDE_SMM_LIST_H
//namespace SourceHook
//{
//This class is from CSDM for AMX Mod X
template <class T>
class List
{
public:
class iterator;
friend class iterator;
class ListNode
{
public:
ListNode(const T & o) : obj(o) { };
ListNode() { };
~ListNode()
{
};
T obj;
ListNode *next;
ListNode *prev;
};
private:
ListNode *_Initialize()
{
ListNode *n = (ListNode *)malloc(sizeof(ListNode));
n->next = NULL;
n->prev = NULL;
return n;
}
public:
List() : m_Head(_Initialize()), m_Size(0)
{
}
List(const List &src) : m_Head(_Initialize()), m_Size(0)
{
iterator iter;
for (iter=src.begin(); iter!=src.end(); iter++)
push_back( (*iter) );
}
~List()
{
clear();
if (m_Head)
{
free(m_Head);
m_Head = NULL;
}
}
void push_back(const T &obj)
{
ListNode *node = new ListNode(obj);
if (!m_Head->prev)
{
//link in the node as the first item
node->next = m_Head;
node->prev = m_Head;
m_Head->prev = node;
m_Head->next = node;
} else {
node->prev = m_Head->prev;
node->next = m_Head;
m_Head->prev->next = node;
m_Head->prev = node;
}
m_Size++;
}
size_t size()
{
return m_Size;
}
void clear()
{
ListNode *node = m_Head->next;
ListNode *temp;
m_Head->next = NULL;
m_Head->prev = NULL;
while (node && node != m_Head)
{
temp = node->next;
delete node;
node = temp;
}
m_Size = 0;
}
bool empty()
{
return (m_Head->next == NULL);
}
T & back()
{
return m_Head->prev->obj;
}
private:
ListNode *m_Head;
size_t m_Size;
public:
class iterator
{
friend class List;
public:
iterator()
{
m_This = NULL;
}
iterator(const List &src)
{
m_This = src.m_Head;
}
iterator(ListNode *n) : m_This(n)
{
}
iterator(const iterator &where)
{
m_This = where.m_This;
}
//pre decrement
iterator & operator--()
{
if (m_This)
m_This = m_This->prev;
return *this;
}
//post decrement
iterator operator--(int)
{
iterator old(*this);
if (m_This)
m_This = m_This->prev;
return old;
}
//pre increment
iterator & operator++()
{
if (m_This)
m_This = m_This->next;
return *this;
}
//post increment
iterator operator++(int)
{
iterator old(*this);
if (m_This)
m_This = m_This->next;
return old;
}
const T & operator * () const
{
return m_This->obj;
}
T & operator * ()
{
return m_This->obj;
}
T * operator -> ()
{
return &(m_This->obj);
}
const T * operator -> () const
{
return &(m_This->obj);
}
bool operator != (const iterator &where) const
{
return (m_This != where.m_This);
}
bool operator ==(const iterator &where) const
{
return (m_This == where.m_This);
}
private:
ListNode *m_This;
};
public:
iterator begin() const
{
if (m_Size)
return iterator(m_Head->next);
else
return iterator(m_Head);
}
iterator end() const
{
return iterator(m_Head);
}
iterator erase(iterator &where)
{
ListNode *pNode = where.m_This;
iterator iter(where);
iter++;
//If we are both the head and tail...
if (m_Head->next == pNode && m_Head->prev == pNode)
{
m_Head->next = NULL;
m_Head->prev = NULL;
} else if (m_Head->next == pNode) {
//we are only the first
pNode->next->prev = m_Head;
m_Head->next = pNode->next;
} else if (m_Head->prev == pNode) {
//we are the tail
pNode->prev->next = m_Head;
m_Head->prev = pNode->prev;
} else {
//middle unlink
pNode->prev->next = pNode->next;
pNode->next->prev = pNode->prev;
}
delete pNode;
m_Size--;
return iter;
}
public:
void remove(const T & obj)
{
iterator b;
for (b=begin(); b!=end(); b++)
{
if ( (*b) == obj )
{
erase( b );
break;
}
}
}
template <typename U>
iterator find(const U & equ)
{
iterator iter;
for (iter=begin(); iter!=end(); iter++)
{
if ( (*iter) == equ )
return iter;
}
return end();
}
List & operator =(List &src)
{
clear();
iterator iter;
for (iter=src.begin(); iter!=src.end(); iter++)
push_back( (*iter) );
return *this;
}
};
//}; //NAMESPACE
#endif //_INCLUDE_CSDM_LIST_H

483
amxmodx/sh_tinyhash.h Normal file
View File

@ -0,0 +1,483 @@
/* ======== SourceMM ========
* Copyright (C) 2004-2005 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
*
* Author(s): David "BAILOPAN" Anderson
* ============================
*/
#ifndef _INCLUDE_SH_TINYHASH_H_
#define _INCLUDE_SH_TINYHASH_H_
#include "sh_list.h"
#define _T_INIT_HASH_SIZE 32
//namespace SourceHook
//{
template <class K>
int HashFunction(const K & k);
template <class K>
int Compare(const K & k1, const K & k2);
/**
* This is a tiny, growable hash class.
* Meant for quick and dirty dictionaries only!
*/
template <class K, class V>
class THash
{
public:
struct THashNode
{
THashNode(const K & k, const V & v) :
key(k), val(v)
{
};
~THashNode()
{
}
K key;
V val;
};
typedef List<THashNode *> * NodePtr;
public:
THash() : m_Buckets(NULL), m_numBuckets(0), m_percentUsed(0.0f), m_NumItems(0)
{
_Refactor();
}
THash(const THash &other) : m_Buckets(new NodePtr[other.m_numBuckets]),
m_numBuckets(other.m_numBuckets), m_percentUsed(other.m_percentUsed)
{
for (size_t i=0; i<m_numBuckets; i++)
m_Buckets[i] = NULL;
for (const_iterator iter = other.begin(); iter != other.end(); ++iter)
_FindOrInsert(iter->key)->val = iter->val;
}
void operator=(const THash &other)
{
clear();
for (const_iterator iter = other.begin(); iter != other.end(); ++iter)
_FindOrInsert(iter->key)->val = iter->val;
}
~THash()
{
_Clear();
}
void clear()
{
_Clear();
_Refactor();
}
size_t GetBuckets()
{
return m_numBuckets;
}
float PercentUsed()
{
return m_percentUsed;
}
size_t size()
{
return m_NumItems;
}
V & operator [](const K & key)
{
THashNode *pNode = _FindOrInsert(key);
return pNode->val;
}
private:
void _Clear()
{
List<THashNode *>::iterator iter, begin, end;
for (size_t i=0; i<m_numBuckets; i++)
{
if (m_Buckets[i])
{
begin = m_Buckets[i]->begin();
end = m_Buckets[i]->end();
for (iter=begin; iter!=end; iter++)
delete (*iter);
delete m_Buckets[i];
m_Buckets[i] = NULL;
}
}
if (m_Buckets)
delete [] m_Buckets;
m_Buckets = NULL;
m_numBuckets = 0;
m_NumItems = 0;
}
THashNode *_FindOrInsert(const K & key)
{
size_t place = HashFunction(key) % m_numBuckets;
THashNode *pNode = NULL;
if (!m_Buckets[place])
{
m_Buckets[place] = new List<THashNode *>;
pNode = new THashNode(key, V());
m_Buckets[place]->push_back(pNode);
m_percentUsed += (1.0f / (float)m_numBuckets);
m_NumItems++;
} else {
typename List<THashNode *>::iterator iter;
for (iter=m_Buckets[place]->begin(); iter!=m_Buckets[place]->end(); iter++)
{
if (Compare((*iter)->key, key) == 0)
return (*iter);
}
//node does not exist
pNode = new THashNode(key, V());
m_Buckets[place]->push_back(pNode);
m_NumItems++;
}
if (PercentUsed() > 0.75f)
_Refactor();
return pNode;
}
void _Refactor()
{
m_percentUsed = 0.0f;
if (!m_numBuckets)
{
m_numBuckets = _T_INIT_HASH_SIZE;
m_Buckets = new NodePtr[m_numBuckets];
for (size_t i=0; i<m_numBuckets; i++)
m_Buckets[i] = NULL;
} else {
size_t oldSize = m_numBuckets;
m_numBuckets *= 2;
typename List<THashNode *>::iterator iter;
size_t place;
THashNode *pHashNode;
NodePtr *temp = new NodePtr[m_numBuckets];
for (size_t i=0; i<m_numBuckets; i++)
temp[i] = NULL;
//look in old hash table
for (size_t i=0; i<oldSize; i++)
{
//does a bucket have anything?
if (m_Buckets[i])
{
//go through the list of items
for (iter = m_Buckets[i]->begin(); iter != m_Buckets[i]->end(); iter++)
{
pHashNode = (*iter);
//rehash it with the new bucket filter
place = HashFunction(pHashNode->key) % m_numBuckets;
//add it to the new hash table
if (!temp[place])
{
temp[place] = new List<THashNode *>;
m_percentUsed += (1.0f / (float)m_numBuckets);
}
temp[place]->push_back(pHashNode);
}
//delete that bucket!
delete m_Buckets[i];
m_Buckets[i] = NULL;
}
}
//reassign bucket table
delete [] m_Buckets;
m_Buckets = temp;
}
}
public:
friend class iterator;
friend class const_iterator;
class iterator
{
friend class THash;
public:
iterator() : curbucket(-1), hash(NULL), end(true)
{
};
iterator(THash *h) : curbucket(-1), hash(h), end(false)
{
if (!h->m_Buckets)
end = true;
else
_Inc();
};
//pre increment
iterator & operator++()
{
_Inc();
return *this;
}
//post increment
iterator operator++(int)
{
iterator old(*this);
_Inc();
return old;
}
const THashNode & operator * () const
{
return *(*iter);
}
THashNode & operator * ()
{
return *(*iter);
}
const THashNode * operator ->() const
{
return (*iter);
}
THashNode * operator ->()
{
return (*iter);
}
bool operator ==(const iterator &where) const
{
if (where.hash == this->hash
&& where.end == this->end
&&
(this->end ||
((where.curbucket == this->curbucket)
&& (where.iter == iter))
))
return true;
return false;
}
bool operator !=(const iterator &where) const
{
return !( (*this) == where );
}
void erase()
{
if (end || !hash || curbucket < 0 || curbucket >= static_cast<int>(hash->m_numBuckets))
return;
// Remove this element and move to the next one
iterator tmp = *this;
++tmp;
hash->m_Buckets[curbucket]->erase(iter);
*this = tmp;
m_NumItems--;
// :TODO: Maybe refactor to a lower size if required
}
private:
void _Inc()
{
if (end || !hash || curbucket >= static_cast<int>(hash->m_numBuckets))
return;
if (curbucket < 0)
{
for (int i=0; i<(int)hash->m_numBuckets; i++)
{
if (hash->m_Buckets[i])
{
iter = hash->m_Buckets[i]->begin();
if (iter == hash->m_Buckets[i]->end())
continue;
curbucket = i;
break;
}
}
if (curbucket < 0)
end = true;
} else {
if (iter != hash->m_Buckets[curbucket]->end())
iter++;
if (iter == hash->m_Buckets[curbucket]->end())
{
int oldbucket = curbucket;
for (int i=curbucket+1; i<(int)hash->m_numBuckets; i++)
{
if (hash->m_Buckets[i])
{
iter = hash->m_Buckets[i]->begin();
if (iter == hash->m_Buckets[i]->end())
continue;
curbucket = i;
break;
}
}
if (curbucket == oldbucket)
end = true;
}
}
}
private:
int curbucket;
typename List<THashNode *>::iterator iter;
THash *hash;
bool end;
};
class const_iterator
{
friend class THash;
public:
const_iterator() : curbucket(-1), hash(NULL), end(true)
{
};
const_iterator(const THash *h) : curbucket(-1), hash(h), end(false)
{
if (!h->m_Buckets)
end = true;
else
_Inc();
};
//pre increment
const_iterator & operator++()
{
_Inc();
return *this;
}
//post increment
const_iterator operator++(int)
{
iterator old(*this);
_Inc();
return old;
}
const THashNode & operator * () const
{
return *(*iter);
}
const THashNode * operator ->() const
{
return (*iter);
}
bool operator ==(const const_iterator &where) const
{
if (where.hash == this->hash
&& where.end == this->end
&&
(this->end ||
((where.curbucket == this->curbucket)
&& (where.iter == iter))
))
return true;
return false;
}
bool operator !=(const const_iterator &where) const
{
return !( (*this) == where );
}
private:
void _Inc()
{
if (end || !hash || curbucket >= static_cast<int>(hash->m_numBuckets))
return;
if (curbucket < 0)
{
for (int i=0; i<(int)hash->m_numBuckets; i++)
{
if (hash->m_Buckets[i])
{
iter = hash->m_Buckets[i]->begin();
if (iter == hash->m_Buckets[i]->end())
continue;
curbucket = i;
break;
}
}
if (curbucket < 0)
end = true;
} else {
if (iter != hash->m_Buckets[curbucket]->end())
iter++;
if (iter == hash->m_Buckets[curbucket]->end())
{
int oldbucket = curbucket;
for (int i=curbucket+1; i<(int)hash->m_numBuckets; i++)
{
if (hash->m_Buckets[i])
{
iter = hash->m_Buckets[i]->begin();
if (iter == hash->m_Buckets[i]->end())
continue;
curbucket = i;
break;
}
}
if (curbucket == oldbucket)
end = true;
}
}
}
private:
int curbucket;
typename List<THashNode *>::iterator iter;
const THash *hash;
bool end;
};
public:
iterator begin()
{
return iterator(this);
}
iterator end()
{
iterator iter;
iter.hash = this;
return iter;
}
const_iterator begin() const
{
return const_iterator(this);
}
const_iterator end() const
{
const_iterator iter;
iter.hash = this;
return iter;
}
template <typename U>
iterator find(const U & u) const
{
iterator b = begin();
iterator e = end();
for (iterator iter = b; iter != e; iter++)
{
if ( (*iter).key == u )
return iter;
}
return end();
}
template <typename U>
iterator find(const U & u)
{
iterator b = begin();
iterator e = end();
for (iterator iter = b; iter != e; iter++)
{
if ( (*iter).key == u )
return iter;
}
return end();
}
iterator erase(iterator where)
{
where.erase();
return where;
}
template <typename U>
void erase(const U & u)
{
iterator iter = find(u);
if (iter == end())
return;
iter.erase();
}
private:
NodePtr *m_Buckets;
size_t m_numBuckets;
float m_percentUsed;
size_t m_NumItems;
};
//};
#endif //_INCLUDE_SH_TINYHASH_H_