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

  1. #include "stdinc.h"
  2. #include "lhport.h"
  3. #include "positionindependenthashtableaccessor.h"
  4. typedef CPositionIndependentHashTable::CHashTable CHashTable;
  5. typedef CPositionIndependentHashTable::CHashTableBucket CHashTableBucket;
  6. ULONG
  7. CPositionIndependentHashTableAccessor::PointerToOffset(const BYTE * p)
  8. {
  9. return m_PositionIndependentTable->PointerToOffset(p);
  10. }
  11. CPositionIndependentHashTableAccessor::CPositionIndependentHashTableAccessor(
  12. CPositionIndependentHashTable * PositionIndependentTable,
  13. ULONG HashTableIndex
  14. )
  15. : m_PositionIndependentTable(PositionIndependentTable),
  16. m_HashTableIndex(HashTableIndex),
  17. m_Key(NULL),
  18. m_PointerToHashTables(NULL),
  19. m_PointerToBucket(NULL),
  20. m_KeyHash(0),
  21. m_KeyIndex(~0UL),
  22. m_KeyHashIsValid(FALSE)
  23. { }
  24. void
  25. CPositionIndependentHashTableAccessor::GetPointerToHashTable(CHashTable ** Result)
  26. {
  27. return this->GetPointerToHashTable(m_HashTableIndex, Result);
  28. }
  29. CHashTable *
  30. CPositionIndependentHashTableAccessor::GetPointerToHashTable()
  31. {
  32. return this->GetPointerToHashTable(m_HashTableIndex);
  33. }
  34. void
  35. CPositionIndependentHashTableAccessor::GetPointerToHashTable(ULONG HashTableIndex, CHashTable ** Result)
  36. {
  37. *Result = GetPointerToHashTable(HashTableIndex);
  38. }
  39. CHashTable *
  40. CPositionIndependentHashTableAccessor::GetPointerToHashTable(ULONG HashTableIndex)
  41. {
  42. if (m_PointerToHashTables == NULL)
  43. {
  44. OffsetToPointer(m_PositionIndependentTable->m_OffsetToHashTables, &m_PointerToHashTables);
  45. }
  46. return &m_PointerToHashTables[HashTableIndex];
  47. }
  48. BOOL
  49. CPositionIndependentHashTableAccessor::AreKeysEqual(const BYTE * Key1, const BYTE * Key2)
  50. {
  51. return (*GetPointerToHashTable()->m_Equal.pfn)(Key1, Key2);
  52. }
  53. void
  54. CPositionIndependentHashTableAccessor::GetKeyHashNoCache(const BYTE * Key, ULONG * KeyHash)
  55. {
  56. *KeyHash = (*GetPointerToHashTable()->m_Hash.pfn)(Key);
  57. }
  58. void
  59. CPositionIndependentHashTableAccessor::GetKeyHash(const BYTE * Key, ULONG * KeyHash)
  60. {
  61. if (Key == m_Key && m_KeyHashIsValid)
  62. {
  63. *KeyHash = m_KeyHash;
  64. return;
  65. }
  66. GetKeyHashNoCache(Key, KeyHash);
  67. m_PointerToBucket = NULL;
  68. m_KeyHash = *KeyHash;
  69. m_Key = Key;
  70. m_KeyHashIsValid = TRUE;
  71. }
  72. BOOL
  73. CPositionIndependentHashTableAccessor::IsKeyPresent(const BYTE * Key)
  74. {
  75. BOOL Result = FALSE;
  76. CHashTable * PointerToHashTable = 0;
  77. CHashTableBucket * PointerToBucket = 0;
  78. ULONG Hash = 0;
  79. ULONG BucketIndex = 0;
  80. ULONG AllocatedElementsInBucket = 0;
  81. CHashTableElement * PointerToElements = 0;
  82. if (IsEmpty())
  83. {
  84. Result = FALSE;
  85. goto Exit;
  86. }
  87. GetPointerToHashTable(&PointerToHashTable);
  88. GetHashTableBucketForKey(Key, &PointerToBucket);
  89. GetKeyHash(Key, &Hash);
  90. BucketIndex = (m_KeyHash % PointerToHashTable->m_NumberOfBuckets);
  91. OffsetToPointer(PointerToHashTable->m_OffsetToBuckets + BucketIndex * sizeof(*PointerToBucket), &PointerToBucket);
  92. AllocatedElementsInBucket = PointerToBucket->m_AllocatedElementsInBucket;
  93. if (AllocatedElementsInBucket == 0)
  94. {
  95. Result = FALSE;
  96. goto Exit;
  97. }
  98. OffsetToPointer(PointerToBucket->m_OffsetToElements, &PointerToElements);
  99. for (ULONG IndexIntoBucket = 0 ; IndexIntoBucket != AllocatedElementsInBucket ; ++IndexIntoBucket )
  100. {
  101. CHashTableElement * Element = &PointerToElements[IndexIntoBucket];
  102. if (Element->m_PseudoKey == Hash)
  103. {
  104. PBYTE PointerToKey;
  105. OffsetToPointer(Element->m_OffsetToKey, &PointerToKey);
  106. if ((*PointerToHashTable->m_Equal.pfn)(Key, PointerToKey))
  107. {
  108. Result = TRUE;
  109. goto Exit;
  110. }
  111. }
  112. }
  113. Exit:
  114. return Result;
  115. }
  116. void
  117. CPositionIndependentHashTableAccessor::GetHashTableBucketForKey(
  118. const BYTE * Key,
  119. CHashTableBucket ** Result
  120. )
  121. {
  122. ULONG Hash = 0;
  123. CHashTable * PointerToHashTable = 0;
  124. CHashTableBucket * PointerToBucket = 0;
  125. ULONG BucketIndex = 0;
  126. ULONG NumberOfElementsInTable = 0;
  127. *Result = NULL;
  128. if (Key == m_Key && m_KeyHashIsValid && m_PointerToBucket != NULL)
  129. {
  130. *Result = m_PointerToBucket;
  131. goto Exit;
  132. }
  133. if (IsEmpty())
  134. {
  135. goto Exit;
  136. }
  137. GetKeyHash(Key, &Hash);
  138. GetPointerToHashTable(&PointerToHashTable);
  139. NumberOfElementsInTable = PointerToHashTable->m_NumberOfElementsInTable;
  140. if (NumberOfElementsInTable == 0)
  141. {
  142. goto Exit;
  143. }
  144. BucketIndex = (Hash % PointerToHashTable->m_NumberOfBuckets);
  145. OffsetToPointer(PointerToHashTable->m_OffsetToBuckets + BucketIndex * sizeof(*PointerToBucket), &PointerToBucket);
  146. *Result = PointerToBucket;
  147. m_PointerToBucket = PointerToBucket;
  148. Exit:
  149. ;
  150. }
  151. BOOL CPositionIndependentHashTableAccessor::IsEmpty()
  152. {
  153. if (m_PositionIndependentTable->m_NumberOfHashTables == 0)
  154. return TRUE;
  155. if (GetPointerToHashTable()->m_NumberOfElementsInTable == 0)
  156. return TRUE;
  157. return FALSE;
  158. }
  159. void
  160. CPositionIndependentHashTableAccessor::GetBounds(
  161. const BYTE * Bounds[2]
  162. )
  163. {
  164. return m_PositionIndependentTable->GetBounds(Bounds);
  165. }
  166. void
  167. CPositionIndependentHashTableAccessor::IsInBlob(
  168. const BYTE * Pointer,
  169. ULONG Size,
  170. BOOL * IsInBlob
  171. )
  172. {
  173. return m_PositionIndependentTable->IsInBlob(Pointer, Size, IsInBlob);
  174. }
  175. void
  176. CPositionIndependentHashTableAccessor::SetAt(
  177. const BYTE * Key,
  178. ULONG KeySize,
  179. const BYTE * Value,
  180. ULONG ValueSize
  181. )
  182. {
  183. FN_PROLOG_VOID_THROW
  184. CHashTableBucket * Result = 0;
  185. ULONG Hash = 0;
  186. CHashTable * PointerToHashTable = 0;
  187. CHashTableBucket Bucket = { 0 };
  188. CHashTableBucket * PointerToBucket = 0;
  189. ULONG BucketIndex = 0;
  190. ULONG NumberOfElementsInTable = 0;
  191. ULONG NumberOfBuckets = 0;
  192. ULONG KeyOffset = 0;
  193. ULONG ValueOffset = 0;
  194. BOOL KeyIsInBlob = 0;
  195. BOOL ValueIsInBlob = 0;
  196. BYTE * BasePointer = BasePointer = GetBasePointer();
  197. GetKeyHash(Key, &Hash);
  198. GetPointerToHashTable(&PointerToHashTable);
  199. NumberOfElementsInTable = PointerToHashTable->m_NumberOfElementsInTable;
  200. NumberOfBuckets = PointerToHashTable->m_NumberOfBuckets;
  201. //
  202. // Do this before we get buckets.
  203. //
  204. IsInBlob(Key, KeySize, &KeyIsInBlob);
  205. IsInBlob(Value, ValueSize, &ValueIsInBlob);
  206. if (KeyIsInBlob)
  207. Key = BasePointer + KeyOffset;
  208. if (ValueIsInBlob)
  209. Value = BasePointer + ValueOffset;
  210. if (NumberOfBuckets == 0)
  211. {
  212. GrowNumberOfBuckets(17);
  213. NumberOfBuckets = PointerToHashTable->m_NumberOfBuckets;
  214. if (KeyIsInBlob)
  215. OffsetToPointer(KeyOffset, &Key);
  216. if (ValueIsInBlob)
  217. OffsetToPointer(ValueOffset, &Value);
  218. }
  219. BucketIndex = (Hash % NumberOfBuckets);
  220. OffsetToPointer(PointerToHashTable->m_OffsetToBuckets + BucketIndex * sizeof(*PointerToBucket), &PointerToBucket);
  221. Bucket = *PointerToBucket;
  222. CHashTableElement * Elements;
  223. OffsetToPointer(Bucket.m_OffsetToElements, &Elements);
  224. ULONG FreeElementIndex = 0;
  225. ULONG FoundElementIndex = 0;
  226. BOOL DidFindFreeElement = FALSE;
  227. BOOL DidFindElement = FALSE;
  228. for (ULONG ElementIndex = 0 ; ElementIndex != Bucket.m_AllocatedElementsInBucket; ++ElementIndex)
  229. {
  230. if (Elements[ElementIndex].m_InUse)
  231. {
  232. if (Hash == Elements[ElementIndex].m_PseudoKey
  233. && AreKeysEqual(Key, BasePointer + Elements[ElementIndex].m_OffsetToKey))
  234. {
  235. FoundElementIndex = ElementIndex;
  236. DidFindElement = TRUE;
  237. }
  238. }
  239. else if (!DidFindFreeElement)
  240. {
  241. FreeElementIndex = ElementIndex;
  242. DidFindFreeElement = TRUE;
  243. }
  244. if (DidFindFreeElement && DidFindElement)
  245. break;
  246. }
  247. ULONG NeededBytes = 0;
  248. ULONG NeededBlocks = 0;
  249. ULONG NeededElementBytes = 0;
  250. if (!DidFindElement && !DidFindFreeElement)
  251. {
  252. //
  253. // REVIEW Should we double, or just add one?
  254. //
  255. NeededElementBytes = sizeof(CHashTableElement) * (Bucket.m_AllocatedElementsInBucket + 1);
  256. NeededBytes += NeededElementBytes;
  257. NeededBlocks += 1;
  258. }
  259. else
  260. {
  261. NeededElementBytes = 0;
  262. }
  263. ULONG NeededKeyBytes = 0;
  264. if (KeySize <= sizeof(CHashTableElement().m_SmallKey)
  265. || KeyIsInBlob
  266. || DidFindElement
  267. || (DidFindFreeElement && Elements[FreeElementIndex].m_KeySize >= ValueSize)
  268. )
  269. {
  270. NeededKeyBytes = 0;
  271. }
  272. else
  273. {
  274. NeededKeyBytes = KeySize;
  275. NeededBytes += KeySize;
  276. NeededBlocks += 1;
  277. }
  278. ULONG NeededValueBytes = 0;
  279. if (ValueSize <= sizeof(CHashTableElement().m_SmallValue)
  280. || ValueIsInBlob
  281. || (DidFindElement && Elements[FoundElementIndex].m_ValueAllocatedSize >= ValueSize)
  282. || (DidFindFreeElement && Elements[FreeElementIndex].m_ValueAllocatedSize >= ValueSize)
  283. )
  284. {
  285. NeededValueBytes = 0;
  286. // NOTE: what about replacement with "equal" values?
  287. }
  288. else
  289. {
  290. NeededValueBytes = ValueSize;
  291. NeededBytes += ValueSize;
  292. NeededBlocks += 1;
  293. }
  294. Reserve(NeededBytes, NeededBlocks);
  295. if (NeededElementBytes != 0)
  296. {
  297. ULONG NewElementsOffset;
  298. Alloc(NeededElementBytes, &NewElementsOffset);
  299. CopyMemory(BasePointer + NewElementsOffset, Elements, NeededElementBytes - sizeof(CHashTableElement));
  300. Elements = reinterpret_cast<CHashTableElement*>(BasePointer + NewElementsOffset);
  301. }
  302. // undone right here
  303. FN_EPILOG_THROW;
  304. }
  305. PBYTE
  306. CPositionIndependentHashTableAccessor::GetBasePointer()
  307. {
  308. return m_PositionIndependentTable->GetBasePointer();
  309. }
  310. void
  311. CPositionIndependentHashTableAccessor::Alloc(ULONG NumberOfBytes, ULONG * Offset)
  312. {
  313. PBYTE BaseBefore = GetBasePointer();
  314. m_PositionIndependentTable->Alloc(NumberOfBytes, Offset);
  315. if (GetBasePointer() != BaseBefore)
  316. {
  317. m_PointerToBucket = NULL;
  318. m_PointerToHashTables = NULL;
  319. m_PointerToBucket = NULL;
  320. }
  321. }