mirror of
https://github.com/thunderbrewhq/squall.git
synced 2026-02-04 00:49:08 +00:00
feat(string): add SStrHash64
This commit is contained in:
parent
a36aded763
commit
0250f274ca
6 changed files with 235 additions and 1 deletions
|
|
@ -38,6 +38,7 @@ if(WHOA_STORM_FLAVOR STREQUAL "SC1")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_definitions(-DWHOA_RECT_USES_SCREEN_COORDINATES)
|
add_definitions(-DWHOA_RECT_USES_SCREEN_COORDINATES)
|
||||||
|
add_definitions(-DWHOA_SSTRHASH64_SUBTRACTS)
|
||||||
elseif(WHOA_STORM_FLAVOR STREQUAL "WOW")
|
elseif(WHOA_STORM_FLAVOR STREQUAL "WOW")
|
||||||
message(STATUS "Building Storm with World of Warcraft flavoring")
|
message(STATUS "Building Storm with World of Warcraft flavoring")
|
||||||
else()
|
else()
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,13 @@ const uint32_t s_hashtable[16] = {
|
||||||
0xE3061AE7, 0xA39B0FA1, 0x9797F25F, 0xE4444563,
|
0xE3061AE7, 0xA39B0FA1, 0x9797F25F, 0xE4444563,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const uint64_t s_hashtable64[16] = {
|
||||||
|
0x486E26EEDCAA16B3ULL, 0xE1918EEF202DAFDBULL, 0x341C7DC71C365303ULL, 0x40EF2D3765FD5E49ULL,
|
||||||
|
0xD6057177904ECE93ULL, 0x1C38024F98FD323BULL, 0xE3061AE7A39B0FA1ULL, 0x9797F25FE4444563ULL,
|
||||||
|
0xCD2EC20C8DC1B898ULL, 0x31759633799A306DULL, 0x8C2063852E6E9627ULL, 0x79237D9973922C66ULL,
|
||||||
|
0x8728628D28628824ULL, 0x8F1F7E9625887795ULL, 0x296E3281389C0D60ULL, 0x6F4893CA61636542ULL,
|
||||||
|
};
|
||||||
|
|
||||||
void GetNextTextUpper(uint32_t* orig, const char** string, uint32_t* upper) {
|
void GetNextTextUpper(uint32_t* orig, const char** string, uint32_t* upper) {
|
||||||
uint8_t byte = **string;
|
uint8_t byte = **string;
|
||||||
int32_t v3 = bytesFromUTF8[byte];
|
int32_t v3 = bytesFromUTF8[byte];
|
||||||
|
|
@ -423,6 +430,50 @@ uint32_t STORMAPI SStrHashHT(const char* string) {
|
||||||
return bjhash((uint8_t*)&normalized, length, 0);
|
return bjhash((uint8_t*)&normalized, length, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t STORMAPI SStrHash64(const char* string, uint32_t flags, int64_t seed) {
|
||||||
|
STORM_VALIDATE_BEGIN;
|
||||||
|
STORM_VALIDATE(string);
|
||||||
|
STORM_VALIDATE_END;
|
||||||
|
|
||||||
|
int64_t result = seed ? seed : 0x7FED7FED7FED7FEDLL;
|
||||||
|
int64_t adjust = 0xEEEEEEEEEEEEEEEELL;
|
||||||
|
uint32_t ch;
|
||||||
|
|
||||||
|
if (flags & SSTR_HASH_CASESENSITIVE) {
|
||||||
|
for (; *string; string++) {
|
||||||
|
ch = static_cast<uint8_t>(*string);
|
||||||
|
|
||||||
|
#if defined(WHOA_SSTRHASH64_SUBTRACTS)
|
||||||
|
result = (s_hashtable64[ch / 16] - s_hashtable64[ch % 16]) ^ (adjust + result);
|
||||||
|
#else
|
||||||
|
result = (s_hashtable64[ch / 16] + s_hashtable64[ch % 16]) ^ (adjust + result);
|
||||||
|
#endif
|
||||||
|
adjust = 33 * adjust + result + ch + 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (; *string; string++) {
|
||||||
|
ch = static_cast<uint8_t>(*string);
|
||||||
|
|
||||||
|
if (ch >= 'a' && ch <= 'z') {
|
||||||
|
ch -= 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ch == '/') {
|
||||||
|
ch = '\\';
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(WHOA_SSTRHASH64_SUBTRACTS)
|
||||||
|
result = (s_hashtable64[ch / 16] - s_hashtable64[ch % 16]) ^ (adjust + result);
|
||||||
|
#else
|
||||||
|
result = (s_hashtable64[ch / 16] + s_hashtable64[ch % 16]) ^ (adjust + result);
|
||||||
|
#endif
|
||||||
|
adjust = 33 * adjust + result + ch + 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result ? result : 1LL;
|
||||||
|
}
|
||||||
|
|
||||||
size_t STORMAPI SStrLen(const char* string) {
|
size_t STORMAPI SStrLen(const char* string) {
|
||||||
STORM_VALIDATE_BEGIN;
|
STORM_VALIDATE_BEGIN;
|
||||||
STORM_VALIDATE(string);
|
STORM_VALIDATE(string);
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,8 @@ uint32_t STORMAPI SStrHash(const char* string, uint32_t flags = 0, uint32_t seed
|
||||||
|
|
||||||
uint32_t STORMAPI SStrHashHT(const char* string);
|
uint32_t STORMAPI SStrHashHT(const char* string);
|
||||||
|
|
||||||
|
int64_t STORMAPI SStrHash64(const char* string, uint32_t flags = 0, int64_t seed = 0);
|
||||||
|
|
||||||
size_t STORMAPI SStrLen(const char* string);
|
size_t STORMAPI SStrLen(const char* string);
|
||||||
|
|
||||||
void STORMAPI SStrLower(char* string);
|
void STORMAPI SStrLower(char* string);
|
||||||
|
|
|
||||||
179
test/String.cpp
179
test/String.cpp
|
|
@ -257,6 +257,11 @@ struct TestHash {
|
||||||
uint32_t hash;
|
uint32_t hash;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TestHash64 {
|
||||||
|
const char* str;
|
||||||
|
uint64_t hash;
|
||||||
|
};
|
||||||
|
|
||||||
TEST_CASE("SStrHash", "[string]") {
|
TEST_CASE("SStrHash", "[string]") {
|
||||||
SECTION("hashes strings with case insensitivity") {
|
SECTION("hashes strings with case insensitivity") {
|
||||||
// Results obtained by directly calling Starcraft 1.17's SStrHash
|
// Results obtained by directly calling Starcraft 1.17's SStrHash
|
||||||
|
|
@ -373,6 +378,180 @@ TEST_CASE("SStrHashHT", "[string]") {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
TEST_CASE("SStrHash64", "[string]") {
|
||||||
|
#if defined(WHOA_SSTRHASH64_SUBTRACTS)
|
||||||
|
SECTION("hashes strings with case insensitivity") {
|
||||||
|
// Results obtained by directly calling Starcraft 1.17's SStrHash64
|
||||||
|
auto testcase = GENERATE(
|
||||||
|
TestHash64{ "bloop bloop", 0xE14D89BC96BA2B0DULL },
|
||||||
|
TestHash64{ "BLOOP bloop", 0xE14D89BC96BA2B0DULL },
|
||||||
|
TestHash64{ "Objects\\CameraHelper\\CameraHelper.mdx", 0x7759083272301974ULL },
|
||||||
|
TestHash64{ "Objects/CameraHelper/CameraHelper.mdx", 0x7759083272301974ULL },
|
||||||
|
TestHash64{ "abcdefghijklmnopqrstuvwxyz", 0x73D40422F72E5B88ULL },
|
||||||
|
TestHash64{ "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0x73D40422F72E5B88ULL },
|
||||||
|
TestHash64{ "123456789~!@#$%^&*()_+`-=[]{}|;':\",.<>?", 0x71E9A046243BE465ULL },
|
||||||
|
TestHash64{ "/", 0xFBD3F11E1E46C4CCULL },
|
||||||
|
TestHash64{ "\\", 0xFBD3F11E1E46C4CCULL },
|
||||||
|
TestHash64{ "\r\n\t ", 0xA739BEA33457DEECULL }
|
||||||
|
);
|
||||||
|
|
||||||
|
auto hash = SStrHash64(testcase.str);
|
||||||
|
CHECK(hash == testcase.hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("hashes strings with case sensitivity") {
|
||||||
|
// Results obtained by directly calling Starcraft 1.17's SStrHash64
|
||||||
|
auto testcase = GENERATE(
|
||||||
|
TestHash64{ "bloop bloop", 0x4F12AE31024D45F9ULL },
|
||||||
|
TestHash64{ "BLOOP bloop", 0x5D851E9D86AE9B9DULL },
|
||||||
|
TestHash64{ "Objects\\CameraHelper\\CameraHelper.mdx", 0xA90280432B37C9C0ULL },
|
||||||
|
TestHash64{ "Objects/CameraHelper/CameraHelper.mdx", 0x76D3CB7BEEA8D106ULL },
|
||||||
|
TestHash64{ "abcdefghijklmnopqrstuvwxyz", 0xA6A43E35042C251CULL },
|
||||||
|
TestHash64{ "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0x73D40422F72E5B88ULL },
|
||||||
|
TestHash64{ "123456789~!@#$%^&*()_+`-=[]{}|;':\",.<>?", 0x71E9A046243BE465ULL },
|
||||||
|
TestHash64{ "/", 0xAA0F8720D40E831AULL },
|
||||||
|
TestHash64{ "\\", 0xFBD3F11E1E46C4CCULL },
|
||||||
|
TestHash64{ "\r\n\t ", 0xA739BEA33457DEECULL }
|
||||||
|
);
|
||||||
|
|
||||||
|
auto hash = SStrHash64(testcase.str, SSTR_HASH_CASESENSITIVE);
|
||||||
|
CHECK(hash == testcase.hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("hashes strings with fixed seeds case insensitive") {
|
||||||
|
// Results obtained by directly calling Starcraft 1.17's SStrHash64
|
||||||
|
auto testcase = GENERATE(
|
||||||
|
TestHash64{ "bloop bloop", 0x03D3898FEC03C4D9ULL },
|
||||||
|
TestHash64{ "BLOOP bloop", 0x03D3898FEC03C4D9ULL },
|
||||||
|
TestHash64{ "Objects\\CameraHelper\\CameraHelper.mdx", 0xCEACEDE00D62B2B6ULL },
|
||||||
|
TestHash64{ "Objects/CameraHelper/CameraHelper.mdx", 0xCEACEDE00D62B2B6ULL },
|
||||||
|
TestHash64{ "abcdefghijklmnopqrstuvwxyz", 0xA39E182D711E5D58ULL },
|
||||||
|
TestHash64{ "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0xA39E182D711E5D58ULL },
|
||||||
|
TestHash64{ "123456789~!@#$%^&*()_+`-=[]{}|;':\",.<>?", 0x5BF56F80621C969BULL },
|
||||||
|
TestHash64{ "/", 0x7BE1712C9E74457EULL },
|
||||||
|
TestHash64{ "\\", 0x7BE1712C9E74457EULL },
|
||||||
|
TestHash64{ "\r\n\t ", 0xEE8A467B9D01DE46ULL }
|
||||||
|
);
|
||||||
|
|
||||||
|
auto hash = SStrHash64(testcase.str, 0, 123LL);
|
||||||
|
CHECK(hash == testcase.hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("hashes strings with fixed seeds case sensitive") {
|
||||||
|
// Results obtained by directly calling Starcraft 1.17's SStrHash64
|
||||||
|
auto testcase = GENERATE(
|
||||||
|
TestHash64{ "bloop bloop", 0x6FFDAAD262D140BDULL },
|
||||||
|
TestHash64{ "BLOOP bloop", 0xF300F24AB99DFB15ULL },
|
||||||
|
TestHash64{ "Objects\\CameraHelper\\CameraHelper.mdx", 0xAE42461A0E6433CEULL },
|
||||||
|
TestHash64{ "Objects/CameraHelper/CameraHelper.mdx", 0x19E9DB9ACCD45BDCULL },
|
||||||
|
TestHash64{ "abcdefghijklmnopqrstuvwxyz", 0x1666B3E05FB2DCA8ULL },
|
||||||
|
TestHash64{ "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0xA39E182D711E5D58ULL },
|
||||||
|
TestHash64{ "123456789~!@#$%^&*()_+`-=[]{}|;':\",.<>?", 0x5BF56F80621C969BULL },
|
||||||
|
TestHash64{ "/", 0x2A3D0712543C02A8ULL },
|
||||||
|
TestHash64{ "\\", 0x7BE1712C9E74457EULL },
|
||||||
|
TestHash64{ "\r\n\t ", 0xEE8A467B9D01DE46ULL }
|
||||||
|
);
|
||||||
|
|
||||||
|
auto hash = SStrHash64(testcase.str, SSTR_HASH_CASESENSITIVE, 123);
|
||||||
|
CHECK(hash == testcase.hash);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
SECTION("hashes strings with case insensitivity") {
|
||||||
|
// Results unverified
|
||||||
|
auto testcase = GENERATE(
|
||||||
|
TestHash64{ "bloop bloop", 0x84FD59305F3877FFULL },
|
||||||
|
TestHash64{ "BLOOP bloop", 0x84FD59305F3877FFULL },
|
||||||
|
TestHash64{ "Objects\\CameraHelper\\CameraHelper.mdx", 0x2B34AA2D06B98C8EULL },
|
||||||
|
TestHash64{ "Objects/CameraHelper/CameraHelper.mdx", 0x2B34AA2D06B98C8EULL },
|
||||||
|
TestHash64{ "abcdefghijklmnopqrstuvwxyz", 0x8E7D62B3AD83962AULL },
|
||||||
|
TestHash64{ "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0x8E7D62B3AD83962AULL },
|
||||||
|
TestHash64{ "123456789~!@#$%^&*()_+`-=[]{}|;':\",.<>?", 0xC0B7B00ECE9E2F07ULL },
|
||||||
|
TestHash64{ "/", 0xCDBC0A00AF83D484ULL },
|
||||||
|
TestHash64{ "\\", 0xCDBC0A00AF83D484ULL },
|
||||||
|
TestHash64{ "\r\n\t ", 0xD8904DDFC816244AULL }
|
||||||
|
);
|
||||||
|
|
||||||
|
auto hash = SStrHash64(testcase.str);
|
||||||
|
CHECK(hash == testcase.hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("hashes strings with case sensitivity") {
|
||||||
|
// Results unverified
|
||||||
|
auto testcase = GENERATE(
|
||||||
|
TestHash64{ "bloop bloop", 0xBBB2156CEDE15737ULL },
|
||||||
|
TestHash64{ "BLOOP bloop", 0x535CFCB6D2D7F37BULL },
|
||||||
|
TestHash64{ "Objects\\CameraHelper\\CameraHelper.mdx", 0x5302DB8D4BA78ABAULL },
|
||||||
|
TestHash64{ "Objects/CameraHelper/CameraHelper.mdx", 0xE8BF631EA4E66D58ULL },
|
||||||
|
TestHash64{ "abcdefghijklmnopqrstuvwxyz", 0x7D8899096CB4CC02ULL },
|
||||||
|
TestHash64{ "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0x8E7D62B3AD83962AULL },
|
||||||
|
TestHash64{ "123456789~!@#$%^&*()_+`-=[]{}|;':\",.<>?", 0xC0B7B00ECE9E2F07ULL },
|
||||||
|
TestHash64{ "/", 0xCDB97F4D1345D69EULL },
|
||||||
|
TestHash64{ "\\", 0xCDBC0A00AF83D484ULL },
|
||||||
|
TestHash64{ "\r\n\t ", 0xD8904DDFC816244AULL }
|
||||||
|
);
|
||||||
|
|
||||||
|
auto hash = SStrHash64(testcase.str, SSTR_HASH_CASESENSITIVE);
|
||||||
|
CHECK(hash == testcase.hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("hashes strings with fixed seeds case insensitive") {
|
||||||
|
// Results unverified
|
||||||
|
auto testcase = GENERATE(
|
||||||
|
TestHash64{ "bloop bloop", 0xC6F40635E6E3C117ULL },
|
||||||
|
TestHash64{ "BLOOP bloop", 0xC6F40635E6E3C117ULL },
|
||||||
|
TestHash64{ "Objects\\CameraHelper\\CameraHelper.mdx", 0x6451F965B5D0FD5CULL },
|
||||||
|
TestHash64{ "Objects/CameraHelper/CameraHelper.mdx", 0x6451F965B5D0FD5CULL },
|
||||||
|
TestHash64{ "abcdefghijklmnopqrstuvwxyz", 0x203432E33CF40F76ULL },
|
||||||
|
TestHash64{ "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0x203432E33CF40F76ULL },
|
||||||
|
TestHash64{ "123456789~!@#$%^&*()_+`-=[]{}|;':\",.<>?", 0xC3891C1567328CB1ULL },
|
||||||
|
TestHash64{ "/", 0x4D8E8A322FB15536ULL },
|
||||||
|
TestHash64{ "\\", 0x4D8E8A322FB15536ULL },
|
||||||
|
TestHash64{ "\r\n\t ", 0x2406686F9A68C604ULL }
|
||||||
|
);
|
||||||
|
|
||||||
|
auto hash = SStrHash64(testcase.str, 0, 123LL);
|
||||||
|
CHECK(hash == testcase.hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("hashes strings with fixed seeds case sensitive") {
|
||||||
|
// Results unverified
|
||||||
|
auto testcase = GENERATE(
|
||||||
|
TestHash64{ "bloop bloop", 0xE57741252C85E807ULL },
|
||||||
|
TestHash64{ "BLOOP bloop", 0x904B2F5E071239EFULL },
|
||||||
|
TestHash64{ "Objects\\CameraHelper\\CameraHelper.mdx", 0xEA1C02D18CA081F4ULL },
|
||||||
|
TestHash64{ "Objects/CameraHelper/CameraHelper.mdx", 0x391D997C0A76FB82ULL },
|
||||||
|
TestHash64{ "abcdefghijklmnopqrstuvwxyz", 0x2416669E47057DB2ULL },
|
||||||
|
TestHash64{ "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0x203432E33CF40F76ULL },
|
||||||
|
TestHash64{ "123456789~!@#$%^&*()_+`-=[]{}|;':\",.<>?", 0xC3891C1567328CB1ULL },
|
||||||
|
TestHash64{ "/", 0x4D8BFF7F9377572CULL },
|
||||||
|
TestHash64{ "\\", 0x4D8E8A322FB15536ULL },
|
||||||
|
TestHash64{ "\r\n\t ", 0x2406686F9A68C604ULL }
|
||||||
|
);
|
||||||
|
|
||||||
|
auto hash = SStrHash64(testcase.str, SSTR_HASH_CASESENSITIVE, 123);
|
||||||
|
CHECK(hash == testcase.hash);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SECTION("hashing empty string with seed of 0 gives default seed") {
|
||||||
|
auto hash = SStrHash64("", 0, 0);
|
||||||
|
CHECK(hash == 0x7FED7FED7FED7FEDLL);
|
||||||
|
|
||||||
|
hash = SStrHash64("", SSTR_HASH_CASESENSITIVE, 0);
|
||||||
|
CHECK(hash == 0x7FED7FED7FED7FEDLL);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("hashing empty string with custom seed returns that seed") {
|
||||||
|
auto seed = GENERATE(1LL, 123LL, 0x7FED7FEDLL, 0xFFFFFFFFLL, 0x7FED7FED7FED7FEDLL, 0xFFFFFFFFFFFFFFFFLL);
|
||||||
|
|
||||||
|
auto hash = SStrHash64("", 0, seed);
|
||||||
|
CHECK(hash == seed);
|
||||||
|
|
||||||
|
hash = SStrHash64("", SSTR_HASH_CASESENSITIVE, seed);
|
||||||
|
CHECK(hash == seed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("SStrLen", "[string]") {
|
TEST_CASE("SStrLen", "[string]") {
|
||||||
SECTION("calculates string length correctly") {
|
SECTION("calculates string length correctly") {
|
||||||
REQUIRE(SStrLen("foo") == 3);
|
REQUIRE(SStrLen("foo") == 3);
|
||||||
|
|
|
||||||
|
|
@ -400,7 +400,7 @@ EXPORTS
|
||||||
;SStrToInt64 @577 NONAME
|
;SStrToInt64 @577 NONAME
|
||||||
SStrPrintf @578 NONAME
|
SStrPrintf @578 NONAME
|
||||||
SStrLower @579 NONAME
|
SStrLower @579 NONAME
|
||||||
;SStrHash64 @580 NONAME
|
SStrHash64 @580 NONAME
|
||||||
SStrVPrintf @581 NONAME
|
SStrVPrintf @581 NONAME
|
||||||
|
|
||||||
; More drawing
|
; More drawing
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,7 @@ size_t STORMAPI SStrCopy(char*, const char*, size_t) { return 0; }
|
||||||
char* STORMAPI SStrDupA(const char*, const char*, uint32_t) { return 0; }
|
char* STORMAPI SStrDupA(const char*, const char*, uint32_t) { return 0; }
|
||||||
uint32_t STORMAPI SStrHash(const char*, uint32_t, uint32_t) { return 0; }
|
uint32_t STORMAPI SStrHash(const char*, uint32_t, uint32_t) { return 0; }
|
||||||
uint32_t STORMAPI SStrHashHT(const char*) { return 0; }
|
uint32_t STORMAPI SStrHashHT(const char*) { return 0; }
|
||||||
|
int64_t STORMAPI SStrHash64(const char*, uint32_t, int64_t) { return 0; }
|
||||||
size_t STORMAPI SStrLen(const char*) { return 0; }
|
size_t STORMAPI SStrLen(const char*) { return 0; }
|
||||||
void STORMAPI SStrLower(char*) {}
|
void STORMAPI SStrLower(char*) {}
|
||||||
uint32_t STORMAPI SStrPack(char*, const char*, uint32_t) { return 0; }
|
uint32_t STORMAPI SStrPack(char*, const char*, uint32_t) { return 0; }
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue