Hash.String.hpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. #pragma once
  2. #include <string>
  3. #include <sstream>
  4. #include <iomanip>
  5. #define __Utility_Hash_String__
  6. //-----------------------------------------------------------------------------
  7. // Hash
  8. // 重点计算字符串的 Hash
  9. // 特别注意以下两点区别:
  10. // Hash (const char *) == std::hash <std::string> ();
  11. // Hash (const wchar_t *) != std::hash <std::wstring> ();
  12. // 另外, 这里计算的 Hash 结果都是 constexpr, 但是 std::hash <> () 的结果不一定是 constexpr
  13. //-----------------------------------------------------------------------------
  14. namespace ECOM::Utility
  15. {
  16. using tHash64 = size_t; // 64 位的 Hash
  17. using tHash32 = DWORD; // 32 位的 Hash
  18. constexpr tHash64 _FNV_offset_basis_64 = 14695981039346656037ULL; // 0xcbf29ce484222325
  19. constexpr tHash64 _FNV_prime_64 = 1099511628211ULL; // 0x00000100000001b3
  20. constexpr tHash32 _FNV_offset_basis_32 = 2166136261U; // 0x811c9dc5
  21. constexpr tHash32 _FNV_prime_32 = 16777619U; // 0x01000193
  22. template <typename T>
  23. inline constexpr tHash64 Hash_Append (tHash64 Hash, const T * const _First)
  24. {
  25. for (auto p = _First; *p; p++)
  26. {
  27. Hash ^= static_cast <tHash64> (*p);
  28. Hash *= _FNV_prime_64;
  29. }
  30. return Hash;
  31. }
  32. template <typename T>
  33. inline constexpr tHash32 Hash_Append (tHash32 Hash, const T * const _First)
  34. {
  35. for (auto p = _First; *p; p++)
  36. {
  37. Hash ^= static_cast <tHash32> (*p);
  38. Hash *= _FNV_prime_32;
  39. }
  40. return Hash;
  41. }
  42. template <typename T>
  43. inline constexpr tHash64 Hash_Append (tHash64 Hash, const T * const _First, unsigned int nCount)
  44. {
  45. for (auto p = _First; nCount; p++, nCount --)
  46. {
  47. Hash ^= static_cast <tHash64> (*p);
  48. Hash *= _FNV_prime_64;
  49. }
  50. return Hash;
  51. }
  52. template <typename T>
  53. inline constexpr tHash32 Hash_Append (tHash32 Hash, const T * const _First, unsigned int nCount)
  54. {
  55. for (auto p = _First; nCount; p++, nCount --)
  56. {
  57. Hash ^= static_cast <tHash32> (*p);
  58. Hash *= _FNV_prime_32;
  59. }
  60. return Hash;
  61. }
  62. template <typename T>
  63. inline constexpr tHash64 Hash64 (const T * const _First)
  64. {
  65. return Hash_Append (_FNV_offset_basis_64, _First);
  66. }
  67. template <typename T>
  68. inline constexpr tHash64 Hash64 (const T * const _First, unsigned int cnt)
  69. {
  70. return Hash_Append (_FNV_offset_basis_64, _First, cnt);
  71. }
  72. template <typename T>
  73. inline constexpr tHash32 Hash32 (const T * const _First)
  74. {
  75. return Hash_Append (_FNV_offset_basis_32, _First);
  76. }
  77. template <typename T>
  78. inline constexpr tHash32 Hash32 (const T * const _First, unsigned int cnt)
  79. {
  80. return Hash_Append (_FNV_offset_basis_32, _First, cnt);
  81. }
  82. inline constexpr tHash64 Hash_Append (tHash64 Hash, char ch)
  83. {
  84. Hash ^= static_cast <tHash64> (ch);
  85. Hash *= _FNV_prime_64;
  86. return Hash;
  87. }
  88. inline constexpr tHash32 Hash_Append (tHash32 Hash, char ch)
  89. {
  90. Hash ^= static_cast <tHash32> (ch);
  91. Hash *= _FNV_prime_32;
  92. return Hash;
  93. }
  94. inline constexpr tHash64 Hash_Append (tHash64 H, unsigned int v)
  95. {
  96. return Hash_Append (H, (const char *)&v, sizeof (v));
  97. }
  98. inline constexpr tHash32 Hash_Append (tHash32 H, unsigned int v)
  99. {
  100. return Hash_Append (H, (const char *)&v, sizeof (v));
  101. }
  102. inline constexpr tHash64 Hash_Append (tHash64 H, unsigned long v)
  103. {
  104. return Hash_Append (H, (const char *)&v, sizeof (v));
  105. }
  106. inline constexpr tHash32 Hash_Append (tHash32 H, unsigned long v)
  107. {
  108. return Hash_Append (H, (const char *)&v, sizeof (v));
  109. }
  110. inline constexpr tHash64 Hash_Append (tHash64 H, size_t v)
  111. {
  112. return Hash_Append (H, (const char *)&v, sizeof (v));
  113. }
  114. inline constexpr tHash32 Hash_Append (tHash32 H, size_t v)
  115. {
  116. return Hash_Append (H, (const char *)&v, sizeof (v));
  117. }
  118. inline constexpr tHash64 Hash64 (unsigned int v)
  119. {
  120. return Hash_Append (_FNV_offset_basis_64, (const char *)&v, sizeof (v));
  121. }
  122. inline constexpr tHash32 Hash32 (unsigned int v)
  123. {
  124. return Hash_Append (_FNV_offset_basis_32, (const char *)&v, sizeof (v));
  125. }
  126. template <typename T>
  127. inline constexpr tHash64 Hash64 (std::initializer_list <T> lst)
  128. {
  129. auto Hash = _FNV_offset_basis_64;
  130. for (const auto & it : lst)
  131. Hash = Hash_Append (Hash, it);
  132. return Hash;
  133. }
  134. template <typename T>
  135. inline constexpr tHash32 Hash32 (std::initializer_list <T> lst)
  136. {
  137. auto Hash = _FNV_offset_basis_32;
  138. for (const auto & it : lst)
  139. Hash = Hash_Append (Hash, it);
  140. return Hash;
  141. }
  142. #ifdef _WIN64
  143. template <typename T>
  144. inline constexpr tHash64 Hash (const T * const _First)
  145. {
  146. return Hash64 (_First);
  147. }
  148. template <typename T>
  149. inline constexpr tHash64 Hash (const T * const _First, unsigned int cnt)
  150. {
  151. return Hash64 (_First, cnt);
  152. }
  153. template <typename T>
  154. inline constexpr tHash64 Hash (const T * const _First, size_t cnt)
  155. {
  156. return Hash64 (_First, static_cast <int> (cnt));
  157. }
  158. inline constexpr tHash64 Hash (const std::string & _First)
  159. {
  160. return Hash64 (_First.c_str (), static_cast <int> (_First.size ()));
  161. }
  162. inline constexpr tHash64 Hash (const std::string_view & _First)
  163. {
  164. return Hash64 (_First.data (), static_cast <int> (_First.size ()));
  165. }
  166. template <typename T>
  167. inline constexpr tHash64 Hash (std::initializer_list <T> lst)
  168. {
  169. return Hash64 (lst);
  170. }
  171. #else
  172. inline constexpr tHash32 Hash (const char * const _First)
  173. {
  174. return Hash32 (_First);
  175. }
  176. inline constexpr tHash32 Hash (const char * const _First, unsigned int cn)
  177. {
  178. return Hash32 (_First, cn);
  179. }
  180. inline constexpr tHash32 Hash (const std::string & _First)
  181. {
  182. return Hash32 (_First.c_str (), _First.size ());
  183. }
  184. inline constexpr tHash32 Hash (const wchar_t * const _First, unsigned int cnt)
  185. {
  186. return Hash32 (_First, cnt);
  187. }
  188. inline constexpr tHash32 Hash (const wchar_t * const _First, size_t cnt)
  189. {
  190. return Hash32 (_First, static_cast <int> (cnt));
  191. }
  192. #endif
  193. inline constexpr tHash64 BoostHash64 (const char * _First)
  194. {
  195. const tHash64 m = UINT64_C (0xc6a4a7935bd1e995);
  196. const int r = 47;
  197. tHash64 h = 0;
  198. for (auto p = _First; *p; p++)
  199. {
  200. tHash64 k = *p;
  201. k *= m;
  202. k ^= k >> r;
  203. k *= m;
  204. h ^= k;
  205. h *= m;
  206. // Completely arbitrary number, to prevent 0's
  207. // from hashing to 0.
  208. h += 0xe6546b64;
  209. }
  210. return h;
  211. }
  212. inline namespace Literals
  213. {
  214. inline constexpr size_t operator ""_hash (const char * str, size_t cn) noexcept
  215. {
  216. return Hash (str, static_cast <unsigned int> (cn));
  217. }
  218. }
  219. // 把 Hash 转换成 16 进制串. ch == 'x' 转成小写, ch == 'X' 转成大写
  220. inline std::string ToHexString (char ch, tHash64 H)
  221. {
  222. constexpr auto NbOf8 = 8;
  223. constexpr auto NbOf32 = 2;
  224. union unHash64
  225. {
  226. BYTE Hash8 [NbOf8]; // LOWLOW, LOW, HIGH, HIGHHIGH
  227. DWORD Hash32 [NbOf32]; // LOW, HIGH
  228. UINT64 Hash64;
  229. };
  230. unHash64 un; un.Hash64 = H;
  231. std::stringstream s;
  232. s << std::setfill ('0') << std::hex;
  233. if (ch == 'X') s << std::uppercase;
  234. for (uint8_t i = 0; i < NbOf8; i++)
  235. s << std::setw (2) << (unsigned int) un.Hash8 [i];
  236. return s.str ();
  237. }
  238. // 把 Hash 转换成 16 进制串. ch == 'x' 转成小写, ch == 'X' 转成大写
  239. inline std::string ToHexString (char ch, tHash32 H)
  240. {
  241. constexpr auto NbOf8 = 4;
  242. union unHash32
  243. {
  244. BYTE Hash8 [NbOf8]; // LOW, HIGH
  245. DWORD Hash32;
  246. };
  247. unHash32 un; un.Hash32 = H;
  248. std::stringstream s;
  249. s << std::setfill ('0') << std::hex;
  250. if (ch == 'X') s << std::uppercase;
  251. for (uint8_t i = 0; i < NbOf8; i++)
  252. s << std::setw (2) << (unsigned int) un.Hash8 [i];
  253. return s.str ();
  254. }
  255. // 把 Hash 转换成 16 进制串. ch == 'x' 转成小写, ch == 'X' 转成大写
  256. inline std::string ToHexString (char ch, unsigned short H16)
  257. {
  258. constexpr auto NbOf8 = 2;
  259. union unHash16
  260. {
  261. BYTE Hash8 [NbOf8]; // LOW, HIGH
  262. unsigned short Hash16;
  263. };
  264. unHash16 un; un.Hash16 = H16;
  265. std::stringstream s;
  266. s << std::setfill ('0') << std::hex;
  267. if (ch == 'X') s << std::uppercase;
  268. s << std::setw (2) << (unsigned int) un.Hash8 [0];
  269. s << std::setw (2) << (unsigned int) un.Hash8 [1];
  270. return s.str ();
  271. }
  272. // 先计算字符串的 Hash, 然后把 Hash 转换成16 进制串. ch == 'x' 转成小写, ch == 'X' 转成大写
  273. inline std::string ToHashToHexString (char ch, const char * str)
  274. {
  275. auto H = Hash (str);
  276. return ToHexString (ch, H);
  277. }
  278. }
  279. /*
  280. [2023-09-02]
  281. Hash64 的性能:
  282. 1. 与字符串长度几乎无关
  283. 2. 循环 1M 次, 耗时约 2.2 毫秒
  284. 3. 性能非常好
  285. 如下测试代码, 输出日志为:
  286. es of Hash of 64 : 2297
  287. es of Hash of 128 : 2297
  288. es of Hash of 256 : 2296
  289. es of Hash of 512 : 2313
  290. es of Hash of 4096 : 2297
  291. es of Hash of 64 : 2312
  292. es of Hash of 128 : 2297
  293. es of Hash of 256 : 2282
  294. es of Hash of 512 : 2250
  295. es of Hash of 4096 : 2281
  296. es of Hash of 64 : 2265
  297. es of Hash of 128 : 2266
  298. es of Hash of 256 : 2234
  299. es of Hash of 512 : 2281
  300. es of Hash of 4096 : 2235
  301. static void TestHash_ES (int MaxLen)
  302. {
  303. eSTR::DString str;
  304. auto * pc = str.GetBufferSetLength (MaxLen);
  305. for (int Index = 0; Index < MaxLen; Index++)
  306. {
  307. *pc = 'A';
  308. pc++;
  309. }
  310. auto start = GetTickCount ();
  311. for (int Index = 0; Index < 1000 * 1000 * 1000; Index++)
  312. {
  313. auto h = ECOM::Utility::Hash (str);
  314. }
  315. auto es = GetTickCount () - start;
  316. str.Format ("es of Hash of {$}: {$}"_sv, MaxLen, es);
  317. puts (str);
  318. }
  319. void TestHash ()
  320. {
  321. TestHash_ES (64);
  322. TestHash_ES (128);
  323. TestHash_ES (256);
  324. TestHash_ES (512);
  325. TestHash_ES (4096);
  326. }
  327. */