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.

471 lines
11 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 2001-2002 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: HashTable.cpp
  6. * Content: Hash Table Object
  7. *
  8. * History:
  9. * Date By Reason
  10. * ==== == ======
  11. * 08/13/2001 masonb Created
  12. *
  13. *
  14. ***************************************************************************/
  15. #include "dncmni.h"
  16. //**********************************************************************
  17. // Constant definitions
  18. //**********************************************************************
  19. //**********************************************************************
  20. // Macro definitions
  21. //**********************************************************************
  22. //**********************************************************************
  23. // Structure definitions
  24. //**********************************************************************
  25. //**********************************************************************
  26. // Variable definitions
  27. //**********************************************************************
  28. //**********************************************************************
  29. // Function prototypes
  30. //**********************************************************************
  31. //**********************************************************************
  32. // Function definitions
  33. //**********************************************************************
  34. //
  35. // pool management functions
  36. //
  37. #undef DPF_MODNAME
  38. #define DPF_MODNAME "CHashTable::HashEntry_Alloc"
  39. BOOL CHashTable::HashEntry_Alloc( void *pItem, void* pvContext )
  40. {
  41. DNASSERT( pItem != NULL );
  42. _HASHTABLE_ENTRY* pEntry = (_HASHTABLE_ENTRY*)pItem;
  43. pEntry->blLinkage.Initialize();
  44. return TRUE;
  45. }
  46. #ifdef DBG
  47. #undef DPF_MODNAME
  48. #define DPF_MODNAME "CHashTable::HashEntry_Init"
  49. void CHashTable::HashEntry_Init( void *pItem, void* pvContext )
  50. {
  51. DNASSERT( pItem != NULL );
  52. const _HASHTABLE_ENTRY* pEntry = (_HASHTABLE_ENTRY*)pItem;
  53. DNASSERT( pEntry->blLinkage.IsEmpty() );
  54. }
  55. #undef DPF_MODNAME
  56. #define DPF_MODNAME "CHashTable::HashEntry_Release"
  57. void CHashTable::HashEntry_Release( void *pItem )
  58. {
  59. DNASSERT( pItem != NULL );
  60. const _HASHTABLE_ENTRY* pEntry = (_HASHTABLE_ENTRY*)pItem;
  61. DNASSERT( pEntry->blLinkage.IsEmpty() );
  62. }
  63. #undef DPF_MODNAME
  64. #define DPF_MODNAME "CHashTable::HashEntry_Dealloc"
  65. void CHashTable::HashEntry_Dealloc( void *pItem )
  66. {
  67. DNASSERT( pItem != NULL );
  68. const _HASHTABLE_ENTRY* pEntry = (_HASHTABLE_ENTRY*)pItem;
  69. DNASSERT( pEntry->blLinkage.IsEmpty() );
  70. }
  71. #endif // DBG
  72. #undef DPF_MODNAME
  73. #define DPF_MODNAME "CHashTable::CHashTable"
  74. CHashTable::CHashTable()
  75. {
  76. DEBUG_ONLY(m_fInitialized = FALSE);
  77. };
  78. #undef DPF_MODNAME
  79. #define DPF_MODNAME "CHashTable::~CHashTable"
  80. CHashTable::~CHashTable()
  81. {
  82. #ifdef DBG
  83. DNASSERT(!m_fInitialized);
  84. #endif // DBG
  85. };
  86. #undef DPF_MODNAME
  87. #define DPF_MODNAME "CHashTable::Initialize"
  88. BOOL CHashTable::Initialize( BYTE bBitDepth,
  89. #ifndef DPNBUILD_PREALLOCATEDMEMORYMODEL
  90. BYTE bGrowBits,
  91. #endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
  92. PFNHASHTABLECOMPARE pfnCompare,
  93. PFNHASHTABLEHASH pfnHash )
  94. {
  95. DNASSERT(bBitDepth != 0);
  96. memset(this, 0, sizeof(CHashTable));
  97. m_dwAllocatedEntries = 1 << bBitDepth;
  98. m_pfnCompareFunction = pfnCompare;
  99. m_pfnHashFunction = pfnHash;
  100. m_pblEntries = (CBilink*)DNMalloc(sizeof(CBilink) * m_dwAllocatedEntries);
  101. if (m_pblEntries == NULL)
  102. {
  103. DPFERR("Failed to allocate hash entries array");
  104. return FALSE;
  105. }
  106. #ifdef DBG
  107. if (!m_EntryPool.Initialize(sizeof(_HASHTABLE_ENTRY), HashEntry_Alloc, HashEntry_Init, HashEntry_Release, HashEntry_Dealloc))
  108. #else
  109. if (!m_EntryPool.Initialize(sizeof(_HASHTABLE_ENTRY), HashEntry_Alloc, NULL, NULL, NULL))
  110. #endif // DBG
  111. {
  112. DPFERR("Failed to initialize hash entries pool");
  113. DNFree(m_pblEntries);
  114. m_pblEntries = NULL;
  115. return FALSE;
  116. }
  117. for (DWORD dwEntry = 0; dwEntry < m_dwAllocatedEntries; dwEntry++)
  118. {
  119. m_pblEntries[dwEntry].Initialize();
  120. }
  121. m_bBitDepth = bBitDepth;
  122. #ifdef DPNBUILD_PREALLOCATEDMEMORYMODEL
  123. //
  124. // Pre-allocate all hash entries now.
  125. //
  126. if (m_EntryPool.Preallocate(m_dwAllocatedEntries, NULL) != m_dwAllocatedEntries)
  127. {
  128. DPFERR("Failed to preallocate hash entries");
  129. m_EntryPool.DeInitialize();
  130. DNFree(m_pblEntries);
  131. m_pblEntries = NULL;
  132. return FALSE;
  133. }
  134. #else // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
  135. m_bGrowBits = bGrowBits;
  136. #endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
  137. DEBUG_ONLY(m_fInitialized = TRUE);
  138. DPFX(DPFPREP, 5,"[%p] Hash table initialized", this);
  139. return TRUE;
  140. };
  141. #undef DPF_MODNAME
  142. #define DPF_MODNAME "CHashTable::Deinitialize"
  143. void CHashTable::Deinitialize( void )
  144. {
  145. #ifdef DBG
  146. DNASSERT(m_fInitialized);
  147. m_fInitialized = FALSE;
  148. #endif // DBG
  149. DNASSERT( m_dwEntriesInUse == 0 );
  150. if (m_pblEntries)
  151. {
  152. DNFree(m_pblEntries);
  153. m_pblEntries = NULL;
  154. }
  155. m_EntryPool.DeInitialize();
  156. DPFX(DPFPREP, 5,"[%p] Hash table deinitialized", this);
  157. };
  158. #ifndef DPNBUILD_PREALLOCATEDMEMORYMODEL
  159. #undef DPF_MODNAME
  160. #define DPF_MODNAME "CHashTable::GrowTable"
  161. void CHashTable::GrowTable( void )
  162. {
  163. #ifdef DBG
  164. DNASSERT( m_fInitialized != FALSE);
  165. DNASSERT( m_bGrowBits != 0 );
  166. #endif // DBG
  167. CBilink* pblOldEntries;
  168. BYTE bNewHashBitDepth;
  169. DWORD dwNewHashSize;
  170. DWORD dwOldHashSize;
  171. #ifdef DBG
  172. DWORD dwOldEntryCount;
  173. #endif // DBG
  174. // We're more than 50% full, find a new has table size that will accomodate
  175. // all of the current entries, and keep a pointer to the old data in case
  176. // the memory allocation fails.
  177. pblOldEntries = m_pblEntries;
  178. bNewHashBitDepth = m_bBitDepth;
  179. do
  180. {
  181. bNewHashBitDepth += m_bGrowBits;
  182. } while (m_dwEntriesInUse >= (DWORD)((1 << bNewHashBitDepth) / 2));
  183. //
  184. // assert that we don't pull up half of the machine's address space!
  185. //
  186. DNASSERT( bNewHashBitDepth <= ( sizeof( UINT_PTR ) * 8 / 2 ) );
  187. dwNewHashSize = 1 << bNewHashBitDepth;
  188. m_pblEntries = (CBilink*)DNMalloc(sizeof(CBilink) * dwNewHashSize);
  189. if ( m_pblEntries == NULL )
  190. {
  191. // Allocation failed, restore the old data pointer and insert the item
  192. // into the hash table. This will probably result in adding to a bucket.
  193. m_pblEntries = pblOldEntries;
  194. DPFX(DPFPREP, 0, "Warning: Failed to grow hash table when 50% full!" );
  195. return;
  196. }
  197. // we have more memory, reorient the hash table and re-add all of
  198. // the old items
  199. DEBUG_ONLY( dwOldEntryCount = m_dwEntriesInUse );
  200. dwOldHashSize = 1 << m_bBitDepth;
  201. m_bBitDepth = bNewHashBitDepth;
  202. m_dwAllocatedEntries = dwNewHashSize;
  203. m_dwEntriesInUse = 0;
  204. for (DWORD dwEntry = 0; dwEntry < dwNewHashSize; dwEntry++)
  205. {
  206. m_pblEntries[dwEntry].Initialize();
  207. }
  208. DNASSERT( dwOldHashSize > 0 );
  209. while ( dwOldHashSize > 0 )
  210. {
  211. dwOldHashSize--;
  212. while (pblOldEntries[dwOldHashSize].GetNext() != &pblOldEntries[dwOldHashSize])
  213. {
  214. BOOL fTempReturn;
  215. PVOID pvKey;
  216. PVOID pvData;
  217. _HASHTABLE_ENTRY* pTempEntry;
  218. pTempEntry = CONTAINING_OBJECT(pblOldEntries[dwOldHashSize ].GetNext(), _HASHTABLE_ENTRY, blLinkage);
  219. pTempEntry->blLinkage.RemoveFromList();
  220. pvKey = pTempEntry->pvKey;
  221. pvData = pTempEntry->pvData;
  222. m_EntryPool.Release( pTempEntry );
  223. // Since we're returning the current hash table entry to the pool
  224. // it will be immediately reused in the new table. We should never
  225. // have a problem adding to the new list.
  226. fTempReturn = Insert( pvKey, pvData );
  227. DNASSERT( fTempReturn != FALSE );
  228. DEBUG_ONLY( dwOldEntryCount-- );
  229. }
  230. }
  231. #ifdef DBG
  232. DNASSERT(dwOldEntryCount == 0);
  233. #endif // DBG
  234. DNFree(pblOldEntries);
  235. pblOldEntries = NULL;
  236. };
  237. #endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
  238. #undef DPF_MODNAME
  239. #define DPF_MODNAME "CHashTable::Insert"
  240. BOOL CHashTable::Insert( PVOID pvKey, PVOID pvData )
  241. {
  242. BOOL fFound;
  243. CBilink* pLink;
  244. _HASHTABLE_ENTRY* pNewEntry;
  245. DEBUG_ONLY( DNASSERT( m_fInitialized != FALSE ) );
  246. pNewEntry = NULL;
  247. #ifndef DPNBUILD_PREALLOCATEDMEMORYMODEL
  248. // grow the map if applicable
  249. if ( ( m_dwEntriesInUse >= ( m_dwAllocatedEntries / 2 ) ) &&
  250. ( m_bGrowBits != 0 ) )
  251. {
  252. GrowTable();
  253. }
  254. #endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
  255. // get a new table entry before trying the lookup
  256. pNewEntry = (_HASHTABLE_ENTRY*)m_EntryPool.Get();
  257. if ( pNewEntry == NULL )
  258. {
  259. DPFX(DPFPREP, 0, "Problem allocating new hash table entry" );
  260. return FALSE;
  261. }
  262. // scan for this item in the list, since we're only supposed to have
  263. // unique items in the list, ASSERT if a duplicate is found
  264. fFound = LocalFind( pvKey, &pLink );
  265. DNASSERT( pLink != NULL );
  266. DNASSERT( fFound == FALSE );
  267. DNASSERT( pLink != NULL );
  268. // officially add entry to the hash table
  269. m_dwEntriesInUse++;
  270. pNewEntry->pvKey = pvKey;
  271. pNewEntry->pvData = pvData;
  272. pNewEntry->blLinkage.InsertAfter(pLink);
  273. return TRUE;
  274. }
  275. #undef DPF_MODNAME
  276. #define DPF_MODNAME "CHashTable::Remove"
  277. BOOL CHashTable::Remove( PVOID pvKey )
  278. {
  279. #ifdef DBG
  280. DNASSERT( m_fInitialized != FALSE );
  281. #endif // DBG
  282. CBilink* pLink;
  283. _HASHTABLE_ENTRY* pEntry;
  284. if ( !LocalFind( pvKey, &pLink ) )
  285. {
  286. return FALSE;
  287. }
  288. DNASSERT( pLink != NULL );
  289. pEntry = CONTAINING_OBJECT(pLink, _HASHTABLE_ENTRY, blLinkage);
  290. pEntry->blLinkage.RemoveFromList();
  291. m_EntryPool.Release( pEntry );
  292. DNASSERT( m_dwEntriesInUse != 0 );
  293. m_dwEntriesInUse--;
  294. return TRUE;
  295. }
  296. #ifndef DPNBUILD_NOREGISTRY
  297. #undef DPF_MODNAME
  298. #define DPF_MODNAME "CHashTable::RemoveAll"
  299. void CHashTable::RemoveAll( void )
  300. {
  301. DWORD dwHashSize;
  302. DWORD dwTemp;
  303. CBilink* pLink;
  304. _HASHTABLE_ENTRY* pEntry;
  305. #ifdef DBG
  306. DNASSERT( m_fInitialized != FALSE );
  307. #endif // DBG
  308. dwHashSize = 1 << m_bBitDepth;
  309. for(dwTemp = 0; dwTemp < dwHashSize; dwTemp++)
  310. {
  311. pLink = m_pblEntries[dwTemp].GetNext();
  312. while (pLink != &m_pblEntries[dwTemp])
  313. {
  314. pEntry = CONTAINING_OBJECT(pLink, _HASHTABLE_ENTRY, blLinkage);
  315. pLink = pLink->GetNext();
  316. pEntry->blLinkage.RemoveFromList();
  317. m_EntryPool.Release( pEntry );
  318. DNASSERT( m_dwEntriesInUse != 0 );
  319. m_dwEntriesInUse--;
  320. }
  321. }
  322. DNASSERT( m_dwEntriesInUse == 0 );
  323. }
  324. #endif // ! DPNBUILD_NOREGISTRY
  325. #undef DPF_MODNAME
  326. #define DPF_MODNAME "CHashTable::Find"
  327. BOOL CHashTable::Find( PVOID pvKey, PVOID* ppvData )
  328. {
  329. #ifdef DBG
  330. DNASSERT( m_fInitialized != FALSE );
  331. #endif // DBG
  332. CBilink* pLink;
  333. _HASHTABLE_ENTRY* pEntry;
  334. if (!LocalFind(pvKey, &pLink))
  335. {
  336. return FALSE;
  337. }
  338. DNASSERT(pLink != NULL);
  339. pEntry = CONTAINING_OBJECT(pLink, _HASHTABLE_ENTRY, blLinkage);
  340. *ppvData = pEntry->pvData;
  341. return TRUE;
  342. }
  343. #undef DPF_MODNAME
  344. #define DPF_MODNAME "CHashTable::LocalFind"
  345. BOOL CHashTable::LocalFind( PVOID pvKey, CBilink** ppLinkage )
  346. {
  347. #ifdef DBG
  348. DNASSERT( m_fInitialized != FALSE);
  349. #endif // DBG
  350. DWORD dwHashResult;
  351. CBilink* pLink;
  352. _HASHTABLE_ENTRY* pEntry;
  353. dwHashResult = (*m_pfnHashFunction)(pvKey, m_bBitDepth );
  354. DNASSERT(dwHashResult < (DWORD)(1 << m_bBitDepth));
  355. pLink = m_pblEntries[dwHashResult].GetNext();
  356. while (pLink != &m_pblEntries[dwHashResult])
  357. {
  358. pEntry = CONTAINING_OBJECT(pLink, _HASHTABLE_ENTRY, blLinkage);
  359. if ( (*m_pfnCompareFunction)( pvKey, pEntry->pvKey ) )
  360. {
  361. *ppLinkage = pLink;
  362. return TRUE;
  363. }
  364. pLink = pLink->GetNext();
  365. }
  366. // entry was not found, return pointer to linkage to insert after if a new
  367. // entry is being added to the table
  368. *ppLinkage = pLink;
  369. return FALSE;
  370. }