#ifndef __CASC_MAP_H__
#define __CASC_MAP_H__
#define MIN_HASH_TABLE_SIZE 0x00000100
typedef int (*PFNCOMPAREFUNC)(const void * pvObjectKey, const void * pvKey, size_t nKeyLength);
typedef DWORD (*PFNHASHFUNC)(void * pvKey, size_t nKeyLength);
typedef enum _KEY_TYPE
{
KeyIsHash, KeyIsArbitrary, KeyIsString } KEY_TYPE, *PKEY_TYPE;
#define KEY_LENGTH_STRING 0xFFFFFFFF
inline DWORD CalcHashValue_Hash(void * pvKey, size_t )
{
return ConvertBytesToInteger_4_LE((LPBYTE)pvKey);
}
inline DWORD CalcHashValue_Key(void * pvKey, size_t nKeyLength)
{
LPBYTE pbKey = (LPBYTE)pvKey;
DWORD dwHash = 0x7EEE7EEE;
for(DWORD i = 0; i < nKeyLength; i++)
dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ pbKey[i];
return dwHash;
}
inline DWORD CalcHashValue_String(const char * szString, const char * szStringEnd)
{
LPBYTE pbKeyEnd = (LPBYTE)szStringEnd;
LPBYTE pbKey = (LPBYTE)szString;
DWORD dwHash = 0x7EEE7EEE;
while(pbKey < pbKeyEnd)
{
dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ AsciiToUpperTable_BkSlash[pbKey[0]];
pbKey++;
}
return dwHash;
}
class CASC_MAP
{
public:
CASC_MAP()
{
PfnCalcHashValue = NULL;
m_HashTable = NULL;
m_HashTableSize = 0;
m_ItemCount = 0;
m_KeyOffset = 0;
m_KeyLength = 0;
m_bKeyIsHash = false;
}
~CASC_MAP()
{
Free();
}
DWORD Create(size_t MaxItems, size_t KeyLength, size_t KeyOffset, KEY_TYPE KeyType = KeyIsHash)
{
m_KeyLength = CASCLIB_MAX(KeyLength, 8);
m_KeyOffset = KeyOffset;
m_ItemCount = 0;
switch(KeyType)
{
case KeyIsHash:
PfnCalcHashValue = CalcHashValue_Hash;
break;
case KeyIsArbitrary:
PfnCalcHashValue = CalcHashValue_Key;
break;
case KeyIsString:
PfnCalcHashValue = NULL;
break;
default:
assert(false);
return ERROR_NOT_SUPPORTED;
}
m_HashTableSize = GetNearestPowerOfTwo(MaxItems * 4 / 3);
if(m_HashTableSize == 0)
return ERROR_NOT_ENOUGH_MEMORY;
m_HashTable = (void **)CASC_ALLOC_ZERO<void *>(m_HashTableSize);
return (m_HashTable != NULL) ? ERROR_SUCCESS : ERROR_NOT_ENOUGH_MEMORY;
}
void * FindObject(void * pvKey, PDWORD PtrIndex = NULL)
{
void * pvObject;
DWORD dwHashIndex;
if(m_HashTable != NULL)
{
dwHashIndex = HashToIndex(PfnCalcHashValue(pvKey, m_KeyLength));
while((pvObject = m_HashTable[dwHashIndex]) != NULL)
{
if(CompareObject_Key(pvObject, pvKey))
{
if(PtrIndex != NULL)
PtrIndex[0] = dwHashIndex;
return pvObject;
}
dwHashIndex = HashToIndex(dwHashIndex + 1);
}
}
return NULL;
}
bool InsertObject(void * pvNewObject, void * pvKey)
{
void * pvExistingObject;
DWORD dwHashIndex;
if(m_HashTable != NULL)
{
if((m_ItemCount + 1) >= m_HashTableSize)
return false;
dwHashIndex = HashToIndex(PfnCalcHashValue(pvKey, m_KeyLength));
while((pvExistingObject = m_HashTable[dwHashIndex]) != NULL)
{
if(CompareObject_Key(pvExistingObject, pvKey))
return false;
dwHashIndex = HashToIndex(dwHashIndex + 1);
}
m_HashTable[dwHashIndex] = pvNewObject;
m_ItemCount++;
return true;
}
return false;
}
const char * FindString(const char * szString, const char * szStringEnd)
{
const char * szExistingString;
DWORD dwHashIndex;
if(m_HashTable != NULL)
{
dwHashIndex = HashToIndex(CalcHashValue_String(szString, szStringEnd));
while((szExistingString = (const char *)m_HashTable[dwHashIndex]) != NULL)
{
if(CompareObject_String(szExistingString, szString, szStringEnd))
return szExistingString;
dwHashIndex = HashToIndex(dwHashIndex + 1);
}
}
return NULL;
}
bool InsertString(const char * szString, bool bCutExtension)
{
const char * szExistingString;
const char * szStringEnd = NULL;
DWORD dwHashIndex;
if(m_HashTable != NULL)
{
if((m_ItemCount + 1) >= m_HashTableSize)
return false;
if(bCutExtension)
szStringEnd = GetFileExtension(szString);
else
szStringEnd = szString + strlen(szString);
dwHashIndex = HashToIndex(CalcHashValue_String(szString, szStringEnd));
while((szExistingString = (const char *)m_HashTable[dwHashIndex]) != NULL)
{
if(CompareObject_String(szExistingString, szString, szStringEnd))
return false;
dwHashIndex = HashToIndex(dwHashIndex + 1);
}
m_HashTable[dwHashIndex] = (void *)szString;
m_ItemCount++;
return true;
}
return false;
}
void * ItemAt(size_t nIndex)
{
assert(nIndex < m_HashTableSize);
return m_HashTable[nIndex];
}
size_t HashTableSize()
{
return m_HashTableSize;
}
size_t ItemCount()
{
return m_ItemCount;
}
bool IsInitialized()
{
return (m_HashTable && m_HashTableSize);
}
void Free()
{
PfnCalcHashValue = NULL;
CASC_FREE(m_HashTable);
m_HashTableSize = 0;
}
protected:
DWORD HashToIndex(DWORD HashValue)
{
return HashValue & (m_HashTableSize - 1);
}
bool CompareObject_Key(void * pvObject, void * pvKey)
{
LPBYTE pbObjectKey = (LPBYTE)pvObject + m_KeyOffset;
return (memcmp(pbObjectKey, pvKey, m_KeyLength) == 0);
}
bool CompareObject_String(const char * szExistingString, const char * szString, const char * szStringEnd)
{
while(szString < szStringEnd)
{
if(AsciiToUpperTable_BkSlash[*szExistingString] != AsciiToUpperTable_BkSlash[*szString])
return false;
szExistingString++;
szString++;
}
return true;
}
size_t GetNearestPowerOfTwo(size_t MaxItems)
{
size_t PowerOfTwo = MIN_HASH_TABLE_SIZE;
while(PowerOfTwo < MaxItems)
{
if((PowerOfTwo << 1) < PowerOfTwo)
{
assert(false);
return 0;
}
PowerOfTwo <<= 1;
}
return PowerOfTwo;
}
PFNHASHFUNC PfnCalcHashValue;
void ** m_HashTable; size_t m_HashTableSize; size_t m_ItemCount; size_t m_KeyOffset; size_t m_KeyLength; bool m_bKeyIsHash; };
#define CASC_KEY_LENGTH 0x10
#define CASC_KEY_TABLE_SIZE 0x100
#define CASC_KEY_TABLE_MASK (CASC_KEY_TABLE_SIZE - 1)
class CASC_KEY_MAP
{
public:
CASC_KEY_MAP();
~CASC_KEY_MAP();
LPBYTE FindKey(ULONGLONG KeyName);
bool AddKey(ULONGLONG KeyName, LPBYTE Key);
protected:
void * HashTable[CASC_KEY_TABLE_SIZE];
};
#endif