📄 hashtable.cpp
字号:
// need to mess with the cleanup stack
/* make sure newtab is cleared */
for (i=0; i<newsize; ++i) newtab[i] = (hitem *)0;
this->iTable = newtab;
this->inMask = newmask;
/* Walk through old iTable putting entries in new iTable */
for (i=newsize>>1; i--;)
{
hitem *curr, *that, **newplace;
for (curr = oldtab[i]; curr;)
{
that = curr;
curr = curr->next;
newplace = &newtab[(that->hval & newmask)];
that->next = *newplace;
*newplace = that;
}
}
/* position the hash iTable on some existing item */
First();
/* free the old array */
delete [] oldtab;
}
/*
* NextBucket - Move position to the first item in the next bucket.
* Return TRUE if we did not wrap around to the beginning of the iTable
*/
template<class KeyType, class ValueType>
TInt CHashTable<KeyType, ValueType>::NextBucket()
{
TUint32 oldapos = this->iAPos;
TUint32 end = (TUint32)1<<(this->inLogSize);
TUint32 i;
/* see if the element can be found without wrapping around */
for (i=oldapos+1; i<end; ++i)
{
if (this->iTable[i&this->inMask])
{
this->iAPos = i;
this->iPos = this->iTable[i];
return TRUE;
}
}
/* must have to wrap around to find the last element */
for (i=0; i<=oldapos; ++i)
{
if (this->iTable[i])
{
this->iAPos = i;
this->iPos = this->iTable[i];
return FALSE;
}
}
return FALSE;
}
/* Count returns the current number of items in the hash iTable */
template<class KeyType, class ValueType>
TUint32 CHashTable<KeyType, ValueType>::Count() const
{
return this->inCount;
}
/* Key returns the current key */
template<class KeyType, class ValueType>
KeyType* CHashTable<KeyType, ValueType>::Key() const
{
return this->iPos->key;
}
/* Value returns the current stuff associated with the key */
template<class KeyType, class ValueType>
ValueType CHashTable<KeyType, ValueType>::Value() const
{
return this->iPos->stuff;
}
/* Value returns the current stuff associated with the key */
template<class KeyType, class ValueType>
ValueType& CHashTable<KeyType, ValueType>::Value()
{
return this->iPos->stuff;
}
/* sanity check -- make sure iPos, iAPos, and inCount make sense */
template<class KeyType, class ValueType>
void CHashTable<KeyType, ValueType>::Sanity() const
{
TUint32 i, end, counter;
hitem *h;
/* test that iAPos makes sense */
end = (TUint32)1<<(this->inLogSize);
if (end < this->iAPos) {
_LIT(KFormatHsErr1, "error: end %ld iAPos %ld");
TBuf<64> buffer;
buffer.Format(KFormatHsErr1, end, this->iAPos);
User::Panic(KFormatHsErr1, KErrCorrupt);
}
/* test that iPos is in bucket iAPos */
if (this->iPos)
{
for (h=this->iTable[this->iAPos]; h && h != this->iPos; h = h->next)
;
if (h != this->iPos) {
_LIT(KFormatHsErr2, "error:iPos not in iAPos, iAPos is %ld");
TBuf<64> buffer;
buffer.Format(KFormatHsErr2, this->iAPos);
User::Panic(KFormatHsErr2, KErrCorrupt);
}
}
/* test that this->inCount is the number of elements in the iTable */
counter=0;
for (counter=0, i=0; i<end; ++i)
for (h=this->iTable[i]; h; h=h->next)
++counter;
if (counter != this->inCount) {
_LIT(KFormatHsErr3, "error: counter %ld this->inCount %ld");
TBuf<64> buffer;
buffer.Format(KFormatHsErr3, counter, this->inCount);
User::Panic(KFormatHsErr3, KErrCorrupt);
}
}
template<class KeyType, class ValueType>
void CHashTable<KeyType, ValueType>::Stats() const
{
TUint32 i,j;
double total = 0.0;
hitem *h;
hitem *walk, *walk2, *stat = (hitem *)0;
/* in stat, hval the number of buckets */
for (i=0; i<=this->inMask; ++i)
{
for (h=this->iTable[i], j=0; h; ++j, h=h->next)
;
for (walk=stat; walk; walk=walk->next)
;
if (walk)
{
++(walk->hval);
}
else
{
walk = new (ELeave) hitem;
walk->hval = 1;
if (!stat) {walk->next=stat; stat=walk;}
else
{
for (walk2=stat;
walk2->next;
walk2=walk2->next)
;
walk->next = walk2->next;
walk2->next = walk;
}
}
}
/* print statistics */
/* printf("\n"); */
for (walk=stat; walk; walk=walk->next)
{
/* printf("items %ld: %ld buckets\n", sizeof(KeyType), walk->hval); */
}
/* printf("\nbuckets: %ld items: %ld existing: %g\n\n",
((TUint32)1<<this->inLogSize), this->inCount, total); */
/* clean up */
while (stat)
{
walk = stat->next;
delete stat;
stat = walk;
}
}
/*
--------------------------------------------------------------------
mix -- mix 3 32-bit values reversibly.
For every delta with one or two bit set, and the deltas of all three
high bits or all three low bits, whether the original value of a,b,c
is almost all zero or is uniformly distributed,
* If mix() is run forward or backward, at least 32 bits in a,b,c
have at least 1/4 probability of changing.
* If mix() is run forward, every bit of c will change between 1/3 and
2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.)
mix() was built out of 36 single-cycle latency instructions in a
structure that could supported 2x parallelism, like so:
a -= b;
a -= c; x = (c>>13);
b -= c; a ^= x;
b -= a; x = (a<<8);
c -= a; b ^= x;
c -= b; x = (b>>13);
...
Unfortunately, superscalar Pentiums and Sparcs can'this take advantage
of that parallelism. They've also turned some of those single-cycle
latency instructions into multi-cycle latency instructions. Still,
this is the fastest good hash I could find. There were about 2^^68
to choose from. I only looked at a billion or so.
--------------------------------------------------------------------
*/
#define mix(a,b,c) \
{ \
a -= b; a -= c; a ^= (c>>13); \
b -= c; b -= a; b ^= (a<<8); \
c -= a; c -= b; c ^= (b>>13); \
a -= b; a -= c; a ^= (c>>12); \
b -= c; b -= a; b ^= (a<<16); \
c -= a; c -= b; c ^= (b>>5); \
a -= b; a -= c; a ^= (c>>3); \
b -= c; b -= a; b ^= (a<<10); \
c -= a; c -= b; c ^= (b>>15); \
}
/*
--------------------------------------------------------------------
Lookup() -- hash a variable-length key into a 32-bit value
k : the key (the unaligned variable-length array of bytes)
len : the length of the key, counting by bytes
level : can be any 4-byte value
Returns a 32-bit value. Every bit of the key affects every bit of
the return value. Every 1-bit and 2-bit delta achieves avalanche.
About 6len+35 instructions.
The best hash iTable sizes are powers of 2. There is no need to do
mod a prime (mod is sooo slow!). If you need less than 32 bits,
use a bitmask. For example, if you need only 10 bits, do
h = (h & hashmask(10));
In which case, the hash iTable should have hashsize(10) elements.
If you are hashing n strings (TUint8 **)k, do it like this:
for (i=0, h=0; i<n; ++i) h = Lookup( k[i], len[i], h);
By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use this
code any way you wish, private, educational, or commercial.
See http://burtleburtle.net/bob/hash/evahash.html
Use for hash iTable Lookup, or anything where one collision in 2^32 is
acceptable. Do NOT use for cryptographic purposes.
--------------------------------------------------------------------
*/
template<class KeyType, class ValueType>
TUint32 CHashTable<KeyType, ValueType>::Lookup(
KeyType *key /* the key */,
TUint32 level /* the previous hash, or an arbitrary value */)
{
TUint32 a,b,c,len;
TUint8* k = (TUint8*) key;
/* Set up the internal state */
len = sizeof(KeyType);
a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
c = level; /* the previous hash value */
/*---------------------------------------- handle most of the key */
while (len >= 12)
{
a += (k[0] +((TUint32)k[1]<<8) +((TUint32)k[2]<<16) +((TUint32)k[3]<<24));
b += (k[4] +((TUint32)k[5]<<8) +((TUint32)k[6]<<16) +((TUint32)k[7]<<24));
c += (k[8] +((TUint32)k[9]<<8) +((TUint32)k[10]<<16)+((TUint32)k[11]<<24));
mix(a,b,c);
k += 12; len -= 12;
}
/*------------------------------------- handle the last 11 bytes */
c += sizeof(KeyType);
switch(len) /* all the case statements fall through */
{
case 11: c+=((TUint32)k[10]<<24);
case 10: c+=((TUint32)k[9]<<16);
case 9 : c+=((TUint32)k[8]<<8);
/* the first byte of c is reserved for the length */
case 8 : b+=((TUint32)k[7]<<24);
case 7 : b+=((TUint32)k[6]<<16);
case 6 : b+=((TUint32)k[5]<<8);
case 5 : b+=k[4];
case 4 : a+=((TUint32)k[3]<<24);
case 3 : a+=((TUint32)k[2]<<16);
case 2 : a+=((TUint32)k[1]<<8);
case 1 : a+=k[0];
/* case 0: nothing left to add */
}
mix(a,b,c);
/*-------------------------------------------- report the result */
return c;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -