#pragma once #include #include #include #define __Utility_Hash_String__ //----------------------------------------------------------------------------- // Hash // 重点计算字符串的 Hash // 特别注意以下两点区别: // Hash (const char *) == std::hash (); // Hash (const wchar_t *) != std::hash (); // 另外, 这里计算的 Hash 结果都是 constexpr, 但是 std::hash <> () 的结果不一定是 constexpr //----------------------------------------------------------------------------- namespace ECOM::Utility { using tHash64 = size_t; // 64 位的 Hash using tHash32 = DWORD; // 32 位的 Hash constexpr tHash64 _FNV_offset_basis_64 = 14695981039346656037ULL; // 0xcbf29ce484222325 constexpr tHash64 _FNV_prime_64 = 1099511628211ULL; // 0x00000100000001b3 constexpr tHash32 _FNV_offset_basis_32 = 2166136261U; // 0x811c9dc5 constexpr tHash32 _FNV_prime_32 = 16777619U; // 0x01000193 template inline constexpr tHash64 Hash_Append (tHash64 Hash, const T * const _First) { for (auto p = _First; *p; p++) { Hash ^= static_cast (*p); Hash *= _FNV_prime_64; } return Hash; } template inline constexpr tHash32 Hash_Append (tHash32 Hash, const T * const _First) { for (auto p = _First; *p; p++) { Hash ^= static_cast (*p); Hash *= _FNV_prime_32; } return Hash; } template inline constexpr tHash64 Hash_Append (tHash64 Hash, const T * const _First, unsigned int nCount) { for (auto p = _First; nCount; p++, nCount --) { Hash ^= static_cast (*p); Hash *= _FNV_prime_64; } return Hash; } template inline constexpr tHash32 Hash_Append (tHash32 Hash, const T * const _First, unsigned int nCount) { for (auto p = _First; nCount; p++, nCount --) { Hash ^= static_cast (*p); Hash *= _FNV_prime_32; } return Hash; } template inline constexpr tHash64 Hash64 (const T * const _First) { return Hash_Append (_FNV_offset_basis_64, _First); } template inline constexpr tHash64 Hash64 (const T * const _First, unsigned int cnt) { return Hash_Append (_FNV_offset_basis_64, _First, cnt); } template inline constexpr tHash32 Hash32 (const T * const _First) { return Hash_Append (_FNV_offset_basis_32, _First); } template inline constexpr tHash32 Hash32 (const T * const _First, unsigned int cnt) { return Hash_Append (_FNV_offset_basis_32, _First, cnt); } inline constexpr tHash64 Hash_Append (tHash64 Hash, char ch) { Hash ^= static_cast (ch); Hash *= _FNV_prime_64; return Hash; } inline constexpr tHash32 Hash_Append (tHash32 Hash, char ch) { Hash ^= static_cast (ch); Hash *= _FNV_prime_32; return Hash; } inline constexpr tHash64 Hash_Append (tHash64 H, unsigned int v) { return Hash_Append (H, (const char *)&v, sizeof (v)); } inline constexpr tHash32 Hash_Append (tHash32 H, unsigned int v) { return Hash_Append (H, (const char *)&v, sizeof (v)); } inline constexpr tHash64 Hash_Append (tHash64 H, unsigned long v) { return Hash_Append (H, (const char *)&v, sizeof (v)); } inline constexpr tHash32 Hash_Append (tHash32 H, unsigned long v) { return Hash_Append (H, (const char *)&v, sizeof (v)); } inline constexpr tHash64 Hash_Append (tHash64 H, size_t v) { return Hash_Append (H, (const char *)&v, sizeof (v)); } inline constexpr tHash32 Hash_Append (tHash32 H, size_t v) { return Hash_Append (H, (const char *)&v, sizeof (v)); } inline constexpr tHash64 Hash64 (unsigned int v) { return Hash_Append (_FNV_offset_basis_64, (const char *)&v, sizeof (v)); } inline constexpr tHash32 Hash32 (unsigned int v) { return Hash_Append (_FNV_offset_basis_32, (const char *)&v, sizeof (v)); } template inline constexpr tHash64 Hash64 (std::initializer_list lst) { auto Hash = _FNV_offset_basis_64; for (const auto & it : lst) Hash = Hash_Append (Hash, it); return Hash; } template inline constexpr tHash32 Hash32 (std::initializer_list lst) { auto Hash = _FNV_offset_basis_32; for (const auto & it : lst) Hash = Hash_Append (Hash, it); return Hash; } #ifdef _WIN64 template inline constexpr tHash64 Hash (const T * const _First) { return Hash64 (_First); } template inline constexpr tHash64 Hash (const T * const _First, unsigned int cnt) { return Hash64 (_First, cnt); } template inline constexpr tHash64 Hash (const T * const _First, size_t cnt) { return Hash64 (_First, static_cast (cnt)); } inline constexpr tHash64 Hash (const std::string & _First) { return Hash64 (_First.c_str (), static_cast (_First.size ())); } inline constexpr tHash64 Hash (const std::string_view & _First) { return Hash64 (_First.data (), static_cast (_First.size ())); } template inline constexpr tHash64 Hash (std::initializer_list lst) { return Hash64 (lst); } #else inline constexpr tHash32 Hash (const char * const _First) { return Hash32 (_First); } inline constexpr tHash32 Hash (const char * const _First, unsigned int cn) { return Hash32 (_First, cn); } inline constexpr tHash32 Hash (const std::string & _First) { return Hash32 (_First.c_str (), _First.size ()); } inline constexpr tHash32 Hash (const wchar_t * const _First, unsigned int cnt) { return Hash32 (_First, cnt); } inline constexpr tHash32 Hash (const wchar_t * const _First, size_t cnt) { return Hash32 (_First, static_cast (cnt)); } #endif inline constexpr tHash64 BoostHash64 (const char * _First) { const tHash64 m = UINT64_C (0xc6a4a7935bd1e995); const int r = 47; tHash64 h = 0; for (auto p = _First; *p; p++) { tHash64 k = *p; k *= m; k ^= k >> r; k *= m; h ^= k; h *= m; // Completely arbitrary number, to prevent 0's // from hashing to 0. h += 0xe6546b64; } return h; } inline namespace Literals { inline constexpr size_t operator ""_hash (const char * str, size_t cn) noexcept { return Hash (str, static_cast (cn)); } } // 把 Hash 转换成 16 进制串. ch == 'x' 转成小写, ch == 'X' 转成大写 inline std::string ToHexString (char ch, tHash64 H) { constexpr auto NbOf8 = 8; constexpr auto NbOf32 = 2; union unHash64 { BYTE Hash8 [NbOf8]; // LOWLOW, LOW, HIGH, HIGHHIGH DWORD Hash32 [NbOf32]; // LOW, HIGH UINT64 Hash64; }; unHash64 un; un.Hash64 = H; std::stringstream s; s << std::setfill ('0') << std::hex; if (ch == 'X') s << std::uppercase; for (uint8_t i = 0; i < NbOf8; i++) s << std::setw (2) << (unsigned int) un.Hash8 [i]; return s.str (); } // 把 Hash 转换成 16 进制串. ch == 'x' 转成小写, ch == 'X' 转成大写 inline std::string ToHexString (char ch, tHash32 H) { constexpr auto NbOf8 = 4; union unHash32 { BYTE Hash8 [NbOf8]; // LOW, HIGH DWORD Hash32; }; unHash32 un; un.Hash32 = H; std::stringstream s; s << std::setfill ('0') << std::hex; if (ch == 'X') s << std::uppercase; for (uint8_t i = 0; i < NbOf8; i++) s << std::setw (2) << (unsigned int) un.Hash8 [i]; return s.str (); } // 把 Hash 转换成 16 进制串. ch == 'x' 转成小写, ch == 'X' 转成大写 inline std::string ToHexString (char ch, unsigned short H16) { constexpr auto NbOf8 = 2; union unHash16 { BYTE Hash8 [NbOf8]; // LOW, HIGH unsigned short Hash16; }; unHash16 un; un.Hash16 = H16; std::stringstream s; s << std::setfill ('0') << std::hex; if (ch == 'X') s << std::uppercase; s << std::setw (2) << (unsigned int) un.Hash8 [0]; s << std::setw (2) << (unsigned int) un.Hash8 [1]; return s.str (); } // 先计算字符串的 Hash, 然后把 Hash 转换成16 进制串. ch == 'x' 转成小写, ch == 'X' 转成大写 inline std::string ToHashToHexString (char ch, const char * str) { auto H = Hash (str); return ToHexString (ch, H); } } /* [2023-09-02] Hash64 的性能: 1. 与字符串长度几乎无关 2. 循环 1M 次, 耗时约 2.2 毫秒 3. 性能非常好 如下测试代码, 输出日志为: es of Hash of 64 : 2297 es of Hash of 128 : 2297 es of Hash of 256 : 2296 es of Hash of 512 : 2313 es of Hash of 4096 : 2297 es of Hash of 64 : 2312 es of Hash of 128 : 2297 es of Hash of 256 : 2282 es of Hash of 512 : 2250 es of Hash of 4096 : 2281 es of Hash of 64 : 2265 es of Hash of 128 : 2266 es of Hash of 256 : 2234 es of Hash of 512 : 2281 es of Hash of 4096 : 2235 static void TestHash_ES (int MaxLen) { eSTR::DString str; auto * pc = str.GetBufferSetLength (MaxLen); for (int Index = 0; Index < MaxLen; Index++) { *pc = 'A'; pc++; } auto start = GetTickCount (); for (int Index = 0; Index < 1000 * 1000 * 1000; Index++) { auto h = ECOM::Utility::Hash (str); } auto es = GetTickCount () - start; str.Format ("es of Hash of {$}: {$}"_sv, MaxLen, es); puts (str); } void TestHash () { TestHash_ES (64); TestHash_ES (128); TestHash_ES (256); TestHash_ES (512); TestHash_ES (4096); } */