amxmodx/dlls/ns/Hash.h

165 lines
4.3 KiB
C
Raw Permalink Normal View History

#ifndef _HASH_H_
#define _HASH_H_
#include "CVector.h"
// Just a very simple hash map, no iteration or anything of the like (not needed)
inline int HashFunction(const String& name)
{
static const int kHashNumTable[128] =
{
0x1148FC3E, 0x0577C975, 0x3BED3AED, 0x62FBBD5F, 0x07DE2DA0, 0x6555C5E5, 0x24DB841A, 0x2AF3F568,
0x01EA1B65, 0x46F7D976, 0x18172B99, 0x394B2A58, 0x1ED39AA8, 0x1214E706, 0x5DD47295, 0x53574932,
0x2CE25D5C, 0x7A2E5BB4, 0x0F2F0153, 0x33888669, 0x729AC55F, 0x2A7BCA9E, 0x36C60816, 0x40F9A7E3,
0x2A37DF30, 0x3D81BB17, 0x6450B311, 0x75FA2DC9, 0x2A2678A5, 0x4C5E3675, 0x743F4486, 0x3B6F74E3,
0x51D5FFEA, 0x302C7F74, 0x1E6B3243, 0x59B42D8A, 0x15824559, 0x4346B65D, 0x04A822F2, 0x176C60BF,
0x0A3E8FD3, 0x1CBF4E8B, 0x50B78B17, 0x29122A7B, 0x2ED43591, 0x2E8BFDAC, 0x7C6973AE, 0x5BB692EE,
0x28BA5960, 0x0B987501, 0x0F3F1957, 0x1B551EBF, 0x36143F9F, 0x4605216D, 0x5C4EC6A2, 0x604C1ECF,
0x0386DC84, 0x409F79B4, 0x56464C99, 0x2DAD5529, 0x0CFDB029, 0x4A85911F, 0x691CCA0D, 0x5ED3B013,
0x7AB21093, 0x0787FC50, 0x3887DD9D, 0x103455ED, 0x4ACEB2AD, 0x3D30008F, 0x27A0B6AC, 0x550D4280,
0x59EF4F1B, 0x785841C3, 0x7E1F6CFC, 0x08C384AC, 0x26E43F70, 0x7A88E0AA, 0x647A179A, 0x4F9E98D0,
0x062155AB, 0x73B930F1, 0x6AF3B790, 0x3C35954B, 0x39BE525E, 0x47427E32, 0x1C81B41A, 0x3D452EE2,
0x07E1F7E6, 0x72C800B3, 0x6AF2840C, 0x14DFA80F, 0x3D4D91D3, 0x540F4E19, 0x73B35822, 0x37FFA266,
0x5B974A69, 0x2C3B35BF, 0x4833F853, 0x2665FD16, 0x696B364F, 0x6FD4AEFF, 0x7B733F96, 0x435A856A,
0x682CF0C3, 0x7992AC92, 0x4C1E0A16, 0x0F113033, 0x741B8D3C, 0x309821B1, 0x5EAFC903, 0x7A3CE2E8,
0x245152A2, 0x49A38093, 0x36727833, 0x5E0FA501, 0x10E5FEC6, 0x52F42C4D, 0x1B54D3E3, 0x18C7F6AC,
0x45BC2D01, 0x064757EF, 0x2DA79EBC, 0x0309BED4, 0x5A56A608, 0x215AF6DE, 0x3B09613A, 0x35EDF071
};
size_t size = name.size();
if (size == 0)
{
return 0;
}
int hasha = kHashNumTable[(*(name.c_str() + (size - 1))) & 0x7F];
int hashb = kHashNumTable[size % 128];
unsigned char c = 0;
for (size_t i = 0; i < size; i++)
{
c = (*(name.c_str() + (size - 1))) & 0x7F;
hasha = (hasha + hashb) ^ kHashNumTable[c];
hashb = hasha + hashb + c + (hasha << 8) + (hashb & 0xFF);
}
return hasha;
}
/**
* @param K Key type.
* @param D Data type.
* @param F Hash function.
* @param B Bucket count.
*/
template <typename K = String, typename D = String, int (*F)(const K&) = HashFunction, int B = 1024>
class Hash
{
protected:
CVector<int> m_HashBuckets[B];
CVector<K> m_KeyBuckets[B];
CVector<D> m_DataBuckets[B];
inline int GetBucket(int hash)
{
return (*reinterpret_cast<unsigned int*>(&hash)) % B;
};
public:
// prints bucket distribution
inline void printbuckets() const
{
for (int i = 0; i < B; i++)
{
if (i % 32 == 0 && i != 0)
{
printf("\n");
}
printf("%d ", m_HashBuckets[i].size());
}
printf("\n");
}
inline void insert(const K& key, const D& value)
{
D* ptr;
if ((ptr = this->find(key)) != NULL)
{
*ptr = value;
return;
}
int hash = F(key);
int bucketnum = GetBucket(hash);
m_HashBuckets[bucketnum].push_back(hash);
m_KeyBuckets[bucketnum].push_back(key);
m_DataBuckets[bucketnum].push_back(value);
return;
}
inline D& lookup_or_add(const K& key)
{
D* ptr;
if ((ptr = this->find(key)) != NULL)
{
return *ptr;
}
int hash = F(key);
int bucketnum = GetBucket(hash);
m_HashBuckets[bucketnum].push_back(hash);
m_KeyBuckets[bucketnum].push_back(key);
m_DataBuckets[bucketnum].push_back(D());
return m_DataBuckets[bucketnum].at(m_DataBuckets[bucketnum].size() - 1);
}
inline bool exists(const K& key)
{
return this->find(key) != NULL;
}
inline D* find(const K& key)
{
int hash = F(key);
int bucketnum = GetBucket(hash);
// TODO: Possibly make this binary search?
// insertion would be annoying, don't think it is worth it
CVector<int>* hashbucket = &m_HashBuckets[bucketnum];
CVector<K>* keybucket = &m_KeyBuckets[bucketnum];
size_t bucketsize = hashbucket->size();
for (size_t i = 0; i < bucketsize; i++)
{
if (hashbucket->at(i) == hash)
{
if (key.compare(keybucket->at(i).c_str()) == 0)
{
return &(m_DataBuckets[bucketnum].at(i));
}
}
}
return NULL;
};
};
#endif