Team Fortress 2 Source Code as on 22/4/2020
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.

268 lines
6.9 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: PearsonsHash.h
  4. //
  5. // This file contains implementation definitions of 'Pearson's' Hash'
  6. // The generic implementation is a template, plus a couple of specializations
  7. // for commonly used types.
  8. //
  9. // Take a look at http://en.wikipedia.org/wiki/Pearson_hashing for more info.
  10. //
  11. //=============================================================================
  12. #ifndef _PEARSONSHASH_H_
  13. #define _PEARSONSHASH_H_
  14. #if defined(_WIN32) || defined(_WIN64)
  15. #pragma once
  16. #endif
  17. extern const unsigned char g_CTHashRandomValues[256] ;
  18. template<typename T>
  19. struct PearsonsHashFunctor
  20. {
  21. typedef uint32 TargetType ;
  22. TargetType operator()(const T& unKey) const
  23. {
  24. // This is a pearsons hash variant that returns a maximum of 32 bits
  25. size_t size = sizeof(T);
  26. const uint8 * k = (const uint8 *) &unKey;
  27. uint32 byte_one = 0, byte_two = 0, byte_three = 0, byte_four = 0, n;
  28. while (size)
  29. {
  30. --size;
  31. n = *k++;
  32. byte_one = g_CTHashRandomValues[byte_one ^ n];
  33. if (size)
  34. {
  35. --size;
  36. n = *k++;
  37. byte_two = g_CTHashRandomValues[byte_two ^ n];
  38. }
  39. else
  40. break;
  41. if (size)
  42. {
  43. --size;
  44. n = *k++;
  45. byte_three = g_CTHashRandomValues[byte_three ^ n];
  46. }
  47. else
  48. break;
  49. if (size)
  50. {
  51. --size;
  52. n = *k++;
  53. byte_four = g_CTHashRandomValues[byte_four ^ n];
  54. }
  55. else
  56. break;
  57. }
  58. TargetType idx = ( byte_four << 24 ) | ( byte_three << 16 ) | ( byte_two << 8 ) | byte_one;
  59. return ( idx );
  60. }
  61. };
  62. //
  63. // We use this specialization for pointer types - it allows somebody
  64. // to define a specialization for some complicated type, and then use a
  65. // pointer to that type as a key, and have that automatically go to the
  66. // specialization for the complicated type !
  67. //
  68. template<typename T>
  69. struct PearsonsHashFunctor<T*>
  70. {
  71. typedef uint32 TargetType ;
  72. TargetType operator()(const T* key) const
  73. {
  74. PearsonsHashFunctor<T> functor ;
  75. return functor(*key) ;
  76. }
  77. };
  78. //
  79. // This functor specializes for unsigned 32 bit integers, a commonly used type in Steam.
  80. // It should return the exact same result as the unspecialized version on Intel Architecture machines.
  81. //
  82. template<>
  83. struct PearsonsHashFunctor<uint32>
  84. {
  85. typedef uint32 TargetType ;
  86. TargetType operator()(const uint32 unKey) const
  87. {
  88. uint32 byte_one = g_CTHashRandomValues[(unKey>>0) & 0xff];
  89. uint32 byte_two = g_CTHashRandomValues[(unKey>>8) & 0xff];
  90. uint32 byte_three = g_CTHashRandomValues[(unKey>>16) & 0xff];
  91. uint32 byte_four = g_CTHashRandomValues[(unKey>>24)&0xff];
  92. return ( byte_four << 24 ) | ( byte_three << 16 ) | ( byte_two << 8 ) | byte_one;
  93. }
  94. };
  95. //
  96. // This functor specializes for unsigned 64 bit integers, another commonly used type in Steam.
  97. // It should return the exact same result as the unspecialized version on Intel Architecture machines.
  98. //
  99. template<>
  100. struct PearsonsHashFunctor<uint64>
  101. {
  102. typedef uint32 TargetType ;
  103. TargetType operator()(const uint64 unKey) const
  104. {
  105. //
  106. // Note that we pull apart the 64 bits in Intel's endian order.
  107. //
  108. uint32 n;
  109. //
  110. // On Intel Machines, to make this return the exact same result as the generic version
  111. // we have to go from least significant byte to most significant byte !
  112. //
  113. n = static_cast<uint32>((unKey >> (0)) & 0xff) ;
  114. uint32 byte_one = g_CTHashRandomValues[n];
  115. n = static_cast<uint32>((unKey >> (8)) & 0xff) ;
  116. uint32 byte_two = g_CTHashRandomValues[n];
  117. n = static_cast<uint32>((unKey >> (16)) & 0xff) ;
  118. uint32 byte_three = g_CTHashRandomValues[n];
  119. n = static_cast<uint32>((unKey >> (24)) & 0xff) ;
  120. uint32 byte_four = g_CTHashRandomValues[n];
  121. n = static_cast<uint32>((unKey >> (32)) & 0xff) ;
  122. byte_one = g_CTHashRandomValues[n ^ byte_one];
  123. n = static_cast<uint32>((unKey >> (8+32)) & 0xff) ;
  124. byte_two = g_CTHashRandomValues[n ^ byte_two];
  125. n = static_cast<uint32>((unKey >> (16+32)) & 0xff) ;
  126. byte_three = g_CTHashRandomValues[n ^ byte_three];
  127. n = static_cast<uint32>((unKey >> (24+32)) & 0xff) ;
  128. byte_four = g_CTHashRandomValues[n ^ byte_four];
  129. return ( byte_four << 24 ) | ( byte_three << 16 ) | ( byte_two << 8 ) | byte_one;
  130. }
  131. };
  132. //
  133. // This functor specializes for C standard NULL terminated strings !
  134. // It is setup so that if you had a char array containing a NULL terminated string
  135. // and correctly sized, ie char rgch[16] = { "123456789012345" } and a
  136. // null terminated string i.e. char *sz = "123456789012345" these will return identical
  137. // results, and both include the NULL terminator in the hash calculation.
  138. //
  139. template<>
  140. struct PearsonsHashFunctor<char*>
  141. {
  142. typedef uint32 TargetType ;
  143. TargetType operator()(const char* szKey) const
  144. {
  145. const uint8 * k = (const uint8 *) szKey ;
  146. uint32 byte_one = 0, byte_two = 0, byte_three = 0, byte_four = 0, n;
  147. do
  148. {
  149. n = *k++;
  150. byte_one = g_CTHashRandomValues[byte_one ^ n];
  151. if (n=='\0')
  152. break;
  153. n = *k++;
  154. byte_two = g_CTHashRandomValues[byte_two ^ n];
  155. if (n=='\0')
  156. break;
  157. n = *k++;
  158. byte_three = g_CTHashRandomValues[byte_three ^ n];
  159. if (n=='\0')
  160. break;
  161. n = *k++;
  162. byte_four = g_CTHashRandomValues[byte_four ^ n];
  163. } while(n!='\0') ;
  164. TargetType idx = ( byte_four << 24 ) | ( byte_three << 16 ) | ( byte_two << 8 ) | byte_one;
  165. return ( idx );
  166. }
  167. };
  168. //
  169. // This functor compares two objects of a particular type and returns a result
  170. // that follows the strcmp/memcmp.
  171. // If the type doesn't provide an operator== or operator< then you can provide
  172. // a type specific specialization to override this defualt functor !
  173. //
  174. template<typename T>
  175. struct ComparisonFunctor
  176. {
  177. int operator()(const T &lhs, const T &rhs) const
  178. {
  179. if( lhs == rhs )
  180. return 0 ;
  181. else if( lhs < rhs )
  182. return -1 ;
  183. else
  184. return 1 ;
  185. }
  186. };
  187. //
  188. // I expect people to build Comparison specializations for full types,
  189. // not pointer types - this Specialization should allow the C++ compiler
  190. // to bind to a specialization for a particular type.
  191. // We do not want to compare pointers for equality, and a memcmp() may
  192. // not be good for a complicated type !
  193. //
  194. template<typename T>
  195. struct ComparisonFunctor<T*>
  196. {
  197. int operator()(const T *lhs, const T *rhs) const
  198. {
  199. ComparisonFunctor<T> functor ;
  200. return functor(*lhs, *rhs) ;
  201. }
  202. };
  203. template<>
  204. struct ComparisonFunctor<int>
  205. {
  206. int operator()(const int lhs, const int rhs) const
  207. {
  208. return lhs-rhs ;
  209. }
  210. };
  211. template<>
  212. struct ComparisonFunctor<unsigned int>
  213. {
  214. int operator()(const unsigned int lhs, const unsigned int rhs) const
  215. {
  216. return static_cast<int>(lhs) - static_cast<int>(rhs) ;
  217. }
  218. };
  219. template<>
  220. struct ComparisonFunctor<uint64>
  221. {
  222. int operator()(const uint64 lhs, const uint64 rhs) const
  223. {
  224. if( lhs < rhs )
  225. return -1 ;
  226. else if( lhs == rhs )
  227. return 0 ;
  228. else
  229. return 1 ;
  230. }
  231. };
  232. template<>
  233. struct ComparisonFunctor<char*>
  234. {
  235. int operator()(const char * lhs, const char* rhs) const
  236. {
  237. return Q_strcmp(lhs, rhs) ;
  238. }
  239. };
  240. #endif // _PEARSONSHASH_H_