diff --git a/amxmodx/CLang.cpp b/amxmodx/CLang.cpp index 3af9ea3e..2c8adb66 100755 --- a/amxmodx/CLang.cpp +++ b/amxmodx/CLang.cpp @@ -46,9 +46,9 @@ #define INSERT_STRING 3 #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 FFHL_VERSION 4 +#define FFHL_VERSION 5 #define FFHL_MIN_VERSION 4 /*version history: @@ -56,6 +56,7 @@ * 2 (BAILOPAN) - One language 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) + * 5 (BAILOPAN) - Removed hash storage FORMAT: Magic 4bytes Version 1byte @@ -65,13 +66,11 @@ LANG INFO TABLE[] Language Name 2bytes Offset 4bytes KEY TABLE[] - Key Hash 4bytes Key Lookup Offset 4bytes LANGUAGES TABLE[] Language[] Definitions 4bytes - Key Hash # 4bytes (virtual # in hash table, 0 indexed) - Def Hash 4bytes + Key # 4bytes (0-index into key table) Def Offset 4bytes KEY LOOKUP TABLE[] Key length 1byte @@ -81,70 +80,32 @@ DEF LOOKUP TABLE[] Def string variable */ -/******** CRC & Strip *********/ -const uint32_t CRCTable[256] = { - 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) +template<> +int Compare(const String &k1, const String &k2) { - uint32_t crc = 0xFFFFFFFF; - - while (*src) - crc = ((crc>>8)&0xFFFFFFFF)^CRCTable[(crc^ (makeLower ? tolower(*src++) : *src++) )&0xFF]; - - return ~crc; + return k1.compare(k2.c_str()); } -uint32_t CLangMngr::MakeHash(const char *src, bool makeLower) +template<> +int HashFunction(const String &k) { - uint32_t crc = 0xFFFFFFFF; - - while (*src) - crc = ((crc>>8)&0xFFFFFFFF)^CRCTable[(crc^ (makeLower ? tolower(*src++) : *src++) )&0xFF]; - - return ~crc; + 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; +} + +template<> +int HashFunction(const int &k) +{ + return k; +} + +template<> +int Compare(const int &k1, const int &k2) +{ + return (k1-k2); } // 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; } -/******** 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 *********/ @@ -283,15 +164,14 @@ CLangMngr::CLang::CLang(const char *lang) 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]; + + if (d.definition) + delete d.definition; - p->SetCache(cache); - - m_LookUpTable.push_back(p); - - return p; + d.definition = new String(definition); } CLangMngr::CLang::~CLang() @@ -301,99 +181,66 @@ CLangMngr::CLang::~CLang() void CLangMngr::CLang::Clear() { - for (unsigned int i = 0; i < m_LookUpTable.size(); i++) + THash::iterator iter; + for (iter=m_LookUpTable.begin(); iter!=m_LookUpTable.end(); iter++) { - if (m_LookUpTable[i]) - delete m_LookUpTable[i]; + if (iter->val.definition) + { + delete iter->val.definition; + iter->val.definition = NULL; + } } - m_LookUpTable.clear(); } -CLangMngr::CLang::LangEntry * CLangMngr::CLang::GetEntry(int pkey) +void CLangMngr::CLang::MergeDefinitions(CQueue &vec) { - unsigned int i; - - 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 &vec) -{ - const char *def = 0; + String *pDef; int key = -1; while (!vec.empty()) { - key = vec.front()->key; - def = vec.front()->def->c_str(); - LangEntry *entry = GetEntry(key); + key = vec.front().key; + pDef = vec.front().definition; + + AddEntry(key, pDef->c_str()); + + delete vec.front().definition; - if (entry->GetDefHash() != MakeHash(def)) - { - if (entry->GetCache()) - { - 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(); } } -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); - - if (ikey == -1) + defentry &def = m_LookUpTable[key]; + + if (!def.definition) { + status = LANG_STATUS_KLNOTFOUND; return NULL; } - for (unsigned int i = 0; i < m_LookUpTable.size(); i++) - { - if (m_LookUpTable[i]->GetKey() == ikey) - return m_LookUpTable[i]->GetDef(); - } - - status = LANG_STATUS_KLNOTFOUND; - return NULL; + return def.definition->c_str(); } -struct OffsetPair -{ - uint32_t defOffset; - uint32_t keyOffset; -}; - // Assumes fp is set to the right position bool CLangMngr::CLang::SaveDefinitions(FILE *fp, uint32_t &curOffset) { unsigned short defLen = 0; + String *pdef; + String blank; - for (unsigned int i = 0; i < m_LookUpTable.size(); i++) + THash::iterator iter; + for (iter=m_LookUpTable.begin(); iter!=m_LookUpTable.end(); iter++) { - defLen = m_LookUpTable[i]->GetDefLength(); + pdef = iter->val.definition; + if (!pdef) + pdef = ␣ + defLen = pdef->size(); fwrite((void *)&defLen, sizeof(unsigned short), 1, fp); curOffset += sizeof(unsigned short); - fwrite(m_LookUpTable[i]->GetDef(), sizeof(char), defLen, fp); + fwrite(pdef->c_str(), sizeof(char), defLen, fp); 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) { uint32_t keynum = 0; - uint32_t defhash = 0; uint32_t size = m_LookUpTable.size(); + String *pdef; + String blank; fwrite((void*)&size, sizeof(uint32_t), 1, fp); curOffset += sizeof(uint32_t); - for (unsigned int i = 0; i < m_LookUpTable.size(); i++) + THash::iterator iter; + for (iter=m_LookUpTable.begin(); iter!=m_LookUpTable.end(); iter++) { - keynum = m_LookUpTable[i]->GetKey(); - defhash = m_LookUpTable[i]->GetDefHash(); + keynum = iter->key; + pdef = iter->val.definition; + if (!pdef) + pdef = ␣ fwrite((void *)&keynum, sizeof(uint32_t), 1, fp); curOffset += sizeof(uint32_t); - fwrite((void *)&defhash, sizeof(uint32_t), 1, fp); - curOffset += sizeof(uint32_t); fwrite((void *)&defOffset, sizeof(uint32_t), 1, fp); curOffset += sizeof(uint32_t); defOffset += sizeof(short); - defOffset += m_LookUpTable[i]->GetDefLength(); + defOffset += pdef->size(); } return true; @@ -443,69 +292,36 @@ CLangMngr::CLangMngr() const char * CLangMngr::GetKey(int key) { if (key < 0 || key >= (int)KeyList.size()) - return 0; + return NULL; - return KeyList[key]->key.c_str(); -} - -int CLangMngr::GetKeyHash(int key) -{ - if (key < 0 || key >= (int)KeyList.size()) - return 0; - - return KeyList[key]->hash; + return KeyList[key]->c_str(); } int CLangMngr::GetKeyEntry(const char *key) { - uint32_t hKey = MakeHash(key, true); - uint32_t cmpKey = 0; - unsigned int i = 0; + keytbl_val val = KeyTable[key]; - if (hKey == 0) - { - return -1; - } - - for (i = 0; i < KeyList.size(); i++) - { - cmpKey = KeyList[i]->hash; - - if (hKey == cmpKey) - { - return i; - } - } - - return -1; + return val.index; } int CLangMngr::AddKeyEntry(String &key) { - uint32_t hKey = MakeHash(key.c_str(), true); + keytbl_val val; + val.index = static_cast(KeyList.size()); - keyEntry *e = new keyEntry; - e->key.assign(key); - e->hash = hKey; - KeyList.push_back(e); + String *pString = new String(key); + KeyList.push_back(pString); - return (KeyList.size() - 1); + KeyTable[key] = val; + + return val.index; } int CLangMngr::GetKeyEntry(String &key) { - uint32_t hKey = MakeHash(key.c_str(), true); - unsigned int i = 0; + keytbl_val val = KeyTable[key]; - for (i = 0; i < KeyList.size(); i++) - { - if (hKey == KeyList[i]->hash) - { - return i; - } - } - - return -1; + return val.index; } #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; } -void CLangMngr::MergeDefinitions(const char *lang, CQueue &tmpVec) +void CLangMngr::MergeDefinitions(const char *lang, CQueue &tmpVec) { CLang * language = GetLang(lang); if (language) @@ -1062,10 +878,10 @@ int CLangMngr::MergeDefinitionFile(const char *file) // Allocate enough memory to store everything bool multiline = 0; int pos = 0, line = 0; - CQueue Defq; + CQueue Defq; String buf; char language[3]; - sKeyDef *tmpEntry = NULL; + sKeyDef tmpEntry; while (!feof(fp)) { @@ -1082,9 +898,8 @@ int CLangMngr::MergeDefinitionFile(const char *file) if (multiline) { AMXXLOG_Log("New section, multiline unterminated (file \"%s\" line %d)", file, line); - if (tmpEntry) - delete tmpEntry; - tmpEntry = 0; + tmpEntry.key = -1; + tmpEntry.definition = NULL; } if (!Defq.empty()) @@ -1102,7 +917,6 @@ int CLangMngr::MergeDefinitionFile(const char *file) if (pos > String::npos) { - tmpEntry = new sKeyDef; String key; key.assign(buf.substr(0, pos).c_str()); String def; @@ -1112,18 +926,18 @@ int CLangMngr::MergeDefinitionFile(const char *file) int iKey = GetKeyEntry(key); if (iKey == -1) iKey = AddKeyEntry(key); - tmpEntry->key = iKey; - tmpEntry->def = new String; - tmpEntry->def->assign(def.c_str()); - tmpEntry->def->trim(); + tmpEntry.key = iKey; + tmpEntry.definition = new String; + tmpEntry.definition->assign(def.c_str()); + tmpEntry.definition->trim(); Defq.push(tmpEntry); - tmpEntry = 0; + tmpEntry.key = -1; + tmpEntry.definition = NULL; } else { pos = buf.find(':'); if (pos > String::npos) { - tmpEntry = new sKeyDef; String key; key.assign(buf.substr(0, pos).c_str());; key.trim(); @@ -1131,8 +945,8 @@ int CLangMngr::MergeDefinitionFile(const char *file) int iKey = GetKeyEntry(key); if (iKey == -1) iKey = AddKeyEntry(key); - tmpEntry->key = iKey; - tmpEntry->def = new String; + tmpEntry.key = iKey; + tmpEntry.definition = new String; multiline = true; } else { //user typed a line with no directives @@ -1143,10 +957,13 @@ int CLangMngr::MergeDefinitionFile(const char *file) if (buf[0] == ':') { Defq.push(tmpEntry); - tmpEntry = 0; + tmpEntry.key = -1; + tmpEntry.definition = NULL; multiline = false; } else { - tmpEntry->def->append(buf); + if (!tmpEntry.definition) + tmpEntry.definition = new String(); + tmpEntry.definition->append(buf); } } // if !multiline } //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) { 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; 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) { FILE *fp = fopen(filename, "wb"); @@ -1217,7 +1048,7 @@ bool CLangMngr::Save(const char *filename) const char *langName = 0; uint32_t curOffset = 0; 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)); fwrite((void *)&magic, sizeof(uint32_t), 1, fp); @@ -1237,7 +1068,7 @@ bool CLangMngr::Save(const char *filename) fwrite(langName, sizeof(char), 2, fp); curOffset += sizeof(char) * 2; 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); } @@ -1246,13 +1077,10 @@ bool CLangMngr::Save(const char *filename) uint32_t keyOffset = langOffset; 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); curOffset += sizeof(uint32_t); keyOffset += sizeof(char); - keyOffset += KeyList[i]->key.size(); + keyOffset += KeyList[i]->size(); } //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; 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); 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; } @@ -1314,6 +1142,19 @@ bool CLangMngr::SaveCache(const char *filename) 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) { FILE *fp = fopen(filename, "rb"); @@ -1326,15 +1167,15 @@ bool CLangMngr::LoadCache(const char *filename) char len = 0; char buf[255]; char md5[34]; - fread((void*)&dictCount, sizeof(short), 1, fp); + CACHEREAD(fread((void*)&dictCount, sizeof(short), 1, fp), short); md5Pair *p = 0; for (int i = 1; i <= dictCount; i++) { - fread((void*)&len, sizeof(char), 1, fp); - fread(buf, sizeof(char), len, fp); + CACHEREAD(fread((void*)&len, sizeof(char), 1, fp), char); + CACHEREAD_S(fread(buf, sizeof(char), len, fp), len); buf[len] = 0; - fread(md5, sizeof(char), 32, fp); + CACHEREAD_S(fread(md5, sizeof(char), 32, fp), 32); md5[32] = 0; p = new md5Pair; p->file.assign(buf); @@ -1348,6 +1189,19 @@ bool CLangMngr::LoadCache(const char *filename) 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) { Clear(); @@ -1362,75 +1216,93 @@ bool CLangMngr::Load(const char *filename) uint32_t keycount = 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) 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) return false; - fread((void*)&keycount, sizeof(uint32_t), 1, fp); - fread((void*)&langCount, sizeof(uint32_t), 1, fp); + DATREAD(fread((void*)&keycount, sizeof(uint32_t), 1, fp), uint32_t); + DATREAD(fread((void*)&langCount, sizeof(uint32_t), 1, fp), uint32_t); uint32_t *LangOffsets = new uint32_t[langCount]; char langname[3]; 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; 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 int ktbOffset = ftell(fp); - keyEntry *e = 0; unsigned char keylen; + char keybuf[255]; + uint32_t bogus; uint32_t keyoffset, save; + String _tmpkey; for (unsigned i = 0; i < keycount; i++) { - e = new keyEntry; - fread((void*)&(e->hash), sizeof(uint32_t), 1, fp); - fread((void*)&keyoffset, sizeof(uint32_t), 1, fp); + if (version == 4) + fread((void*)&(bogus), 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); fseek(fp, keyoffset, SEEK_SET); - fread((void*)&keylen, sizeof(char), 1, fp); - char *data = new char[keylen + 1]; - fread(data, sizeof(char), keylen, fp); - data[keylen] = 0; - e->key.assign(data); - delete [] data; - KeyList.push_back(e); + DATREAD(fread((void*)&keylen, sizeof(char), 1, fp), char); + DATREAD_S(fread(keybuf, sizeof(char), keylen, fp), keylen); + keybuf[keylen] = 0; + _tmpkey.assign(keybuf); + AddKeyEntry(_tmpkey); fseek(fp, save, SEEK_SET); //bring back to next key } //we should now be at the languages table uint32_t numentries; uint32_t keynum; - uint32_t defhash; uint32_t defoffset; unsigned short deflen; + char valbuf[4096]; 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++) { - fread((void *)&keynum, sizeof(uint32_t), 1, fp); - fread((void *)&defhash, sizeof(uint32_t), 1, fp); - fread((void *)&defoffset, sizeof(uint32_t), 1, fp); + DATREAD(fread((void *)&keynum, sizeof(uint32_t), 1, fp), uint32_t); + if (version == 4) + { + 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); fseek(fp, defoffset, SEEK_SET); - fread((void *)&deflen, sizeof(unsigned short), 1, fp); - char *data = new char[deflen + 1]; - fread(data, sizeof(char), deflen, fp); - data[deflen] = 0; - m_Languages[i]->AddEntry(keynum, defhash, data, true); - delete [] data; + DATREAD(fread((void *)&deflen, sizeof(unsigned short), 1, fp), short); + //:TODO: possible string overflow here. + DATREAD_S(fread(valbuf, sizeof(char), deflen, fp), deflen); + valbuf[deflen] = 0; + m_Languages[i]->AddEntry(keynum, valbuf); fseek(fp, save, SEEK_SET); //bring back to next entry } } @@ -1451,6 +1323,8 @@ CLangMngr::~CLangMngr() void CLangMngr::Clear() { unsigned int i = 0; + + KeyTable.clear(); for (i = 0; i < m_Languages.size(); i++) { diff --git a/amxmodx/CLang.h b/amxmodx/CLang.h index cf786337..4289c742 100755 --- a/amxmodx/CLang.h +++ b/amxmodx/CLang.h @@ -32,6 +32,8 @@ #ifndef _INCLUDE_CLANG_H #define _INCLUDE_CLANG_H +#include "sh_tinyhash.h" + #define LANG_SERVER 0 #define LANG_PLAYER -1 @@ -45,19 +47,35 @@ struct md5Pair String val; }; -struct keyEntry -{ - String key; - uint32_t hash; -}; - struct sKeyDef { - sKeyDef() { key = -1; def = 0; } - ~sKeyDef() { if (def) delete def; } - + String *definition; 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 @@ -73,9 +91,9 @@ class CLangMngr ~CLang(); // Get the definition - const char *GetDef(const char *key, int &status); + const char *GetDef(int key, int &status); // Add definitions to this language - void MergeDefinitions(CQueue & vec); + void MergeDefinitions(CQueue & vec); // Reset this language void Clear(); @@ -95,49 +113,9 @@ class CLangMngr void SetMngr(CLangMngr *l) { m_LMan = l; } // Get number of entries 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: - // An entry in the language - class LangEntry - { - // 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 LookUpVec; - typedef LookUpVec::iterator LookUpVecIter; + typedef THash LookUpVec; + typedef LookUpVec::iterator LookUpVecIter; char m_LanguageName[3]; @@ -145,11 +123,11 @@ class CLangMngr LookUpVec m_LookUpTable; CLangMngr *m_LMan; 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 - void MergeDefinitions(const char *lang, CQueue &tmpVec); + void MergeDefinitions(const char *lang, CQueue &tmpVec); // strip lowercase; make lower if needed static size_t strip(char *str, char *newstr, bool makelower = false); @@ -159,7 +137,8 @@ class CLangMngr LangVec m_Languages; CVector FileList; - CVector KeyList; + CVector KeyList; + THash KeyTable; // Get a lang object (construct if needed) CLang * GetLang(const char *name); @@ -185,16 +164,15 @@ public: // Cache bool LoadCache(const char *filename); bool SaveCache(const char *filename); + void InvalidateCache(); // Get index int GetKeyEntry(String &key); int GetKeyEntry(const char *key); - int GetKeyHash(int key); + int GetKeyIndex(const char *key); // Get key from index const char *GetKey(int key); // Add 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 int GetLangsNum(); diff --git a/amxmodx/CString.h b/amxmodx/CString.h index 4fe52b15..034e00e7 100755 --- a/amxmodx/CString.h +++ b/amxmodx/CString.h @@ -118,7 +118,7 @@ public: v[0] = '\0'; } - int compare (const char *d) + int compare (const char *d) const { if (!v) return strcmp("", d); diff --git a/amxmodx/meta_api.cpp b/amxmodx/meta_api.cpp index e8de75f8..e73f9b39 100755 --- a/amxmodx/meta_api.cpp +++ b/amxmodx/meta_api.cpp @@ -249,7 +249,10 @@ int C_Spawn(edict_t *pent) // ###### Load lang 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.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 g_commands.registerPrefix("amx"); diff --git a/amxmodx/msvc/amxmodx_mm.vcproj b/amxmodx/msvc/amxmodx_mm.vcproj index b84a1dd0..dfa63e11 100755 --- a/amxmodx/msvc/amxmodx_mm.vcproj +++ b/amxmodx/msvc/amxmodx_mm.vcproj @@ -257,7 +257,7 @@ LinkIncremental="1" SuppressStartupBanner="TRUE" AdditionalLibraryDirectories="..\extra\lib_win32" - IgnoreDefaultLibraryNames="LIBC" + IgnoreDefaultLibraryNames="MSVCRT" ModuleDefinitionFile="" GenerateDebugInformation="TRUE" ProgramDatabaseFile=".\memtestrelease/amxx_mm.pdb" @@ -822,9 +822,15 @@ + + + + diff --git a/amxmodx/natives.h b/amxmodx/natives.h index 4b54a2ca..995844e1 100755 --- a/amxmodx/natives.h +++ b/amxmodx/natives.h @@ -32,7 +32,9 @@ #define _INCLUDE_NATIVES_H //only 16 for now sorry +#if !defined CALLFUNC_MAXPARAMS #define CALLFUNC_MAXPARAMS 16 +#endif #define CALLFUNC_FLAG_BYREF 1 #define CALLFUNC_FLAG_BYREF_REUSED 2 diff --git a/amxmodx/sh_list.h b/amxmodx/sh_list.h new file mode 100644 index 00000000..95884fce --- /dev/null +++ b/amxmodx/sh_list.h @@ -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 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 + 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 diff --git a/amxmodx/sh_tinyhash.h b/amxmodx/sh_tinyhash.h new file mode 100644 index 00000000..1960b5ca --- /dev/null +++ b/amxmodx/sh_tinyhash.h @@ -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 + int HashFunction(const K & k); + + template + int Compare(const K & k1, const K & k2); + + /** + * This is a tiny, growable hash class. + * Meant for quick and dirty dictionaries only! + */ + template + class THash + { + public: + struct THashNode + { + THashNode(const K & k, const V & v) : + key(k), val(v) + { + }; + ~THashNode() + { + } + K key; + V val; + }; + typedef List * 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; ikey)->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::iterator iter, begin, end; + for (size_t i=0; ibegin(); + 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; + pNode = new THashNode(key, V()); + m_Buckets[place]->push_back(pNode); + m_percentUsed += (1.0f / (float)m_numBuckets); + m_NumItems++; + } else { + typename List::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::iterator iter; + size_t place; + THashNode *pHashNode; + NodePtr *temp = new NodePtr[m_numBuckets]; + for (size_t i=0; ibegin(); 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; + 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(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(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::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(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::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 + 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 + 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 + 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_