#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(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; } }