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.
 
 
 
 
 
 

374 lines
10 KiB

#include "stdinc.h"
#include "lhport.h"
#include "positionindependenthashtableaccessor.h"
typedef CPositionIndependentHashTable::CHashTable CHashTable;
typedef CPositionIndependentHashTable::CHashTableBucket CHashTableBucket;
ULONG
CPositionIndependentHashTableAccessor::PointerToOffset(const BYTE * p)
{
return m_PositionIndependentTable->PointerToOffset(p);
}
CPositionIndependentHashTableAccessor::CPositionIndependentHashTableAccessor(
CPositionIndependentHashTable * PositionIndependentTable,
ULONG HashTableIndex
)
: m_PositionIndependentTable(PositionIndependentTable),
m_HashTableIndex(HashTableIndex),
m_Key(NULL),
m_PointerToHashTables(NULL),
m_PointerToBucket(NULL),
m_KeyHash(0),
m_KeyIndex(~0UL),
m_KeyHashIsValid(FALSE)
{ }
void
CPositionIndependentHashTableAccessor::GetPointerToHashTable(CHashTable ** Result)
{
return this->GetPointerToHashTable(m_HashTableIndex, Result);
}
CHashTable *
CPositionIndependentHashTableAccessor::GetPointerToHashTable()
{
return this->GetPointerToHashTable(m_HashTableIndex);
}
void
CPositionIndependentHashTableAccessor::GetPointerToHashTable(ULONG HashTableIndex, CHashTable ** Result)
{
*Result = GetPointerToHashTable(HashTableIndex);
}
CHashTable *
CPositionIndependentHashTableAccessor::GetPointerToHashTable(ULONG HashTableIndex)
{
if (m_PointerToHashTables == NULL)
{
OffsetToPointer(m_PositionIndependentTable->m_OffsetToHashTables, &m_PointerToHashTables);
}
return &m_PointerToHashTables[HashTableIndex];
}
BOOL
CPositionIndependentHashTableAccessor::AreKeysEqual(const BYTE * Key1, const BYTE * Key2)
{
return (*GetPointerToHashTable()->m_Equal.pfn)(Key1, Key2);
}
void
CPositionIndependentHashTableAccessor::GetKeyHashNoCache(const BYTE * Key, ULONG * KeyHash)
{
*KeyHash = (*GetPointerToHashTable()->m_Hash.pfn)(Key);
}
void
CPositionIndependentHashTableAccessor::GetKeyHash(const BYTE * Key, ULONG * KeyHash)
{
if (Key == m_Key && m_KeyHashIsValid)
{
*KeyHash = m_KeyHash;
return;
}
GetKeyHashNoCache(Key, KeyHash);
m_PointerToBucket = NULL;
m_KeyHash = *KeyHash;
m_Key = Key;
m_KeyHashIsValid = TRUE;
}
BOOL
CPositionIndependentHashTableAccessor::IsKeyPresent(const BYTE * Key)
{
BOOL Result = FALSE;
CHashTable * PointerToHashTable = 0;
CHashTableBucket * PointerToBucket = 0;
ULONG Hash = 0;
ULONG BucketIndex = 0;
ULONG AllocatedElementsInBucket = 0;
CHashTableElement * PointerToElements = 0;
if (IsEmpty())
{
Result = FALSE;
goto Exit;
}
GetPointerToHashTable(&PointerToHashTable);
GetHashTableBucketForKey(Key, &PointerToBucket);
GetKeyHash(Key, &Hash);
BucketIndex = (m_KeyHash % PointerToHashTable->m_NumberOfBuckets);
OffsetToPointer(PointerToHashTable->m_OffsetToBuckets + BucketIndex * sizeof(*PointerToBucket), &PointerToBucket);
AllocatedElementsInBucket = PointerToBucket->m_AllocatedElementsInBucket;
if (AllocatedElementsInBucket == 0)
{
Result = FALSE;
goto Exit;
}
OffsetToPointer(PointerToBucket->m_OffsetToElements, &PointerToElements);
for (ULONG IndexIntoBucket = 0 ; IndexIntoBucket != AllocatedElementsInBucket ; ++IndexIntoBucket )
{
CHashTableElement * Element = &PointerToElements[IndexIntoBucket];
if (Element->m_PseudoKey == Hash)
{
PBYTE PointerToKey;
OffsetToPointer(Element->m_OffsetToKey, &PointerToKey);
if ((*PointerToHashTable->m_Equal.pfn)(Key, PointerToKey))
{
Result = TRUE;
goto Exit;
}
}
}
Exit:
return Result;
}
void
CPositionIndependentHashTableAccessor::GetHashTableBucketForKey(
const BYTE * Key,
CHashTableBucket ** Result
)
{
ULONG Hash = 0;
CHashTable * PointerToHashTable = 0;
CHashTableBucket * PointerToBucket = 0;
ULONG BucketIndex = 0;
ULONG NumberOfElementsInTable = 0;
*Result = NULL;
if (Key == m_Key && m_KeyHashIsValid && m_PointerToBucket != NULL)
{
*Result = m_PointerToBucket;
goto Exit;
}
if (IsEmpty())
{
goto Exit;
}
GetKeyHash(Key, &Hash);
GetPointerToHashTable(&PointerToHashTable);
NumberOfElementsInTable = PointerToHashTable->m_NumberOfElementsInTable;
if (NumberOfElementsInTable == 0)
{
goto Exit;
}
BucketIndex = (Hash % PointerToHashTable->m_NumberOfBuckets);
OffsetToPointer(PointerToHashTable->m_OffsetToBuckets + BucketIndex * sizeof(*PointerToBucket), &PointerToBucket);
*Result = PointerToBucket;
m_PointerToBucket = PointerToBucket;
Exit:
;
}
BOOL CPositionIndependentHashTableAccessor::IsEmpty()
{
if (m_PositionIndependentTable->m_NumberOfHashTables == 0)
return TRUE;
if (GetPointerToHashTable()->m_NumberOfElementsInTable == 0)
return TRUE;
return FALSE;
}
void
CPositionIndependentHashTableAccessor::GetBounds(
const BYTE * Bounds[2]
)
{
return m_PositionIndependentTable->GetBounds(Bounds);
}
void
CPositionIndependentHashTableAccessor::IsInBlob(
const BYTE * Pointer,
ULONG Size,
BOOL * IsInBlob
)
{
return m_PositionIndependentTable->IsInBlob(Pointer, Size, IsInBlob);
}
void
CPositionIndependentHashTableAccessor::SetAt(
const BYTE * Key,
ULONG KeySize,
const BYTE * Value,
ULONG ValueSize
)
{
FN_PROLOG_VOID_THROW
CHashTableBucket * Result = 0;
ULONG Hash = 0;
CHashTable * PointerToHashTable = 0;
CHashTableBucket Bucket = { 0 };
CHashTableBucket * PointerToBucket = 0;
ULONG BucketIndex = 0;
ULONG NumberOfElementsInTable = 0;
ULONG NumberOfBuckets = 0;
ULONG KeyOffset = 0;
ULONG ValueOffset = 0;
BOOL KeyIsInBlob = 0;
BOOL ValueIsInBlob = 0;
BYTE * BasePointer = BasePointer = GetBasePointer();
GetKeyHash(Key, &Hash);
GetPointerToHashTable(&PointerToHashTable);
NumberOfElementsInTable = PointerToHashTable->m_NumberOfElementsInTable;
NumberOfBuckets = PointerToHashTable->m_NumberOfBuckets;
//
// Do this before we get buckets.
//
IsInBlob(Key, KeySize, &KeyIsInBlob);
IsInBlob(Value, ValueSize, &ValueIsInBlob);
if (KeyIsInBlob)
Key = BasePointer + KeyOffset;
if (ValueIsInBlob)
Value = BasePointer + ValueOffset;
if (NumberOfBuckets == 0)
{
GrowNumberOfBuckets(17);
NumberOfBuckets = PointerToHashTable->m_NumberOfBuckets;
if (KeyIsInBlob)
OffsetToPointer(KeyOffset, &Key);
if (ValueIsInBlob)
OffsetToPointer(ValueOffset, &Value);
}
BucketIndex = (Hash % NumberOfBuckets);
OffsetToPointer(PointerToHashTable->m_OffsetToBuckets + BucketIndex * sizeof(*PointerToBucket), &PointerToBucket);
Bucket = *PointerToBucket;
CHashTableElement * Elements;
OffsetToPointer(Bucket.m_OffsetToElements, &Elements);
ULONG FreeElementIndex = 0;
ULONG FoundElementIndex = 0;
BOOL DidFindFreeElement = FALSE;
BOOL DidFindElement = FALSE;
for (ULONG ElementIndex = 0 ; ElementIndex != Bucket.m_AllocatedElementsInBucket; ++ElementIndex)
{
if (Elements[ElementIndex].m_InUse)
{
if (Hash == Elements[ElementIndex].m_PseudoKey
&& AreKeysEqual(Key, BasePointer + Elements[ElementIndex].m_OffsetToKey))
{
FoundElementIndex = ElementIndex;
DidFindElement = TRUE;
}
}
else if (!DidFindFreeElement)
{
FreeElementIndex = ElementIndex;
DidFindFreeElement = TRUE;
}
if (DidFindFreeElement && DidFindElement)
break;
}
ULONG NeededBytes = 0;
ULONG NeededBlocks = 0;
ULONG NeededElementBytes = 0;
if (!DidFindElement && !DidFindFreeElement)
{
//
// REVIEW Should we double, or just add one?
//
NeededElementBytes = sizeof(CHashTableElement) * (Bucket.m_AllocatedElementsInBucket + 1);
NeededBytes += NeededElementBytes;
NeededBlocks += 1;
}
else
{
NeededElementBytes = 0;
}
ULONG NeededKeyBytes = 0;
if (KeySize <= sizeof(CHashTableElement().m_SmallKey)
|| KeyIsInBlob
|| DidFindElement
|| (DidFindFreeElement && Elements[FreeElementIndex].m_KeySize >= ValueSize)
)
{
NeededKeyBytes = 0;
}
else
{
NeededKeyBytes = KeySize;
NeededBytes += KeySize;
NeededBlocks += 1;
}
ULONG NeededValueBytes = 0;
if (ValueSize <= sizeof(CHashTableElement().m_SmallValue)
|| ValueIsInBlob
|| (DidFindElement && Elements[FoundElementIndex].m_ValueAllocatedSize >= ValueSize)
|| (DidFindFreeElement && Elements[FreeElementIndex].m_ValueAllocatedSize >= ValueSize)
)
{
NeededValueBytes = 0;
// NOTE: what about replacement with "equal" values?
}
else
{
NeededValueBytes = ValueSize;
NeededBytes += ValueSize;
NeededBlocks += 1;
}
Reserve(NeededBytes, NeededBlocks);
if (NeededElementBytes != 0)
{
ULONG NewElementsOffset;
Alloc(NeededElementBytes, &NewElementsOffset);
CopyMemory(BasePointer + NewElementsOffset, Elements, NeededElementBytes - sizeof(CHashTableElement));
Elements = reinterpret_cast<CHashTableElement*>(BasePointer + NewElementsOffset);
}
// undone right here
FN_EPILOG_THROW;
}
PBYTE
CPositionIndependentHashTableAccessor::GetBasePointer()
{
return m_PositionIndependentTable->GetBasePointer();
}
void
CPositionIndependentHashTableAccessor::Alloc(ULONG NumberOfBytes, ULONG * Offset)
{
PBYTE BaseBefore = GetBasePointer();
m_PositionIndependentTable->Alloc(NumberOfBytes, Offset);
if (GetBasePointer() != BaseBefore)
{
m_PointerToBucket = NULL;
m_PointerToHashTables = NULL;
m_PointerToBucket = NULL;
}
}