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.

344 lines
8.0 KiB

  1. /*
  2. * hash.cpp
  3. *
  4. * Purpose:
  5. * implementation of a string hash table
  6. *
  7. * Owner:
  8. * EricAn
  9. *
  10. * History:
  11. * Mar 97: Created.
  12. *
  13. * Copyright (C) Microsoft Corp. 1997
  14. */
  15. #include <pch.hxx>
  16. #include "dllmain.h"
  17. #include "privunk.h"
  18. #include "hash.h"
  19. #include "demand.h"
  20. // possible hash-table sizes, chosen from primes not close to powers of 2
  21. static const DWORD s_rgPrimes[] = { 29, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593 };
  22. BOOL FastStrCmp(char *psz1, char *psz2)
  23. {
  24. if (psz1 == NULL || psz2 == NULL)
  25. return FALSE;
  26. while (*psz1 && *psz2 && (*psz1 == *psz2))
  27. {
  28. psz1++;
  29. psz2++;
  30. };
  31. return *psz1 == *psz2;
  32. }
  33. //+---------------------------------------------------------------
  34. //
  35. // Member: Constructor
  36. //
  37. // Synopsis:
  38. //
  39. //---------------------------------------------------------------
  40. CHash::CHash(IUnknown *pUnkOuter) : CPrivateUnknown(pUnkOuter)
  41. {
  42. m_cBins = 0;
  43. m_rgBins = NULL;
  44. m_fDupe = FALSE;
  45. m_pLastEntryEnum = NULL;
  46. m_iListBinEnum = 0;
  47. DllAddRef();
  48. }
  49. CHash::~CHash()
  50. {
  51. PHASHENTRY phe, pheTemp;
  52. for (DWORD dw = 0; dw < m_cBins; dw++)
  53. {
  54. if (m_rgBins[dw].pheNext)
  55. {
  56. phe = m_rgBins[dw].pheNext;
  57. while (phe)
  58. {
  59. pheTemp = phe;
  60. phe = phe->pheNext;
  61. if (m_fDupe && pheTemp->pszKey)
  62. MemFree(pheTemp->pszKey);
  63. MemFree(pheTemp);
  64. }
  65. }
  66. if (m_rgBins[dw].pszKey && m_fDupe)
  67. MemFree(m_rgBins[dw].pszKey);
  68. }
  69. SafeMemFree(m_rgBins);
  70. DllRelease();
  71. }
  72. HRESULT CHash::Init(DWORD dwSize, BOOL fDupeKeys)
  73. {
  74. int i = 0;
  75. m_fDupe = fDupeKeys;
  76. while (i < (ARRAYSIZE(s_rgPrimes) - 1) && s_rgPrimes[i] < dwSize)
  77. i++;
  78. Assert(s_rgPrimes[i] >= dwSize || i == (ARRAYSIZE(s_rgPrimes)-1));
  79. m_cBins = s_rgPrimes[i];
  80. if (!MemAlloc((LPVOID*)&m_rgBins, m_cBins * sizeof(HASHENTRY)))
  81. return E_OUTOFMEMORY;
  82. ZeroMemory(m_rgBins, m_cBins * sizeof(HASHENTRY));
  83. return NOERROR;
  84. }
  85. DWORD CHash::Hash(LPSTR psz)
  86. {
  87. DWORD h = 0;
  88. while (*psz)
  89. h = ((h << 4) + *psz++ + (h >> 28));
  90. return (h % m_cBins);
  91. }
  92. HRESULT CHash::Insert(LPSTR psz, LPVOID pv, DWORD dwFlags)
  93. {
  94. PHASHENTRY phe = &m_rgBins[Hash(psz)];
  95. if (m_fDupe &&
  96. (!(psz = PszDupA(psz))))
  97. return E_OUTOFMEMORY;
  98. if (HF_NO_DUPLICATES & dwFlags)
  99. {
  100. PHASHENTRY pheCurrent = phe;
  101. // Check for duplicate entries: if found, do not insert this entry
  102. do
  103. {
  104. if (pheCurrent->pszKey && FastStrCmp(pheCurrent->pszKey, psz))
  105. {
  106. // This is already in our hash table. Replace data value
  107. pheCurrent->pv = pv;
  108. if (m_fDupe)
  109. MemFree(psz);
  110. return NOERROR;
  111. }
  112. // Advance pointer
  113. pheCurrent = pheCurrent->pheNext;
  114. } while (NULL != pheCurrent);
  115. }
  116. if (phe->pszKey)
  117. {
  118. PHASHENTRY pheNew;
  119. if (!MemAlloc((LPVOID*)&pheNew, sizeof(HASHENTRY)))
  120. {
  121. if (m_fDupe)
  122. MemFree(psz);
  123. return E_OUTOFMEMORY;
  124. }
  125. pheNew->pheNext = phe->pheNext;
  126. phe->pheNext = pheNew;
  127. phe = pheNew;
  128. }
  129. phe->pszKey = psz;
  130. phe->pv = pv;
  131. return NOERROR;
  132. }
  133. HRESULT CHash::Find(LPSTR psz, BOOL fRemove, LPVOID * ppv)
  134. {
  135. PHASHENTRY phe = &m_rgBins[Hash(psz)],
  136. phePrev = NULL,
  137. pheTemp;
  138. if (phe->pszKey)
  139. {
  140. do
  141. {
  142. if (FastStrCmp(phe->pszKey, psz))
  143. {
  144. *ppv = phe->pv;
  145. if (fRemove)
  146. {
  147. if (m_fDupe)
  148. SafeMemFree(phe->pszKey);
  149. if (phePrev)
  150. {
  151. // mid-chain
  152. phePrev->pheNext = phe->pheNext;
  153. MemFree(phe);
  154. }
  155. else
  156. {
  157. // head of bucket
  158. phe->pv = NULL;
  159. phe->pszKey = NULL;
  160. pheTemp = phe->pheNext;
  161. if (pheTemp)
  162. {
  163. CopyMemory(phe, pheTemp, sizeof(HASHENTRY));
  164. MemFree(pheTemp);
  165. }
  166. }
  167. }
  168. return NOERROR;
  169. }
  170. phePrev = phe;
  171. phe = phe->pheNext;
  172. }
  173. while (phe);
  174. }
  175. return CO_E_NOMATCHINGNAMEFOUND;
  176. }
  177. HRESULT CHash::Replace(LPSTR psz, LPVOID pv)
  178. {
  179. PHASHENTRY phe = &m_rgBins[Hash(psz)];
  180. if (phe->pszKey)
  181. {
  182. do
  183. {
  184. if (FastStrCmp(phe->pszKey, psz))
  185. {
  186. phe->pv = pv;
  187. return NOERROR;
  188. }
  189. phe = phe->pheNext;
  190. }
  191. while (phe);
  192. }
  193. return CO_E_NOMATCHINGNAMEFOUND;
  194. }
  195. HRESULT CHash::Reset()
  196. {
  197. m_iListBinEnum = 0;
  198. m_pLastEntryEnum = &m_rgBins[0];
  199. return S_OK;
  200. }
  201. HRESULT CHash::Next(ULONG cFetch, LPVOID **prgpv, ULONG *pcFetched)
  202. {
  203. LPVOID *rgpv;
  204. ULONG cFound=0;
  205. PHASHENTRY phe;
  206. HRESULT hr;
  207. if (!MemAlloc((LPVOID *)&rgpv, sizeof(LPVOID) * cFetch))
  208. return E_OUTOFMEMORY;
  209. ZeroMemory(rgpv, sizeof(LPVOID) * cFetch);
  210. while (m_pLastEntryEnum)
  211. {
  212. if (m_pLastEntryEnum->pszKey)
  213. rgpv[cFound++] = m_pLastEntryEnum->pv;
  214. m_pLastEntryEnum = m_pLastEntryEnum->pheNext;
  215. if (!m_pLastEntryEnum && m_iListBinEnum < m_cBins -1)
  216. m_pLastEntryEnum = &m_rgBins[++m_iListBinEnum];
  217. if (cFound == cFetch)
  218. break;
  219. }
  220. hr = cFound ? (cFound == cFetch ? S_OK : S_FALSE) : E_FAIL;
  221. if (FAILED(hr))
  222. {
  223. MemFree(rgpv);
  224. rgpv = NULL;
  225. }
  226. *prgpv = rgpv;
  227. *pcFetched = cFound;
  228. return hr;
  229. }
  230. #ifdef DEBUG
  231. void CHash::Stats()
  232. {
  233. DWORD dwLongest = 0;
  234. DWORD dwCollisions = 0;
  235. DWORD dwTotalCost = 0;
  236. DWORD dwItems = 0;
  237. DWORD dwLength;
  238. DWORD dw;
  239. PHASHENTRY phe;
  240. DWORD rgLen[100];
  241. TraceCall("CHash::Stats()");
  242. ZeroMemory(rgLen, sizeof(rgLen));
  243. for (dw = 0; dw < m_cBins; dw++)
  244. {
  245. dwLength = 0;
  246. if (m_rgBins[dw].pszKey)
  247. {
  248. dwLength++;
  249. phe = m_rgBins[dw].pheNext;
  250. while (phe)
  251. {
  252. dwCollisions++;
  253. dwLength++;
  254. phe = phe->pheNext;
  255. }
  256. }
  257. if (dwLength > dwLongest)
  258. dwLongest = dwLength;
  259. dwTotalCost += (dwLength * (dwLength + 1)) / 2;
  260. dwItems += dwLength;
  261. rgLen[dwLength]++;
  262. }
  263. TraceInfo(_MSG("\tdwCollisions = %ld\r\n\tdwLongest = %ld\r\n\tdwItems = %ld\r\n\tdwTotalCost = %ld",
  264. dwCollisions, dwLongest, dwItems, dwTotalCost));
  265. for (dw = 0; dw <= dwLongest; dw++)
  266. TraceInfo(_MSG("Len %d: %d", dw, rgLen[dw]));
  267. }
  268. #endif
  269. //+---------------------------------------------------------------
  270. //
  271. // Member: PrivateQueryInterface
  272. //
  273. // Synopsis:
  274. //
  275. //---------------------------------------------------------------
  276. HRESULT CHash::PrivateQueryInterface(REFIID riid, LPVOID *lplpObj)
  277. {
  278. if(!lplpObj)
  279. return E_INVALIDARG;
  280. *lplpObj = NULL;
  281. if (IsEqualIID(riid, IID_IHashTable))
  282. *lplpObj = (LPVOID)(IHashTable *)this;
  283. else
  284. return E_NOINTERFACE;
  285. AddRef();
  286. return NOERROR;
  287. }