Source code of Windows XP (NT5)
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.

513 lines
13 KiB

  1. /********************************************************************
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. PFHash.cpp
  5. Abstract:
  6. hash table implementation. This hash table is NOT thread safe.
  7. Revision History:
  8. DerekM created 05/01/99
  9. DerekM modified 03/14/00
  10. ********************************************************************/
  11. #include "stdafx.h"
  12. #include "PFHash.h"
  13. /////////////////////////////////////////////////////////////////////////////
  14. // tracing stuff
  15. #ifdef THIS_FILE
  16. #undef THIS_FILE
  17. #endif
  18. static char __szTraceSourceFile[] = __FILE__;
  19. #define THIS_FILE __szTraceSourceFile
  20. /////////////////////////////////////////////////////////////////////////////
  21. // CPFHashBase - construction
  22. // ***************************************************************************
  23. CPFHashBase::CPFHashBase(void)
  24. {
  25. m_pfnDelete = NULL;
  26. m_rgpMap = NULL;
  27. m_pEnumNext = NULL;
  28. m_cSlots = 0;
  29. m_cObjs = 0;
  30. m_iEnumSlot = (DWORD)-1;
  31. }
  32. // ***************************************************************************
  33. CPFHashBase::~CPFHashBase()
  34. {
  35. this->Cleanup();
  36. if (m_rgpMap != NULL)
  37. MyFree(m_rgpMap);
  38. }
  39. /////////////////////////////////////////////////////////////////////////////
  40. // CPFHashBase - internal methods
  41. // ***************************************************************************
  42. void CPFHashBase::Cleanup(void)
  43. {
  44. USE_TRACING("CPFHashBase::Cleanup");
  45. SPFHashObj *pObj = NULL, *pObjNext;
  46. DWORD i;
  47. // if the map is NULL, our work here is done. We can go lay on a beach
  48. // somewhere...
  49. if (m_rgpMap == NULL)
  50. return;
  51. // delete everything from the map
  52. for (i = 0; i < m_cSlots; i++)
  53. {
  54. pObj = m_rgpMap[i];
  55. while(pObj != NULL)
  56. {
  57. pObjNext = pObj->pNext;
  58. if (pObj->pvTag != NULL)
  59. /*this->*/DeleteTag(pObj->pvTag);
  60. if (pObj->pvData != NULL && m_pfnDelete != NULL)
  61. (*this->m_pfnDelete)(pObj->pvData);
  62. MyFree(pObj);
  63. pObj = pObjNext;
  64. }
  65. m_rgpMap[i] = NULL;
  66. }
  67. m_cObjs = 0;
  68. }
  69. // ***************************************************************************
  70. SPFHashObj *CPFHashBase::FindInChain(LPVOID pvTag, DWORD iSlot,
  71. SPFHashObj ***pppObjStore)
  72. {
  73. USE_TRACING("CPFHashBase::FindInChain");
  74. SPFHashObj *pObj = NULL, **ppObjStore = NULL;
  75. INT_PTR iResult;
  76. // search thru the array. Since we insert in sorted order, we can
  77. // optimize searching and stop if we get to an array larger than we are.
  78. // So that this can be used to find locations for inserting & deleting, we
  79. // also keep track of the next ptr of the previous object and return it if
  80. // necessary...
  81. pObj = m_rgpMap[iSlot];
  82. ppObjStore = &m_rgpMap[iSlot];
  83. while (pObj != NULL)
  84. {
  85. // if it's a string, do a strcmp. Otherwise do a subtraction
  86. iResult = /*this->*/CompareTag(pObj->pvTag, pvTag);
  87. // if it's equal, we found it
  88. if (iResult == 0)
  89. {
  90. break;
  91. }
  92. // if it's greater, we can stop
  93. else if (iResult > 0)
  94. {
  95. pObj = NULL;
  96. break;
  97. }
  98. // incrememnt ptrs and continue walkin' the chain gang...
  99. ppObjStore = &(pObj->pNext);
  100. pObj = pObj->pNext;
  101. }
  102. // return the next ptr.
  103. if (pppObjStore != NULL)
  104. *pppObjStore = ppObjStore;
  105. return pObj;
  106. }
  107. ////////////////////////////////////////////////////////////////////////////
  108. // CPFHashBase - exposed methods
  109. // ***************************************************************************
  110. HRESULT CPFHashBase::Init(DWORD cSlots)
  111. {
  112. USE_TRACING("CPFHashBase::Init");
  113. SPFHashObj **rgpMap = NULL;
  114. HRESULT hr = NOERROR;
  115. VALIDATEPARM(hr, (cSlots <= 1));
  116. if (FAILED(hr))
  117. goto done;
  118. // if we already have an array, clear out the old contents. If the new
  119. // size is different than the old, then nuke the array as well and
  120. // reallocate.
  121. if (m_rgpMap != NULL)
  122. {
  123. this->Cleanup();
  124. if (cSlots == m_cSlots)
  125. goto done;
  126. MyFree(m_rgpMap);
  127. m_rgpMap = NULL;
  128. m_cSlots = 0;
  129. }
  130. // alloc the array
  131. rgpMap = (SPFHashObj **)MyAlloc(cSlots * sizeof(SPFHashObj *));
  132. VALIDATEEXPR(hr, (rgpMap == NULL), E_OUTOFMEMORY);
  133. if (FAILED(hr))
  134. goto done;
  135. ZeroMemory(rgpMap, cSlots * sizeof(SPFHashObj *));
  136. // save off internal data
  137. m_rgpMap = rgpMap;
  138. m_cSlots = cSlots;
  139. rgpMap = NULL;
  140. done:
  141. if (rgpMap != NULL)
  142. MyFree(rgpMap);
  143. return hr;
  144. }
  145. // ***************************************************************************
  146. HRESULT CPFHashBase::AddToMap(LPVOID pvTag, LPVOID pvData, LPVOID *ppvOld)
  147. {
  148. USE_TRACING("CPFHashBase::AddToMap");
  149. SPFHashObj *pObj = NULL, **ppObjStore = NULL, *pNewObj = NULL;
  150. HRESULT hr = NOERROR;
  151. DWORD iSlot;
  152. VALIDATEPARM(hr, (pvTag == NULL));
  153. if (FAILED(hr))
  154. goto done;
  155. // if we don't have a map already setup fail...
  156. VALIDATEEXPR(hr, (m_rgpMap == NULL), E_FAIL)
  157. if (FAILED(hr))
  158. goto done;
  159. if (ppvOld != NULL)
  160. *ppvOld = NULL;
  161. // compute the slot & try to find the object
  162. iSlot = /*this->*/ComputeSlot(pvTag);
  163. pObj = this->FindInChain(pvTag, iSlot, &ppObjStore);
  164. // we're just updating an existing element
  165. if (pObj != NULL)
  166. {
  167. // does the user want it back?
  168. if (ppvOld != NULL)
  169. *ppvOld = pObj->pvData;
  170. // or should be just delete it?
  171. else if (pObj->pvData != NULL && m_pfnDelete != NULL)
  172. (*this->m_pfnDelete)(pObj->pvData);
  173. pObj->pvData = pvData;
  174. }
  175. // ok folks, we got REAL work to do now.
  176. else
  177. {
  178. if (ppvOld != NULL)
  179. *ppvOld = NULL;
  180. // alloc new object
  181. pNewObj = (SPFHashObj *)MyAlloc(sizeof(SPFHashObj));
  182. VALIDATEEXPR(hr, (pNewObj == NULL), E_OUTOFMEMORY);
  183. if (FAILED(hr))
  184. goto done;
  185. TESTHR(hr, /*this->*/AllocTag(pvTag, &(pNewObj->pvTag)));
  186. if (FAILED(hr))
  187. goto done;
  188. pNewObj->pvData = pvData;
  189. pNewObj->pNext = *ppObjStore;
  190. *ppObjStore = pNewObj;
  191. // increment the number of objects
  192. m_cObjs++;
  193. pNewObj = NULL;
  194. }
  195. done:
  196. if (pNewObj != NULL)
  197. {
  198. if (pNewObj->pvTag != NULL)
  199. /*this->*/DeleteTag(pNewObj->pvTag);
  200. MyFree(pNewObj);
  201. }
  202. return hr;
  203. }
  204. // ***************************************************************************
  205. HRESULT CPFHashBase::FindInMap(LPVOID pvTag, LPVOID *ppv)
  206. {
  207. USE_TRACING("CPFHashBase::FindInMap");
  208. SPFHashObj *pObj = NULL;
  209. HRESULT hr = NOERROR;
  210. DWORD iSlot;
  211. // validate params
  212. VALIDATEPARM(hr, (ppv == NULL || pvTag == NULL));
  213. if (FAILED(hr))
  214. goto done;
  215. // if we don't have a map already setup fail...
  216. VALIDATEEXPR(hr, (m_rgpMap == NULL), E_FAIL);
  217. if (FAILED(hr))
  218. goto done;
  219. // compute the slot & try to find the object
  220. iSlot = /*this->*/ComputeSlot(pvTag);
  221. pObj = this->FindInChain(pvTag, iSlot, NULL);
  222. // if we didn't find it, signal S_FALSE
  223. if (pObj == NULL)
  224. {
  225. hr = S_FALSE;
  226. goto done;
  227. }
  228. // otherwise, return the data to the user
  229. *ppv = pObj->pvData;
  230. done:
  231. return hr;
  232. }
  233. // ***************************************************************************
  234. HRESULT CPFHashBase::RemoveFromMap(LPVOID pvTag, LPVOID *ppvOld)
  235. {
  236. USE_TRACING("CPFHashBase::RemoveFromMap");
  237. SPFHashObj *pObj = NULL, **ppObjStore = NULL;
  238. HRESULT hr = NOERROR;
  239. DWORD iSlot;
  240. // validate params
  241. VALIDATEPARM(hr, (ppvOld == NULL || pvTag == NULL));
  242. if (FAILED(hr))
  243. goto done;
  244. // if we don't have a map already setup fail...
  245. VALIDATEEXPR(hr, (m_rgpMap == NULL), E_FAIL);
  246. if (FAILED(hr))
  247. goto done;
  248. // compute the slot & try to find the object
  249. iSlot = /*this->*/ComputeSlot(pvTag);
  250. pObj = this->FindInChain(pvTag, iSlot, &ppObjStore);
  251. // if we didn't find one, just return NOERROR cuz not having one in the
  252. // map is pretty much what the user wanted...
  253. if (pObj != NULL)
  254. {
  255. // does the user want it back?
  256. if (ppvOld != NULL)
  257. *ppvOld = pObj->pvData;
  258. // or should be just delete it?
  259. else if (pObj->pvData != NULL && m_pfnDelete != NULL)
  260. (*this->m_pfnDelete)(pObj->pvData);
  261. *ppObjStore = pObj->pNext;
  262. /*this->*/DeleteTag(pObj->pvTag);
  263. MyFree(pObj);
  264. }
  265. done:
  266. return hr;
  267. }
  268. // ***************************************************************************
  269. HRESULT CPFHashBase::RemoveAll(void)
  270. {
  271. USE_TRACING("CPFHashBase::RemoveAll");
  272. // if we don't have a map already just succeed cuz everything has been
  273. // deleted. Otherwise, remove everything in life (as far as the map
  274. // is concerned anyway).
  275. if (m_rgpMap != NULL)
  276. this->Cleanup();
  277. return NOERROR;
  278. }
  279. // ***************************************************************************
  280. HRESULT CPFHashBase::BeginEnum(void)
  281. {
  282. USE_TRACING("CPFHashBase::BeginEnum");
  283. HRESULT hr = NOERROR;
  284. // if we don't have a map already setup fail...
  285. VALIDATEEXPR(hr, (m_rgpMap == NULL), E_FAIL);
  286. if (FAILED(hr))
  287. goto done;
  288. m_iEnumSlot = 0;
  289. m_pEnumNext = m_rgpMap[0];
  290. done:
  291. return hr;
  292. }
  293. // ***************************************************************************
  294. HRESULT CPFHashBase::EnumNext(LPVOID *ppvTag, LPVOID *ppvData)
  295. {
  296. USE_TRACING("CPFHashBase::EnumNext");
  297. HRESULT hr = NOERROR;
  298. // if we don't have a map already setup fail...
  299. VALIDATEEXPR(hr, (m_rgpMap == NULL || m_iEnumSlot == (DWORD)-1), E_FAIL);
  300. if (FAILED(hr))
  301. goto done;
  302. for(;;)
  303. {
  304. if (m_pEnumNext != NULL)
  305. {
  306. *ppvTag = m_pEnumNext->pvTag;
  307. *ppvData = m_pEnumNext->pvData;
  308. m_pEnumNext = m_pEnumNext->pNext;
  309. break;
  310. }
  311. m_iEnumSlot++;
  312. if (m_iEnumSlot >= m_cSlots)
  313. {
  314. m_iEnumSlot = (DWORD)-1;
  315. hr = S_FALSE;
  316. break;
  317. }
  318. m_pEnumNext = m_rgpMap[m_iEnumSlot];
  319. }
  320. done:
  321. return hr;
  322. }
  323. /*
  324. #if defined(DEBUG) || defined(_DEBUG)
  325. // ***************************************************************************
  326. void CPFHashBase::DumpAll(FILE *pf)
  327. {
  328. USE_TRACING("CPFHashBASE::DumpAll");
  329. SPFHashObj *pmo = NULL, *pmoNext;
  330. DWORD i;
  331. // if the map is NULL, our work here is done. We can go lay on a beach
  332. // somewhere...
  333. if (m_rgpMap == NULL)
  334. {
  335. fprintf(pf, "empty map\n\n");
  336. return;
  337. }
  338. // delete everything from the map
  339. for (i = 0; i < m_cSlots; i++)
  340. {
  341. fprintf(pf, "Slot %2d: ", i);
  342. pmo = m_rgpMap[i];
  343. while(pmo != NULL)
  344. {
  345. pmoNext = pmo->pNext;
  346. this->PrintTag(pf, pmo->pvTag);
  347. pmo = pmoNext;
  348. }
  349. fprintf(pf, "\n");
  350. }
  351. fprintf(pf, "\n");
  352. }
  353. // ***************************************************************************
  354. void CPFHashBase::DumpCount(FILE *pf)
  355. {
  356. USE_TRACING("CPFHashBASE::DumpCount");
  357. fprintf(pf, "count: %d\n", m_cObjs);
  358. }
  359. #endif
  360. */
  361. /////////////////////////////////////////////////////////////////////////////
  362. // CPFHashWSTR virtual method implementation
  363. // ***************************************************************************
  364. HRESULT CPFHashWSTR::AllocTag(LPVOID pvTag, LPVOID *ppvTagCopy)
  365. {
  366. USE_TRACING("CPFHashWSTR::AllocTag");
  367. HRESULT hr = NOERROR;
  368. LPWSTR pwsz = NULL;
  369. pwsz = (LPWSTR)MyAlloc((wcslen((LPWSTR)pvTag) + 1) * sizeof(WCHAR));
  370. VALIDATEEXPR(hr, (pwsz == NULL), E_OUTOFMEMORY);
  371. if (FAILED(hr))
  372. goto done;
  373. wcscpy(pwsz, (LPWSTR)pvTag);
  374. *ppvTagCopy = (LPVOID)pwsz;
  375. done:
  376. return hr;
  377. }
  378. // ***************************************************************************
  379. DWORD CPFHashWSTR::ComputeSlot(LPVOID pvTag)
  380. {
  381. USE_TRACING("CPFHashWSTR::ComputeSlot");
  382. WCHAR *pwch = NULL;
  383. DWORD dwHash;
  384. dwHash = 0;
  385. for (pwch = (WCHAR *)pvTag; *pwch != '\0'; pwch++)
  386. dwHash = ((dwHash << 6) + towupper(*pwch)) % m_cSlots;
  387. return dwHash;
  388. }
  389. // ***************************************************************************
  390. void CPFHashWSTR::DeleteTag(LPVOID pvTag)
  391. {
  392. USE_TRACING("CPFHashWSTR::DeleteTag");
  393. MyFree(pvTag);
  394. }
  395. // ***************************************************************************
  396. INT_PTR CPFHashWSTR::CompareTag(LPVOID pvTag1, LPVOID pvTag2)
  397. {
  398. USE_TRACING("CPFHashWSTR::CompareTag");
  399. return (INT_PTR)_wcsicmp((LPWSTR)pvTag1, (LPWSTR)pvTag2);
  400. }