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.

499 lines
18 KiB

  1. /****************************************************************************
  2. * SPHash.h
  3. * This is modified from sr/include/hash_n.h to minimize dependencies on
  4. * application specific headers.
  5. *
  6. * Owner: bohsu
  7. * Copyright 2000 Microsoft Corporation All Rights Reserved.
  8. *****************************************************************************/
  9. #pragma once
  10. #ifndef WIN32_LEAN_AND_MEAN
  11. #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
  12. #endif
  13. //--- Includes --------------------------------------------------------------
  14. #include <windows.h>
  15. #include <math.h>
  16. #include <crtdbg.h>
  17. #ifdef _DEBUG
  18. #include <stdio.h>
  19. #endif _DEBUG
  20. //--- Forward and External Declarations -------------------------------------
  21. //--- TypeDef and Enumeration Declarations ----------------------------------
  22. //--- Constants -------------------------------------------------------------
  23. //--- Class, Struct and Union Definitions -----------------------------------
  24. /***********************************************************************
  25. * CSPHash Class
  26. * This is a templated hash table class. Note that the base CSPHash class
  27. * does not allocate or free the Keys and Values. To define a hash class
  28. * that manages its Keys and Values, derive a subclass an overload Add()
  29. * and ...
  30. *****************************************************************bohsu*/
  31. template<class KEY, class VALUE>
  32. class CSPHash
  33. {
  34. public:
  35. // Constructor
  36. CSPHash(
  37. VALUE ValueNIL = NULL, // Value representing NIL
  38. UINT32 uInitialSize = 0); // Initial hash table size
  39. // Destructor
  40. virtual ~CSPHash();
  41. // Returns number of (Key, Value) entries used in the hash table.
  42. inline UINT32 GetNumEntries(void) const { return m_uNumEntriesUsed; }
  43. // Returns the next entry starting at the given index. Set puIndex = 0 for the first entry.
  44. VALUE GetNextEntry(
  45. UINT32 *puIndex, // Index to start looking for the next entry
  46. KEY *pKey = NULL) const; // [out] Key of the next entry found
  47. // Resets the content hash table.
  48. virtual void Reset(void);
  49. // Adds a (Key, Value) entry to the hash table.
  50. HRESULT Add(
  51. KEY Key, // Key to add
  52. VALUE Val); // Value associated with the Key
  53. // Lookup a Value based on the Key. If not found, ValueNIL is returned.
  54. VALUE Lookup(
  55. KEY Key) const; // Key to lookup
  56. #ifdef _DEBUG
  57. // Dumps the hash table statistics to file handle.
  58. void DumpStat(
  59. FILE *hFile = NULL, // Output file handle. NULL -> DebugWindow
  60. const char *strHeader = NULL) const; // Trace header
  61. #endif _DEBUG
  62. protected:
  63. // Data structure containing (Key, Value) pair
  64. struct ENTRY
  65. {
  66. KEY Key;
  67. VALUE Value;
  68. };
  69. // Find the index corresponding to the given Key.
  70. int FindIndex(
  71. KEY Key) const; // Key to search for
  72. static UINT32 NextPrime(UINT32 Val);
  73. protected:
  74. //---------------------------------------------------------------
  75. //--- The following functions can be overloaded by subclasses ---
  76. //---------------------------------------------------------------
  77. // If Destroy*() is overloaded, you MUST overload the destructor with:
  78. // virtual ~CSPDerivedHash() { Reset(); }
  79. // Calling Reset() in the base class destructor has no effect because
  80. // the derived subclass will have been destroyed already by the time it
  81. // gets to the base class destructor. Thus, the correct DestroyKey() and
  82. // DestroyValue() will never be called.
  83. // Hash function mapping the Key to a UINT32 index.
  84. virtual UINT32 HashKey(KEY Key) const { return (UINT32)Key; }
  85. // Compare if two Keys are equal.
  86. virtual bool AreKeysEqual(KEY Key1, KEY Key2) const { return Key1 == Key2; }
  87. // Hash function used to determine the skip count.
  88. virtual UINT32 HashKey2(KEY Key) const { return 1; }
  89. // Overload if a deep copy of the Key needs to be made in Add().
  90. virtual KEY CopyKey(KEY Key) const { return Key; }
  91. // Overload if a deep copy of the Key needs to be made in Add().
  92. virtual VALUE CopyValue(VALUE Value) const { return Value; }
  93. // Overload if the Key needs to be destroyed.
  94. virtual void DestroyKey(KEY Key) const { }
  95. // Overload if the Value needs to be destroyed.
  96. virtual void DestroyValue(VALUE Value) const { }
  97. //------------------------
  98. //--- Member Variables ---
  99. //------------------------
  100. protected:
  101. ENTRY *m_aTable; // Hash table containing (Key, Value) pairs
  102. VALUE m_ValueNIL; // Value representing NIL
  103. UINT32 m_uNumEntries; // Current size of hash table
  104. UINT32 m_uNumEntriesInit; // Initial size of hash table
  105. UINT32 m_uNumEntriesUsed; // Current number of entries used in hash table
  106. #ifdef _DEBUG
  107. UINT32 m_uAccess; // Number of times a Key is looked up
  108. UINT32 m_uSearch; // Number of times a entry in the table is searched
  109. UINT32 m_uRegrow; // Number of times the hash table regrew
  110. #endif _DEBUG
  111. };
  112. /***********************************************************************
  113. * CSPStringHashW Class
  114. * CSPStringHashW is a hash of UNICODE strings to VALUEs. The UNICODE string
  115. * is treated as a constant. It is neither copied during Add() nor deleted
  116. * during destructor. Likewise, VALUE is treated as a simple data type and
  117. * is neither copied nor destroyed. If the application wants the class to
  118. * manage its own copy of the string key or VALUE, derive a subclass and
  119. * overload Copy*() and/or Destroy().
  120. *****************************************************************bohsu*/
  121. template<class VALUE> class CSPStringHashW : public CSPHash<const WCHAR *, VALUE>
  122. {
  123. protected:
  124. UINT32 StringHashW(const WCHAR *wcsKey, UINT32 uPrime) const
  125. {
  126. UINT32 uHashIndex = 0;
  127. for(const WCHAR *pwch = wcsKey; *pwch != NULL; pwch++)
  128. uHashIndex = uHashIndex * uPrime + *pwch;
  129. return uHashIndex;
  130. }
  131. //--- Overloaded functions ---
  132. protected:
  133. virtual UINT32 HashKey(const WCHAR* wcsKey) const { return StringHashW(wcsKey, 65599); }
  134. virtual UINT32 HashKey2(const WCHAR* wcsKey) const { return StringHashW(wcsKey, 257); }
  135. virtual bool AreKeysEqual(const WCHAR* wcsKey1, const WCHAR* wcsKey2) const
  136. {
  137. return wcscmp(wcsKey1, wcsKey2) == 0;
  138. }
  139. };
  140. /***********************************************************************
  141. * CSPGUIDHash Class
  142. * CSPGUIDHash is a hash of GUIDs to VALUEs. The GUID pointer is treated
  143. * as a constant. It is neither copied during Add() nor deleted
  144. * during destructor. Likewise, VALUE is treated as a simple data type and
  145. * is neither copied nor destroyed. If the application wants the class to
  146. * manage its own copy of the GUID key or VALUE, derive a subclass and
  147. * overload Copy*() and/or Destroy().
  148. *****************************************************************bohsu*/
  149. template<class VALUE> class CSPGUIDHash : public CSPHash<const GUID *, VALUE>
  150. {
  151. //--- Overloaded functions ---
  152. protected:
  153. virtual UINT32 HashKey(const GUID *pguidKey) const { return pguidKey->Data1; }
  154. virtual UINT32 HashKey2(const GUID *pguidKey) const { return pguidKey->Data2; }
  155. virtual bool AreKeysEqual(const GUID *pguidKey1, const GUID *pguidKey2) const
  156. {
  157. // It is annoying that operator== for GUIDs return int (BOOL) instead of bool.
  158. return (*pguidKey1 == *pguidKey2) != 0;
  159. }
  160. };
  161. //--- Function Declarations -------------------------------------------------
  162. //--- Inline Function Definitions -------------------------------------------
  163. /**********************************************************************
  164. * CSPHash::CSPHash *
  165. *------------------*
  166. * Description:
  167. * Constructor.
  168. ****************************************************************bohsu*/
  169. template<class KEY, class VALUE>
  170. CSPHash<KEY, VALUE>::CSPHash(
  171. VALUE ValueNIL, // Value representing NIL
  172. UINT32 uInitialSize) // Initial hash table size
  173. {
  174. m_ValueNIL = ValueNIL;
  175. m_aTable = 0;
  176. m_uNumEntries = 0;
  177. m_uNumEntriesInit = uInitialSize; // Estimated final number of entries to be stored.
  178. m_uNumEntriesUsed = 0;
  179. #ifdef _DEBUG
  180. m_uAccess = 0;
  181. m_uSearch = 0;
  182. m_uRegrow = 0;
  183. #endif _DEBUG
  184. }
  185. /**********************************************************************
  186. * CSPHash::~CSPHash *
  187. *-------------------*
  188. * Description:
  189. * Destructor. This does not free KEY and VALUE.
  190. * If Destroy*() is overloaded, call Reset() in the subclass destructor.
  191. ****************************************************************bohsu*/
  192. template<class KEY, class VALUE>
  193. CSPHash<KEY, VALUE>::~CSPHash()
  194. {
  195. delete [] m_aTable;
  196. }
  197. /**********************************************************************
  198. * CSPHash::GetNextEntry *
  199. *-----------------------*
  200. * Description:
  201. * Returns the next entry starting at the given index. Set puIndex = 0 for the first entry.
  202. ****************************************************************bohsu*/
  203. template<class KEY, class VALUE>
  204. VALUE CSPHash<KEY, VALUE>::GetNextEntry(
  205. UINT32 *puIndex, // Index to start looking for the next entry
  206. KEY *pKey) const // [out] Key of the next entry found
  207. {
  208. while (*puIndex < m_uNumEntries)
  209. {
  210. if (m_aTable[*puIndex].Value != m_ValueNIL)
  211. {
  212. if(pKey) *pKey = m_aTable[*puIndex].Key;
  213. return m_aTable[(*puIndex)++].Value;
  214. }
  215. ++*puIndex;
  216. }
  217. return m_ValueNIL;
  218. }
  219. /**********************************************************************
  220. * CSPHash::Reset *
  221. *----------------*
  222. * Description:
  223. * Resets the content hash table.
  224. ****************************************************************bohsu*/
  225. template<class KEY, class VALUE>
  226. void CSPHash<KEY, VALUE>::Reset()
  227. {
  228. for (UINT32 i=0; i < m_uNumEntries; i++)
  229. {
  230. if(m_aTable[i].Value != m_ValueNIL)
  231. {
  232. DestroyKey(m_aTable[i].Key);
  233. DestroyValue(m_aTable[i].Value);
  234. m_aTable[i].Value = m_ValueNIL;
  235. }
  236. }
  237. m_uNumEntriesUsed = 0;
  238. #ifdef _DEBUG
  239. m_uAccess = m_uSearch = m_uRegrow = 0;
  240. #endif _DEBUG
  241. }
  242. /**********************************************************************
  243. * CSPHash::Add *
  244. *--------------*
  245. * Description:
  246. * Adds a (Key, Value) entry to the hash table.
  247. ****************************************************************bohsu*/
  248. template<class KEY, class VALUE>
  249. HRESULT CSPHash<KEY, VALUE>::Add(
  250. KEY Key, // Key to add
  251. VALUE Val) // Value associated with the Key
  252. {
  253. int ientry;
  254. // Implementation uses Val==m_ValueNIL to detect empty entries.
  255. _ASSERTE(Val != m_ValueNIL);
  256. // Grow if allowed and we're more than half full.
  257. // (Also handles initial alloc)
  258. if (m_uNumEntriesUsed * 2 >= m_uNumEntries)
  259. {
  260. /* half-full, too crowded ==> regrow */
  261. ENTRY * oldtable = m_aTable;
  262. UINT32 oldentry = m_uNumEntries;
  263. UINT32 prime = NextPrime(max(m_uNumEntriesUsed * 3 + 17, m_uNumEntriesInit));
  264. #ifdef _DEBUG
  265. m_uRegrow++;
  266. #endif _DEBUG
  267. // Alloc new table.
  268. m_aTable = new ENTRY[prime];
  269. if (m_aTable == NULL)
  270. {
  271. m_aTable = oldtable;
  272. return E_OUTOFMEMORY;
  273. }
  274. for (UINT32 i=0; i < prime; i++)
  275. {
  276. m_aTable[i].Value = m_ValueNIL;
  277. }
  278. m_uNumEntries = prime;
  279. for (i = 0; i < oldentry; i++)
  280. {
  281. if (oldtable[i].Value != m_ValueNIL)
  282. {
  283. ientry = FindIndex(oldtable[i].Key);
  284. _ASSERTE(ientry >= 0 && m_aTable[ientry].Value == m_ValueNIL);
  285. m_aTable[ientry] = oldtable[i];
  286. }
  287. }
  288. delete [] oldtable;
  289. }
  290. // Find out where this element should end up.
  291. ientry = FindIndex(Key);
  292. if (ientry < 0)
  293. return E_FAIL; // Too full
  294. if (m_aTable[ientry].Value == m_ValueNIL)
  295. {
  296. // Not already there. Add it.
  297. m_aTable[ientry].Key = CopyKey(Key);
  298. m_aTable[ientry].Value = CopyValue(Val);
  299. m_uNumEntriesUsed++;
  300. }
  301. else
  302. {
  303. return S_FALSE; // It was already there.
  304. }
  305. return S_OK;
  306. }
  307. /**********************************************************************
  308. * CSPHash::Lookup *
  309. *-----------------*
  310. * Description:
  311. * Lookup a Value based on the Key. If not found, ValueNIL is returned.
  312. ****************************************************************bohsu*/
  313. template<class KEY, class VALUE>
  314. VALUE CSPHash<KEY, VALUE>::Lookup(
  315. KEY Key) const // Key to lookup
  316. {
  317. int ientry = FindIndex(Key);
  318. if (ientry < 0)
  319. return m_ValueNIL;
  320. return m_aTable[ientry].Value;
  321. }
  322. #ifdef _DEBUG
  323. /**********************************************************************
  324. * CSPHash::DumpStat *
  325. *-------------------*
  326. * Description:
  327. * Dumps the hash table statistics to file handle.
  328. ****************************************************************bohsu*/
  329. template<class KEY, class VALUE>
  330. void CSPHash<KEY, VALUE>::DumpStat(
  331. FILE *hFile, // Output file handle.
  332. const char *strHeader) const // Trace header
  333. {
  334. if(hFile == NULL)
  335. {
  336. char buf[100];
  337. sprintf(buf, "(%s) hash statistics:\n", strHeader ? strHeader : "");
  338. OutputDebugString(buf);
  339. sprintf(buf, "load=%d/%d = %.3g, regrow = %d\n", m_uNumEntriesUsed, m_uNumEntries,
  340. (m_uNumEntries == 0) ? 0 : (float)m_uNumEntriesUsed/(float)m_uNumEntries, m_uRegrow);
  341. OutputDebugString(buf);
  342. sprintf(buf, "access %d/%d = %g\n\n", m_uSearch, m_uAccess,
  343. (m_uAccess == 0) ? 0 :
  344. (float) m_uSearch / (float) m_uAccess);
  345. OutputDebugString(buf);
  346. }
  347. else
  348. {
  349. fprintf(hFile, "(%s) hash statistics:\n", strHeader ? strHeader : "");
  350. fprintf(hFile, "load=%d/%d = %.3g, regrow = %d\n", m_uNumEntriesUsed, m_uNumEntries,
  351. (m_uNumEntries == 0) ? 0 : (float)m_uNumEntriesUsed/(float)m_uNumEntries, m_uRegrow);
  352. fprintf(hFile, "access %d/%d = %g\n\n", m_uSearch, m_uAccess,
  353. (m_uAccess == 0) ? 0 :
  354. (float) m_uSearch / (float) m_uAccess);
  355. }
  356. }
  357. #endif _DEBUG
  358. /**********************************************************************
  359. * CSPHash::FindIndex *
  360. *--------------------*
  361. * Description:
  362. * Find the index corresponding to the given Key.
  363. ****************************************************************bohsu*/
  364. template<class KEY, class VALUE>
  365. int CSPHash<KEY, VALUE>::FindIndex(
  366. KEY Key) const
  367. {
  368. #ifdef _DEBUG
  369. // Hack: Violate const declaration for statistics member variables
  370. const_cast<CSPHash *>(this)->m_uAccess++;
  371. #endif _DEBUG
  372. if (m_uNumEntries == 0)
  373. return -1;
  374. UINT32 start = HashKey(Key) % m_uNumEntries;
  375. UINT32 index = start;
  376. UINT32 skip = 0;
  377. do
  378. {
  379. #ifdef _DEBUG
  380. // Hack: Violate const declaration for statistics member variables
  381. const_cast<CSPHash *>(this)->m_uSearch++;
  382. #endif _DEBUG
  383. // Not in table; return index where it should be placed.
  384. if (m_aTable[index].Value == m_ValueNIL)
  385. return index;
  386. if (AreKeysEqual(m_aTable[index].Key, Key))
  387. return index;
  388. if (skip == 0)
  389. {
  390. skip = HashKey2(Key);
  391. // Limit skip amount to non-zero and less than hash table size.
  392. // Since m_uNumEntries is prime, they are relatively prime and so we're guaranteed
  393. // to visit every bucket.
  394. if (m_uNumEntries > 1)
  395. skip = skip % (m_uNumEntries - 1) + 1;
  396. }
  397. index += skip;
  398. if (index >= m_uNumEntries)
  399. index -= m_uNumEntries;
  400. } while (index != start);
  401. _ASSERTE(m_uNumEntriesUsed == m_uNumEntries);
  402. return -1; /* all full and not found */
  403. }
  404. /**********************************************************************
  405. * CSPHash::NextPrime *
  406. *--------------------*
  407. * Description:
  408. * Return a prime number greater than or equal to Val.
  409. * If overflow occurs, return 0.
  410. *
  411. * To Do: This function can be optimized significantly.
  412. ****************************************************************bohsu*/
  413. template<class KEY, class VALUE>
  414. UINT32 CSPHash<KEY, VALUE>::NextPrime(UINT32 Val)
  415. {
  416. UINT32 maxFactor;
  417. UINT32 i;
  418. if (Val < 2) return 2; // the smallest prime number
  419. while(Val < 0xFFFFFFFF)
  420. {
  421. maxFactor = (UINT32) sqrt ((double) Val); // Is Val a prime number?
  422. for (i = 2; i <= maxFactor; i++) // Is i a factor of Val?
  423. if (Val % i == 0) break;
  424. if (i > maxFactor) return (Val);
  425. Val++;
  426. };
  427. return 0;
  428. }