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.

280 lines
6.8 KiB

  1. /*++
  2. Copyright (c) 1998-2002 Microsoft Corporation
  3. Module Name :
  4. hashfn.h
  5. Abstract:
  6. Declares and defines a collection of overloaded hash functions.
  7. It is strongly suggested that you use these functions with LKRhash.
  8. Author:
  9. George V. Reilly (GeorgeRe) 06-Jan-1998
  10. Environment:
  11. Win32 - User Mode
  12. Project:
  13. Internet Information Server RunTime Library
  14. Revision History:
  15. --*/
  16. #ifndef __HASHFN_H__
  17. #define __HASHFN_H__
  18. #define __HASHFN_NO_NAMESPACE__
  19. #ifndef __HASHFN_NO_NAMESPACE__
  20. namespace HashFn {
  21. #endif // !__HASHFN_NO_NAMESPACE__
  22. // Produce a scrambled, randomish number in the range 0 to RANDOM_PRIME-1.
  23. // Applying this to the results of the other hash functions is likely to
  24. // produce a much better distribution, especially for the identity hash
  25. // functions such as Hash(char c), where records will tend to cluster at
  26. // the low end of the hashtable otherwise. LKRhash applies this internally
  27. // to all hash signatures for exactly this reason.
  28. inline DWORD
  29. HashScramble(DWORD dwHash)
  30. {
  31. // Here are 10 primes slightly greater than 10^9
  32. // 1000000007, 1000000009, 1000000021, 1000000033, 1000000087,
  33. // 1000000093, 1000000097, 1000000103, 1000000123, 1000000181.
  34. // default value for "scrambling constant"
  35. const DWORD RANDOM_CONSTANT = 314159269UL;
  36. // large prime number, also used for scrambling
  37. const DWORD RANDOM_PRIME = 1000000007UL;
  38. return (RANDOM_CONSTANT * dwHash) % RANDOM_PRIME ;
  39. }
  40. // Faster scrambling function suggested by Eric Jacobsen
  41. inline DWORD
  42. HashRandomizeBits(DWORD dw)
  43. {
  44. return (((dw * 1103515245 + 12345) >> 16)
  45. | ((dw * 69069 + 1) & 0xffff0000));
  46. }
  47. // Small prime number used as a multiplier in the supplied hash functions
  48. const DWORD HASH_MULTIPLIER = 101;
  49. #undef HASH_SHIFT_MULTIPLY
  50. #ifdef HASH_SHIFT_MULTIPLY
  51. # define HASH_MULTIPLY(dw) (((dw) << 7) - (dw))
  52. #else
  53. # define HASH_MULTIPLY(dw) ((dw) * HASH_MULTIPLIER)
  54. #endif
  55. // Fast, simple hash function that tends to give a good distribution.
  56. // Apply HashScramble to the result if you're using this for something
  57. // other than LKRhash.
  58. inline DWORD
  59. HashString(
  60. const char* psz,
  61. DWORD dwHash = 0)
  62. {
  63. // force compiler to use unsigned arithmetic
  64. const unsigned char* upsz = (const unsigned char*) psz;
  65. for ( ; *upsz; ++upsz)
  66. dwHash = HASH_MULTIPLY(dwHash) + *upsz;
  67. return dwHash;
  68. }
  69. // Unicode version of above
  70. inline DWORD
  71. HashString(
  72. const wchar_t* pwsz,
  73. DWORD dwHash = 0)
  74. {
  75. for ( ; *pwsz; ++pwsz)
  76. dwHash = HASH_MULTIPLY(dwHash) + *pwsz;
  77. return dwHash;
  78. }
  79. // Quick-'n'-dirty case-insensitive string hash function.
  80. // Make sure that you follow up with _stricmp or _mbsicmp. You should
  81. // also cache the length of strings and check those first. Caching
  82. // an uppercase version of a string can help too.
  83. // Again, apply HashScramble to the result if using with something other
  84. // than LKRhash.
  85. // Note: this is not really adequate for MBCS strings.
  86. inline DWORD
  87. HashStringNoCase(
  88. const char* psz,
  89. DWORD dwHash = 0)
  90. {
  91. const unsigned char* upsz = (const unsigned char*) psz;
  92. for ( ; *upsz; ++upsz)
  93. dwHash = HASH_MULTIPLY(dwHash)
  94. + (*upsz & 0xDF); // strip off lowercase bit
  95. return dwHash;
  96. }
  97. // Unicode version of above
  98. inline DWORD
  99. HashStringNoCase(
  100. const wchar_t* pwsz,
  101. DWORD dwHash = 0)
  102. {
  103. for ( ; *pwsz; ++pwsz)
  104. dwHash = HASH_MULTIPLY(dwHash) + (*pwsz & 0xFFDF);
  105. return dwHash;
  106. }
  107. // HashBlob returns the hash of a blob of arbitrary binary data.
  108. //
  109. // Warning: HashBlob is generally not the right way to hash a class object.
  110. // Consider:
  111. // class CFoo {
  112. // public:
  113. // char m_ch;
  114. // double m_d;
  115. // char* m_psz;
  116. // };
  117. //
  118. // inline DWORD Hash(const CFoo& rFoo)
  119. // { return HashBlob(&rFoo, sizeof(CFoo)); }
  120. //
  121. // This is the wrong way to hash a CFoo for two reasons: (a) there will be
  122. // a 7-byte gap between m_ch and m_d imposed by the alignment restrictions
  123. // of doubles, which will be filled with random data (usually non-zero for
  124. // stack variables), and (b) it hashes the address (rather than the
  125. // contents) of the string m_psz. Similarly,
  126. //
  127. // bool operator==(const CFoo& rFoo1, const CFoo& rFoo2)
  128. // { return memcmp(&rFoo1, &rFoo2, sizeof(CFoo)) == 0; }
  129. //
  130. // does the wrong thing. Much better to do this:
  131. //
  132. // DWORD Hash(const CFoo& rFoo)
  133. // {
  134. // return HashString(rFoo.m_psz,
  135. // HASH_MULTIPLIER * Hash(rFoo.m_ch)
  136. // + Hash(rFoo.m_d));
  137. // }
  138. //
  139. // Again, apply HashScramble if using with something other than LKRhash.
  140. inline DWORD
  141. HashBlob(
  142. const void* pv,
  143. size_t cb,
  144. DWORD dwHash = 0)
  145. {
  146. LPBYTE pb = static_cast<LPBYTE>(const_cast<void*>(pv));
  147. while (cb-- > 0)
  148. dwHash = HASH_MULTIPLY(dwHash) + *pb++;
  149. return dwHash;
  150. }
  151. //
  152. // Overloaded hash functions for all the major builtin types.
  153. // Again, apply HashScramble to result if using with something other than
  154. // LKRhash.
  155. //
  156. inline DWORD Hash(const char* psz)
  157. { return HashString(psz); }
  158. inline DWORD Hash(const unsigned char* pusz)
  159. { return HashString(reinterpret_cast<const char*>(pusz)); }
  160. inline DWORD Hash(const signed char* pssz)
  161. { return HashString(reinterpret_cast<const char*>(pssz)); }
  162. inline DWORD Hash(const wchar_t* pwsz)
  163. { return HashString(pwsz); }
  164. inline DWORD
  165. Hash(
  166. const GUID* pguid,
  167. DWORD dwHash = 0)
  168. {
  169. return * reinterpret_cast<DWORD*>(const_cast<GUID*>(pguid)) + dwHash;
  170. }
  171. // Identity hash functions: scalar values map to themselves
  172. inline DWORD Hash(char c)
  173. { return c; }
  174. inline DWORD Hash(unsigned char uc)
  175. { return uc; }
  176. inline DWORD Hash(signed char sc)
  177. { return sc; }
  178. inline DWORD Hash(short sh)
  179. { return sh; }
  180. inline DWORD Hash(unsigned short ush)
  181. { return ush; }
  182. inline DWORD Hash(int i)
  183. { return i; }
  184. inline DWORD Hash(unsigned int u)
  185. { return u; }
  186. inline DWORD Hash(long l)
  187. { return l; }
  188. inline DWORD Hash(unsigned long ul)
  189. { return ul; }
  190. inline DWORD Hash(float f)
  191. {
  192. // be careful of rounding errors when computing keys
  193. union {
  194. float f;
  195. DWORD dw;
  196. } u;
  197. u.f = f;
  198. return u.dw;
  199. }
  200. inline DWORD Hash(double dbl)
  201. {
  202. // be careful of rounding errors when computing keys
  203. union {
  204. double dbl;
  205. DWORD dw[2];
  206. } u;
  207. u.dbl = dbl;
  208. return u.dw[0] * HASH_MULTIPLIER + u.dw[1];
  209. }
  210. #ifndef __HASHFN_NO_NAMESPACE__
  211. }
  212. #endif // !__HASHFN_NO_NAMESPACE__
  213. #endif // __HASHFN_H__