Rewrote language backend for integrity checking and optimization
Replaced CRC32 system with real hash-map
This commit is contained in:
		| @@ -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) | ||||||
| 	{ | 	{ | ||||||
| 		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; | 		status = LANG_STATUS_KLNOTFOUND; | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| struct OffsetPair | 	return def.definition->c_str(); | ||||||
| { | } | ||||||
| 	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 = ␣ | ||||||
|  | 		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 = ␣ | ||||||
| 		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]) | ||||||
|   | |||||||
| @@ -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,48 +113,8 @@ 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 |  | ||||||
| 		{ |  | ||||||
| 			// 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; | 		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(); | ||||||
|   | |||||||
| @@ -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); | ||||||
|   | |||||||
| @@ -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"); | ||||||
|   | |||||||
| @@ -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> | ||||||
|   | |||||||
| @@ -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
									
								
							
							
						
						
									
										268
									
								
								amxmodx/sh_list.h
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										483
									
								
								amxmodx/sh_tinyhash.h
									
									
									
									
									
										Normal 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_ | ||||||
		Reference in New Issue
	
	Block a user