Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

553 lines
18 KiB

#ifndef _HASH_HPP_
#define _HASH_HPP_
// Ruler
// 1 2 3 4 5 6 7 8
//345678901234567890123456789012345678901234567890123456789012345678901234567890
/********************************************************************/
/* */
/* The standard layout. */
/* */
/* The standard layout for 'hpp' files for this code is as */
/* follows: */
/* */
/* 1. Include files. */
/* 2. Constants exported from the class. */
/* 3. Data structures exported from the class. */
/* 4. Forward references to other data structures. */
/* 5. Class specifications (including inline functions). */
/* 6. Additional large inline functions. */
/* */
/* Any portion that is not required is simply omitted. */
/* */
/********************************************************************/
#include "Global.hpp"
/********************************************************************/
/* */
/* Include files for inherited classes. */
/* */
/* The include files for inherited classes are required in the */
/* specification of this class. */
/* */
/********************************************************************/
#include "Common.hpp"
#include "Lock.hpp"
#include "Stack.hpp"
#include "Vector.hpp"
/********************************************************************/
/* */
/* Macros exported from this class. */
/* */
/* This class has three template parameters so to make it more */
/* readable a macro is specified here to simplify the code. */
/* */
/********************************************************************/
#define HASH_TEMPLATE class KEY,class TYPE,class LOCK
/********************************************************************/
/* */
/* Constants exported from the class. */
/* */
/* The stack constants specify the initial size of the map. */
/* */
/********************************************************************/
CONST SBIT32 HashSize = 1024;
CONST SBIT32 MinHashFree = (100/25);
CONST SBIT32 ValueSize = 256;
/********************************************************************/
/* */
/* Hash table. */
/* */
/* This class provides general purpose hash table functions to */
/* safely map sparse integer keys into some pointer or value. */
/* */
/********************************************************************/
template <HASH_TEMPLATE=NO_LOCK> class HASH : public LOCK
{
//
// Private structures.
//
typedef struct
{
KEY Key;
SBIT32 Next;
TYPE Value;
}
VALUE;
//
// Private data.
//
SBIT32 MaxHash;
SBIT32 MaxValues;
SBIT32 ValuesUsed;
SBIT32 Active;
VECTOR<SBIT32> Hash;
SBIT32 HashMask;
SBIT32 HashShift;
STACK<SBIT32> FreeStack;
VECTOR<VALUE> Values;
public:
//
// Public functions.
//
HASH
(
SBIT32 NewMaxHash = HashSize,
SBIT32 NewMaxValues = ValueSize,
SBIT32 Alignment = 1
);
VOID AddToHash( CONST KEY & Key, CONST TYPE & Value );
VIRTUAL SBIT32 ComputeHashKey( CONST KEY & Key );
BOOLEAN FindInHash( CONST KEY & Key, TYPE *Value );
VIRTUAL BOOLEAN MatchingKeys( CONST KEY & Key1, CONST KEY & Key2 );
VOID RemoveFromHash( CONST KEY & Key );
~HASH( VOID );
private:
//
// Private functions.
//
BOOLEAN FindHashKeyValue( CONST KEY & Key, SBIT32 **HashIndex );
VOID Resize( VOID );
//
// Disabled operations.
//
HASH( CONST HASH & Copy );
VOID operator=( CONST HASH & Copy );
};
/********************************************************************/
/* */
/* Class constructor. */
/* */
/* Create a new hash and prepare it for use. This call is */
/* not thread safe and should only be made in a single thread */
/* environment. */
/* */
/********************************************************************/
template <HASH_TEMPLATE> HASH<KEY,TYPE,LOCK>::HASH
(
SBIT32 NewMaxHash,
SBIT32 NewMaxValues,
SBIT32 Alignment
) :
//
// Call the constructors for the contained classes.
//
Hash( (COMMON::ForceToPowerOfTwo( NewMaxHash )),1,CacheLineSize ),
FreeStack( (NewMaxValues / 2) ),
Values( NewMaxValues,Alignment,CacheLineSize )
{
if
(
(NewMaxHash > 0)
&&
(
COMMON::ConvertDivideToShift
(
(COMMON::ForceToPowerOfTwo( NewMaxHash )),
& HashMask
)
)
&&
(NewMaxValues > 0)
)
{
REGISTER SBIT32 Count;
//
// Setup the hash table size information.
//
MaxHash = (COMMON::ForceToPowerOfTwo( NewMaxHash ));
MaxValues = NewMaxValues;
ValuesUsed = 0;
//
// Zero the control values compute the
// hash table shift values.
//
Active = 0;
HashShift = (32-HashMask);
HashMask = ((1 << HashMask)-1);
for( Count=0;Count < MaxHash;Count ++ )
{ Hash[ Count ] = EndOfList; }
}
else
{ Failure( "Max sizes in constructor for HASH" ); }
}
/********************************************************************/
/* */
/* Add to the hash table. */
/* */
/* We add an key to the hash table if it does not already exist. */
/* Then we add (or update) the current value. If the is not */
/* space we expand the size of the 'Values' table. */
/* */
/********************************************************************/
template <HASH_TEMPLATE> VOID HASH<KEY,TYPE,LOCK>::AddToHash
(
CONST KEY & Key,
CONST TYPE & Value
)
{
AUTO SBIT32 *HashIndex;
//
// Claim an exclusive lock (if enabled).
//
ClaimExclusiveLock();
if ( ! FindHashKeyValue( Key, & HashIndex ) )
{
AUTO SBIT32 NewIndex;
REGISTER VALUE *NewValue;
//
// Extract a free element from the stack.
// If the stack is empty then allocated one
// from the array.
//
if ( ! FreeStack.PopStack( & NewIndex ) )
{
//
// If the array is full then resize it.
// We need to be careful here as a resize
// can change the address of the 'Values'
// array.
//
if ( (NewIndex = ValuesUsed ++) >= MaxValues )
{ Values.Resize( (MaxValues *= ExpandStore) ); }
}
//
// Add the new element into the hash table
// and link it into any overflow chains.
//
NewValue = & Values[ NewIndex ];
Active ++;
//
// Link in the new element.
//
NewValue -> Key = Key;
NewValue -> Next = (*HashIndex);
(*HashIndex) = NewIndex;
NewValue -> Value = Value;
}
else
{ Values[ (*HashIndex) ].Value = Value; }
//
// If the hash table has grown too big we
// resize it.
//
if ( (Active + (MaxHash / MinHashFree)) > MaxHash )
{ Resize(); }
//
// Release any lock we got earlier.
//
ReleaseExclusiveLock();
}
/********************************************************************/
/* */
/* Compute the hash key. . */
/* */
/* Compute a hash value from the supplied key. */
/* */
/********************************************************************/
template <HASH_TEMPLATE> SBIT32 HASH<KEY,TYPE,LOCK>::ComputeHashKey
(
CONST KEY & Key
)
{
//
// When the key is larger than an integer the we need
// to do a bit more work.
//
if ( sizeof(KEY) > sizeof(SBIT32) )
{
REGISTER SBIT32 HighWord = ((SBIT32) (Key >> 32));
REGISTER SBIT32 LowWord = ((SBIT32) Key);
//
// We compute the hash key using both the high
// and low order words.
//
return
(
(HighWord * 2964557531)
+
(LowWord * 2964557531)
+
(HighWord + LowWord)
);
}
else
{ return ((((SBIT32) Key) * 2964557531) + ((SBIT32) Key)); }
}
/********************************************************************/
/* */
/* Find a key in the hash table. */
/* */
/* Find a key in the hash table and return the associated value. */
/* */
/********************************************************************/
template <HASH_TEMPLATE> BOOLEAN HASH<KEY,TYPE,LOCK>::FindInHash
(
CONST KEY & Key,
TYPE *Value
)
{
AUTO SBIT32 *Index;
REGISTER BOOLEAN Result;
//
// Claim an shared lock (if enabled).
//
ClaimSharedLock();
//
// Find the key in the hash table.
//
if ( (Result = FindHashKeyValue( Key,& Index )) )
{ (*Value) = Values[ (*Index) ].Value; }
//
// Release any lock we got earlier.
//
ReleaseSharedLock();
return Result;
}
/********************************************************************/
/* */
/* Find the hash key value. */
/* */
/* Find the value associated with the supplied hash key. */
/* */
/********************************************************************/
template <HASH_TEMPLATE> BOOLEAN HASH<KEY,TYPE,LOCK>::FindHashKeyValue
(
CONST KEY & Key,
SBIT32 **Index
)
{
REGISTER SBIT32 *Current;
REGISTER VALUE *List;
//
// Find the bucket in the hash table that should
// contain this key.
//
(*Index) = & Hash[ ((ComputeHashKey( Key ) >> HashShift) & HashMask) ];
//
// Walk the overflow chain and look for the key.
//
for ( Current = (*Index);(*Current) != EndOfList;Current = & List -> Next )
{
List = & Values[ (*Current) ];
//
// If the keys match we are out of here.
//
if ( MatchingKeys( Key,List -> Key ) )
{
(*Index) = Current;
return True;
}
}
return False;
}
/********************************************************************/
/* */
/* Compare two hask keys. . */
/* */
/* Compare two hash keys to see if they match. */
/* */
/********************************************************************/
template <HASH_TEMPLATE> BOOLEAN HASH<KEY,TYPE,LOCK>::MatchingKeys
(
CONST KEY & Key1,
CONST KEY & Key2
)
{ return (Key1 == Key2); }
/********************************************************************/
/* */
/* Remove a key from the hash table. */
/* */
/* The supplied key is removed from the hash table (if it exists) */
/* and the associated value is deleted. */
/* */
/********************************************************************/
template <HASH_TEMPLATE> VOID HASH<KEY,TYPE,LOCK>::RemoveFromHash
(
CONST KEY & Key
)
{
AUTO SBIT32 *Index;
//
// Claim an exclusive lock (if enabled).
//
ClaimExclusiveLock();
//
// Find the key in the hash table.. If it
// exists then delete it.
//
if ( FindHashKeyValue( Key,& Index ) )
{
Active --;
FreeStack.PushStack( (*Index) );
(*Index) = Values[ (*Index) ].Next;
}
//
// Release any lock we got earlier.
//
ReleaseExclusiveLock();
}
/********************************************************************/
/* */
/* Resize the hash table. */
/* */
/* The hash table is resized if it becomes more than 75% full */
/* and all the keys are rehashed. */
/* */
/********************************************************************/
template <HASH_TEMPLATE> VOID HASH<KEY,TYPE,LOCK>::Resize( VOID )
{
REGISTER SBIT32 Count;
REGISTER SBIT32 List = EndOfList;
//
// Walk the hash table and link all the active
// values into a single linked list.
//
for ( Count=0;Count < MaxHash;Count ++ )
{
REGISTER SBIT32 Start = Hash[ Count ];
//
// We know that some of the hash buckets may
// be empty so we skip these.
//
if ( Start != EndOfList )
{
REGISTER SBIT32 Last = Start;
//
// Walk along the overflow chain until
// we find the end.
//
while ( Values[ Last ].Next != EndOfList )
{ Last = Values[ Last ].Next; }
//
// Add the list on the front of the new
// global list.
//
Values[ Last ].Next = List;
List = Start;
}
}
//
// Resize the hash table.
//
Hash.Resize( (MaxHash *= ExpandStore) );
if ( COMMON::ConvertDivideToShift( MaxHash,& HashMask ) )
{
REGISTER SBIT32 Count;
//
// Update the shift values.
//
HashShift = (32-HashMask);
HashMask = ((1 << HashMask)-1);
//
// Zero the resized table.
//
for ( Count=0;Count < MaxHash;Count ++ )
{ Hash[ Count ] = EndOfList; }
}
else
{ Failure( "Hash size in Resize" ); }
//
// Rehash all the existing values.
//
while ( List != EndOfList )
{
AUTO SBIT32 *Index;
REGISTER VALUE *Current = & Values[ List ];
REGISTER SBIT32 Next = Current -> Next;
if ( ! FindHashKeyValue( Current -> Key,& Index ) )
{
Current -> Next = (*Index);
(*Index) = List;
List = Next;
}
else
{ Failure( "Duplicate hash key in Risize" ); }
}
}
/********************************************************************/
/* */
/* Class destructor. */
/* */
/* Destory the hash. This call is not thread safe and should */
/* only be made in a single thread environment. */
/* */
/********************************************************************/
template <HASH_TEMPLATE> HASH<KEY,TYPE,LOCK>::~HASH( VOID )
{ /* void */ }
#endif