123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435 |
- #pragma once
- #include <string>
- #include <sstream>
- #include <iomanip>
- #define __Utility_Hash_String__
- //-----------------------------------------------------------------------------
- // Hash
- // 重点计算字符串的 Hash
- // 特别注意以下两点区别:
- // Hash (const char *) == std::hash <std::string> ();
- // Hash (const wchar_t *) != std::hash <std::wstring> ();
- // 另外, 这里计算的 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 <typename T>
- inline constexpr tHash64 Hash_Append (tHash64 Hash, const T * const _First)
- {
- for (auto p = _First; *p; p++)
- {
- Hash ^= static_cast <tHash64> (*p);
- Hash *= _FNV_prime_64;
- }
- return Hash;
- }
- template <typename T>
- inline constexpr tHash32 Hash_Append (tHash32 Hash, const T * const _First)
- {
- for (auto p = _First; *p; p++)
- {
- Hash ^= static_cast <tHash32> (*p);
- Hash *= _FNV_prime_32;
- }
- return Hash;
- }
- template <typename T>
- inline constexpr tHash64 Hash_Append (tHash64 Hash, const T * const _First, unsigned int nCount)
- {
- for (auto p = _First; nCount; p++, nCount --)
- {
- Hash ^= static_cast <tHash64> (*p);
- Hash *= _FNV_prime_64;
- }
- return Hash;
- }
- template <typename T>
- inline constexpr tHash32 Hash_Append (tHash32 Hash, const T * const _First, unsigned int nCount)
- {
- for (auto p = _First; nCount; p++, nCount --)
- {
- Hash ^= static_cast <tHash32> (*p);
- Hash *= _FNV_prime_32;
- }
- return Hash;
- }
- template <typename T>
- inline constexpr tHash64 Hash64 (const T * const _First)
- {
- return Hash_Append (_FNV_offset_basis_64, _First);
- }
- template <typename T>
- inline constexpr tHash64 Hash64 (const T * const _First, unsigned int cnt)
- {
- return Hash_Append (_FNV_offset_basis_64, _First, cnt);
- }
- template <typename T>
- inline constexpr tHash32 Hash32 (const T * const _First)
- {
- return Hash_Append (_FNV_offset_basis_32, _First);
- }
- template <typename T>
- 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 <tHash64> (ch);
- Hash *= _FNV_prime_64;
- return Hash;
- }
- inline constexpr tHash32 Hash_Append (tHash32 Hash, char ch)
- {
- Hash ^= static_cast <tHash32> (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 <typename T>
- inline constexpr tHash64 Hash64 (std::initializer_list <T> lst)
- {
- auto Hash = _FNV_offset_basis_64;
- for (const auto & it : lst)
- Hash = Hash_Append (Hash, it);
- return Hash;
- }
- template <typename T>
- inline constexpr tHash32 Hash32 (std::initializer_list <T> lst)
- {
- auto Hash = _FNV_offset_basis_32;
- for (const auto & it : lst)
- Hash = Hash_Append (Hash, it);
- return Hash;
- }
- #ifdef _WIN64
- template <typename T>
- inline constexpr tHash64 Hash (const T * const _First)
- {
- return Hash64 (_First);
- }
- template <typename T>
- inline constexpr tHash64 Hash (const T * const _First, unsigned int cnt)
- {
- return Hash64 (_First, cnt);
- }
- template <typename T>
- inline constexpr tHash64 Hash (const T * const _First, size_t cnt)
- {
- return Hash64 (_First, static_cast <int> (cnt));
- }
- inline constexpr tHash64 Hash (const std::string & _First)
- {
- return Hash64 (_First.c_str (), static_cast <int> (_First.size ()));
- }
- inline constexpr tHash64 Hash (const std::string_view & _First)
- {
- return Hash64 (_First.data (), static_cast <int> (_First.size ()));
- }
- template <typename T>
- inline constexpr tHash64 Hash (std::initializer_list <T> 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 <int> (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 <unsigned int> (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);
- }
- */
|