diff options
author | Anton Samokhvalov <pg83@yandex.ru> | 2022-02-10 16:45:15 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:15 +0300 |
commit | 72cb13b4aff9bc9cf22e49251bc8fd143f82538f (patch) | |
tree | da2c34829458c7d4e74bdfbdf85dff449e9e7fb8 /util/digest | |
parent | 778e51ba091dc39e7b7fcab2b9cf4dbedfb6f2b5 (diff) | |
download | ydb-72cb13b4aff9bc9cf22e49251bc8fd143f82538f.tar.gz |
Restoring authorship annotation for Anton Samokhvalov <pg83@yandex.ru>. Commit 1 of 2.
Diffstat (limited to 'util/digest')
-rw-r--r-- | util/digest/benchmark/murmur/main.cpp | 14 | ||||
-rw-r--r-- | util/digest/city.cpp | 622 | ||||
-rw-r--r-- | util/digest/city.h | 64 | ||||
-rw-r--r-- | util/digest/fnv.cpp | 2 | ||||
-rw-r--r-- | util/digest/fnv.h | 108 | ||||
-rw-r--r-- | util/digest/fnv_ut.cpp | 40 | ||||
-rw-r--r-- | util/digest/multi.h | 4 | ||||
-rw-r--r-- | util/digest/murmur.cpp | 4 | ||||
-rw-r--r-- | util/digest/murmur.h | 32 | ||||
-rw-r--r-- | util/digest/murmur_ut.cpp | 88 | ||||
-rw-r--r-- | util/digest/numeric.cpp | 2 | ||||
-rw-r--r-- | util/digest/numeric.h | 132 | ||||
-rw-r--r-- | util/digest/sequence.h | 4 | ||||
-rw-r--r-- | util/digest/sequence_ut.cpp | 4 | ||||
-rw-r--r-- | util/digest/ut/ya.make | 8 |
15 files changed, 564 insertions, 564 deletions
diff --git a/util/digest/benchmark/murmur/main.cpp b/util/digest/benchmark/murmur/main.cpp index 1fe2fdcc21..7729ef345f 100644 --- a/util/digest/benchmark/murmur/main.cpp +++ b/util/digest/benchmark/murmur/main.cpp @@ -6,21 +6,21 @@ #include <array> constexpr auto MakeTestData() { - std::array<ui64, 4096> result; - for (ui64 i = 0; i < result.size(); ++i) { - result[i] = i; - } - return result; + std::array<ui64, 4096> result; + for (ui64 i = 0; i < result.size(); ++i) { + result[i] = i; + } + return result; } constexpr auto TEST_DATA = MakeTestData(); template <typename Result> static void BenchmarkMurmurHash(benchmark::State& state) { - for (auto _ : state) { + for (auto _ : state) { Result hash = MurmurHash<Result>(TEST_DATA.data(), sizeof(TEST_DATA)); Y_DO_NOT_OPTIMIZE_AWAY(hash); - } + } } BENCHMARK_TEMPLATE(BenchmarkMurmurHash, ui32); diff --git a/util/digest/city.cpp b/util/digest/city.cpp index c25f175d54..f73f2fd1a0 100644 --- a/util/digest/city.cpp +++ b/util/digest/city.cpp @@ -1,323 +1,323 @@ #ifndef NO_CITYHASH -// Copyright (c) 2011 Google, Inc. - -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: - -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// CityHash Version 1, by Geoff Pike and Jyrki Alakuijala - -// This file provides CityHash64() and related functions. - -// It's probably possible to create even faster hash functions by -// writing a program that systematically explores some of the space of -// possible hash functions, by using SIMD instructions, or by -// compromising on hash quality. - - #include "city.h" - +// Copyright (c) 2011 Google, Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// CityHash Version 1, by Geoff Pike and Jyrki Alakuijala + +// This file provides CityHash64() and related functions. + +// It's probably possible to create even faster hash functions by +// writing a program that systematically explores some of the space of +// possible hash functions, by using SIMD instructions, or by +// compromising on hash quality. + + #include "city.h" + using uint8 = ui8; using uint32 = ui32; using uint64 = ui64; - - #include <util/system/unaligned_mem.h> - #include <util/generic/algorithm.h> - -using namespace std; - -//#define UNALIGNED_LOAD64(p) (*(const uint64*)(p)) -//#define UNALIGNED_LOAD32(p) (*(const uint32*)(p)) - - #define UNALIGNED_LOAD64(p) (ReadUnaligned<uint64>((const void*)(p))) - #define UNALIGNED_LOAD32(p) (ReadUnaligned<uint32>((const void*)(p))) - - #define LIKELY(x) Y_LIKELY(!!(x)) - -// Some primes between 2^63 and 2^64 for various uses. -static const uint64 k0 = 0xc3a5c85c97cb3127ULL; -static const uint64 k1 = 0xb492b66fbe98f273ULL; -static const uint64 k2 = 0x9ae16a3b2f90404fULL; -static const uint64 k3 = 0xc949d7c7509e6557ULL; - -// Bitwise right rotate. Normally this will compile to a single -// instruction, especially if the shift is a manifest constant. -static uint64 Rotate(uint64 val, int shift) { - // Avoid shifting by 64: doing so yields an undefined result. - return shift == 0 ? val : ((val >> shift) | (val << (64 - shift))); -} - -// Equivalent to Rotate(), but requires the second arg to be non-zero. -// On x86-64, and probably others, it's possible for this to compile -// to a single instruction if both args are already in registers. -static uint64 RotateByAtLeast1(uint64 val, int shift) { - return (val >> shift) | (val << (64 - shift)); -} - -static uint64 ShiftMix(uint64 val) { - return val ^ (val >> 47); -} - -static uint64 HashLen16(uint64 u, uint64 v) { - return Hash128to64(uint128(u, v)); -} - -static uint64 HashLen0to16(const char* s, size_t len) { - if (len > 8) { - uint64 a = UNALIGNED_LOAD64(s); - uint64 b = UNALIGNED_LOAD64(s + len - 8); - return HashLen16(a, RotateByAtLeast1(b + len, static_cast<int>(len))) ^ b; - } - if (len >= 4) { - uint64 a = UNALIGNED_LOAD32(s); - return HashLen16(len + (a << 3), UNALIGNED_LOAD32(s + len - 4)); - } - if (len > 0) { - uint8 a = s[0]; - uint8 b = s[len >> 1]; - uint8 c = s[len - 1]; - uint32 y = static_cast<uint32>(a) + (static_cast<uint32>(b) << 8); - uint32 z = static_cast<uint32>(len) + (static_cast<uint32>(c) << 2); - return ShiftMix(y * k2 ^ z * k3) * k2; - } - return k2; -} - -// This probably works well for 16-byte strings as well, but it may be overkill -// in that case. -static uint64 HashLen17to32(const char* s, size_t len) { - uint64 a = UNALIGNED_LOAD64(s) * k1; - uint64 b = UNALIGNED_LOAD64(s + 8); - uint64 c = UNALIGNED_LOAD64(s + len - 8) * k2; - uint64 d = UNALIGNED_LOAD64(s + len - 16) * k0; - return HashLen16(Rotate(a - b, 43) + Rotate(c, 30) + d, - a + Rotate(b ^ k3, 20) - c + len); -} - -// Return a 16-byte hash for 48 bytes. Quick and dirty. -// Callers do best to use "random-looking" values for a and b. -static pair<uint64, uint64> WeakHashLen32WithSeeds( - uint64 w, uint64 x, uint64 y, uint64 z, uint64 a, uint64 b) { - a += w; - b = Rotate(b + a + z, 21); - uint64 c = a; - a += x; - a += y; - b += Rotate(a, 44); - return make_pair(a + z, b + c); -} - -// Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty. -static pair<uint64, uint64> WeakHashLen32WithSeeds( - const char* s, uint64 a, uint64 b) { - return WeakHashLen32WithSeeds(UNALIGNED_LOAD64(s), - UNALIGNED_LOAD64(s + 8), - UNALIGNED_LOAD64(s + 16), - UNALIGNED_LOAD64(s + 24), - a, - b); -} - -// Return an 8-byte hash for 33 to 64 bytes. -static uint64 HashLen33to64(const char* s, size_t len) { - uint64 z = UNALIGNED_LOAD64(s + 24); - uint64 a = UNALIGNED_LOAD64(s) + (len + UNALIGNED_LOAD64(s + len - 16)) * k0; - uint64 b = Rotate(a + z, 52); - uint64 c = Rotate(a, 37); - a += UNALIGNED_LOAD64(s + 8); - c += Rotate(a, 7); - a += UNALIGNED_LOAD64(s + 16); - uint64 vf = a + z; - uint64 vs = b + Rotate(a, 31) + c; - a = UNALIGNED_LOAD64(s + 16) + UNALIGNED_LOAD64(s + len - 32); - z = UNALIGNED_LOAD64(s + len - 8); - b = Rotate(a + z, 52); - c = Rotate(a, 37); - a += UNALIGNED_LOAD64(s + len - 24); - c += Rotate(a, 7); - a += UNALIGNED_LOAD64(s + len - 16); - uint64 wf = a + z; - uint64 ws = b + Rotate(a, 31) + c; - uint64 r = ShiftMix((vf + ws) * k2 + (wf + vs) * k0); - return ShiftMix(r * k0 + vs) * k2; -} - -uint64 CityHash64(const char* s, size_t len) noexcept { - if (len <= 32) { - if (len <= 16) { - return HashLen0to16(s, len); - } else { - return HashLen17to32(s, len); - } - } else if (len <= 64) { - return HashLen33to64(s, len); - } - - // For strings over 64 bytes we hash the end first, and then as we - // loop we keep 56 bytes of state: v, w, x, y, and z. - uint64 x = UNALIGNED_LOAD64(s); - uint64 y = UNALIGNED_LOAD64(s + len - 16) ^ k1; - uint64 z = UNALIGNED_LOAD64(s + len - 56) ^ k0; - pair<uint64, uint64> v = WeakHashLen32WithSeeds(s + len - 64, len, y); - pair<uint64, uint64> w = WeakHashLen32WithSeeds(s + len - 32, len * k1, k0); - z += ShiftMix(v.second) * k1; - x = Rotate(z + x, 39) * k1; - y = Rotate(y, 33) * k1; - - // Decrease len to the nearest multiple of 64, and operate on 64-byte chunks. - len = (len - 1) & ~static_cast<size_t>(63); - do { - x = Rotate(x + y + v.first + UNALIGNED_LOAD64(s + 16), 37) * k1; - y = Rotate(y + v.second + UNALIGNED_LOAD64(s + 48), 42) * k1; - x ^= w.second; - y ^= v.first; - z = Rotate(z ^ w.first, 33); - v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first); - w = WeakHashLen32WithSeeds(s + 32, z + w.second, y); - DoSwap(z, x); - s += 64; - len -= 64; - } while (len != 0); - return HashLen16(HashLen16(v.first, w.first) + ShiftMix(y) * k1 + z, - HashLen16(v.second, w.second) + x); -} - -uint64 CityHash64WithSeed(const char* s, size_t len, uint64 seed) noexcept { - return CityHash64WithSeeds(s, len, k2, seed); -} - -uint64 CityHash64WithSeeds(const char* s, size_t len, + + #include <util/system/unaligned_mem.h> + #include <util/generic/algorithm.h> + +using namespace std; + +//#define UNALIGNED_LOAD64(p) (*(const uint64*)(p)) +//#define UNALIGNED_LOAD32(p) (*(const uint32*)(p)) + + #define UNALIGNED_LOAD64(p) (ReadUnaligned<uint64>((const void*)(p))) + #define UNALIGNED_LOAD32(p) (ReadUnaligned<uint32>((const void*)(p))) + + #define LIKELY(x) Y_LIKELY(!!(x)) + +// Some primes between 2^63 and 2^64 for various uses. +static const uint64 k0 = 0xc3a5c85c97cb3127ULL; +static const uint64 k1 = 0xb492b66fbe98f273ULL; +static const uint64 k2 = 0x9ae16a3b2f90404fULL; +static const uint64 k3 = 0xc949d7c7509e6557ULL; + +// Bitwise right rotate. Normally this will compile to a single +// instruction, especially if the shift is a manifest constant. +static uint64 Rotate(uint64 val, int shift) { + // Avoid shifting by 64: doing so yields an undefined result. + return shift == 0 ? val : ((val >> shift) | (val << (64 - shift))); +} + +// Equivalent to Rotate(), but requires the second arg to be non-zero. +// On x86-64, and probably others, it's possible for this to compile +// to a single instruction if both args are already in registers. +static uint64 RotateByAtLeast1(uint64 val, int shift) { + return (val >> shift) | (val << (64 - shift)); +} + +static uint64 ShiftMix(uint64 val) { + return val ^ (val >> 47); +} + +static uint64 HashLen16(uint64 u, uint64 v) { + return Hash128to64(uint128(u, v)); +} + +static uint64 HashLen0to16(const char* s, size_t len) { + if (len > 8) { + uint64 a = UNALIGNED_LOAD64(s); + uint64 b = UNALIGNED_LOAD64(s + len - 8); + return HashLen16(a, RotateByAtLeast1(b + len, static_cast<int>(len))) ^ b; + } + if (len >= 4) { + uint64 a = UNALIGNED_LOAD32(s); + return HashLen16(len + (a << 3), UNALIGNED_LOAD32(s + len - 4)); + } + if (len > 0) { + uint8 a = s[0]; + uint8 b = s[len >> 1]; + uint8 c = s[len - 1]; + uint32 y = static_cast<uint32>(a) + (static_cast<uint32>(b) << 8); + uint32 z = static_cast<uint32>(len) + (static_cast<uint32>(c) << 2); + return ShiftMix(y * k2 ^ z * k3) * k2; + } + return k2; +} + +// This probably works well for 16-byte strings as well, but it may be overkill +// in that case. +static uint64 HashLen17to32(const char* s, size_t len) { + uint64 a = UNALIGNED_LOAD64(s) * k1; + uint64 b = UNALIGNED_LOAD64(s + 8); + uint64 c = UNALIGNED_LOAD64(s + len - 8) * k2; + uint64 d = UNALIGNED_LOAD64(s + len - 16) * k0; + return HashLen16(Rotate(a - b, 43) + Rotate(c, 30) + d, + a + Rotate(b ^ k3, 20) - c + len); +} + +// Return a 16-byte hash for 48 bytes. Quick and dirty. +// Callers do best to use "random-looking" values for a and b. +static pair<uint64, uint64> WeakHashLen32WithSeeds( + uint64 w, uint64 x, uint64 y, uint64 z, uint64 a, uint64 b) { + a += w; + b = Rotate(b + a + z, 21); + uint64 c = a; + a += x; + a += y; + b += Rotate(a, 44); + return make_pair(a + z, b + c); +} + +// Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty. +static pair<uint64, uint64> WeakHashLen32WithSeeds( + const char* s, uint64 a, uint64 b) { + return WeakHashLen32WithSeeds(UNALIGNED_LOAD64(s), + UNALIGNED_LOAD64(s + 8), + UNALIGNED_LOAD64(s + 16), + UNALIGNED_LOAD64(s + 24), + a, + b); +} + +// Return an 8-byte hash for 33 to 64 bytes. +static uint64 HashLen33to64(const char* s, size_t len) { + uint64 z = UNALIGNED_LOAD64(s + 24); + uint64 a = UNALIGNED_LOAD64(s) + (len + UNALIGNED_LOAD64(s + len - 16)) * k0; + uint64 b = Rotate(a + z, 52); + uint64 c = Rotate(a, 37); + a += UNALIGNED_LOAD64(s + 8); + c += Rotate(a, 7); + a += UNALIGNED_LOAD64(s + 16); + uint64 vf = a + z; + uint64 vs = b + Rotate(a, 31) + c; + a = UNALIGNED_LOAD64(s + 16) + UNALIGNED_LOAD64(s + len - 32); + z = UNALIGNED_LOAD64(s + len - 8); + b = Rotate(a + z, 52); + c = Rotate(a, 37); + a += UNALIGNED_LOAD64(s + len - 24); + c += Rotate(a, 7); + a += UNALIGNED_LOAD64(s + len - 16); + uint64 wf = a + z; + uint64 ws = b + Rotate(a, 31) + c; + uint64 r = ShiftMix((vf + ws) * k2 + (wf + vs) * k0); + return ShiftMix(r * k0 + vs) * k2; +} + +uint64 CityHash64(const char* s, size_t len) noexcept { + if (len <= 32) { + if (len <= 16) { + return HashLen0to16(s, len); + } else { + return HashLen17to32(s, len); + } + } else if (len <= 64) { + return HashLen33to64(s, len); + } + + // For strings over 64 bytes we hash the end first, and then as we + // loop we keep 56 bytes of state: v, w, x, y, and z. + uint64 x = UNALIGNED_LOAD64(s); + uint64 y = UNALIGNED_LOAD64(s + len - 16) ^ k1; + uint64 z = UNALIGNED_LOAD64(s + len - 56) ^ k0; + pair<uint64, uint64> v = WeakHashLen32WithSeeds(s + len - 64, len, y); + pair<uint64, uint64> w = WeakHashLen32WithSeeds(s + len - 32, len * k1, k0); + z += ShiftMix(v.second) * k1; + x = Rotate(z + x, 39) * k1; + y = Rotate(y, 33) * k1; + + // Decrease len to the nearest multiple of 64, and operate on 64-byte chunks. + len = (len - 1) & ~static_cast<size_t>(63); + do { + x = Rotate(x + y + v.first + UNALIGNED_LOAD64(s + 16), 37) * k1; + y = Rotate(y + v.second + UNALIGNED_LOAD64(s + 48), 42) * k1; + x ^= w.second; + y ^= v.first; + z = Rotate(z ^ w.first, 33); + v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first); + w = WeakHashLen32WithSeeds(s + 32, z + w.second, y); + DoSwap(z, x); + s += 64; + len -= 64; + } while (len != 0); + return HashLen16(HashLen16(v.first, w.first) + ShiftMix(y) * k1 + z, + HashLen16(v.second, w.second) + x); +} + +uint64 CityHash64WithSeed(const char* s, size_t len, uint64 seed) noexcept { + return CityHash64WithSeeds(s, len, k2, seed); +} + +uint64 CityHash64WithSeeds(const char* s, size_t len, uint64 seed0, uint64 seed1) noexcept { - return HashLen16(CityHash64(s, len) - seed0, seed1); -} - -// A subroutine for CityHash128(). Returns a decent 128-bit hash for strings -// of any length representable in ssize_t. Based on City and Murmur. -static uint128 CityMurmur(const char* s, size_t len, uint128 seed) { - uint64 a = Uint128Low64(seed); - uint64 b = Uint128High64(seed); - uint64 c = 0; - uint64 d = 0; - ssize_t l = len - 16; - if (l <= 0) { // len <= 16 - c = b * k1 + HashLen0to16(s, len); - d = Rotate(a + (len >= 8 ? UNALIGNED_LOAD64(s) : c), 32); - } else { // len > 16 - c = HashLen16(UNALIGNED_LOAD64(s + len - 8) + k1, a); - d = HashLen16(b + len, c + UNALIGNED_LOAD64(s + len - 16)); - a += d; - do { - a ^= ShiftMix(UNALIGNED_LOAD64(s) * k1) * k1; - a *= k1; - b ^= a; - c ^= ShiftMix(UNALIGNED_LOAD64(s + 8) * k1) * k1; - c *= k1; - d ^= c; - s += 16; - l -= 16; - } while (l > 0); - } - a = HashLen16(a, c); - b = HashLen16(d, b); - return uint128(a ^ b, HashLen16(b, a)); -} - -uint128 CityHash128WithSeed(const char* s, size_t len, uint128 seed) noexcept { - if (len < 128) { - return CityMurmur(s, len, seed); - } - - // We expect len >= 128 to be the common case. Keep 56 bytes of state: - // v, w, x, y, and z. - pair<uint64, uint64> v, w; - uint64 x = Uint128Low64(seed); - uint64 y = Uint128High64(seed); - uint64 z = len * k1; - v.first = Rotate(y ^ k1, 49) * k1 + UNALIGNED_LOAD64(s); - v.second = Rotate(v.first, 42) * k1 + UNALIGNED_LOAD64(s + 8); - w.first = Rotate(y + z, 35) * k1 + x; - w.second = Rotate(x + UNALIGNED_LOAD64(s + 88), 53) * k1; - - // This is the same inner loop as CityHash64(), manually unrolled. - do { - x = Rotate(x + y + v.first + UNALIGNED_LOAD64(s + 16), 37) * k1; - y = Rotate(y + v.second + UNALIGNED_LOAD64(s + 48), 42) * k1; - x ^= w.second; - y ^= v.first; - z = Rotate(z ^ w.first, 33); - v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first); - w = WeakHashLen32WithSeeds(s + 32, z + w.second, y); - DoSwap(z, x); - s += 64; - x = Rotate(x + y + v.first + UNALIGNED_LOAD64(s + 16), 37) * k1; - y = Rotate(y + v.second + UNALIGNED_LOAD64(s + 48), 42) * k1; - x ^= w.second; - y ^= v.first; - z = Rotate(z ^ w.first, 33); - v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first); - w = WeakHashLen32WithSeeds(s + 32, z + w.second, y); - DoSwap(z, x); - s += 64; - len -= 128; - } while (LIKELY(len >= 128)); - y += Rotate(w.first, 37) * k0 + z; - x += Rotate(v.first + z, 49) * k0; - // If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s. - for (size_t tail_done = 0; tail_done < len;) { - tail_done += 32; - y = Rotate(y - x, 42) * k0 + v.second; - w.first += UNALIGNED_LOAD64(s + len - tail_done + 16); - x = Rotate(x, 49) * k0 + w.first; - w.first += v.first; - v = WeakHashLen32WithSeeds(s + len - tail_done, v.first, v.second); - } - // At this point our 48 bytes of state should contain more than - // enough information for a strong 128-bit hash. We use two - // different 48-byte-to-8-byte hashes to get a 16-byte final result. - x = HashLen16(x, v.first); - y = HashLen16(y, w.first); - return uint128(HashLen16(x + v.second, w.second) + y, - HashLen16(x + w.second, y + v.second)); -} - -uint128 CityHash128(const char* s, size_t len) noexcept { - if (len >= 16) { - return CityHash128WithSeed(s + 16, - len - 16, - uint128(UNALIGNED_LOAD64(s) ^ k3, - UNALIGNED_LOAD64(s + 8))); - } else if (len >= 8) { - return CityHash128WithSeed(nullptr, - 0, - uint128(UNALIGNED_LOAD64(s) ^ (len * k0), - UNALIGNED_LOAD64(s + len - 8) ^ k1)); - } else { - return CityHash128WithSeed(s, len, uint128(k0, k1)); - } -} + return HashLen16(CityHash64(s, len) - seed0, seed1); +} + +// A subroutine for CityHash128(). Returns a decent 128-bit hash for strings +// of any length representable in ssize_t. Based on City and Murmur. +static uint128 CityMurmur(const char* s, size_t len, uint128 seed) { + uint64 a = Uint128Low64(seed); + uint64 b = Uint128High64(seed); + uint64 c = 0; + uint64 d = 0; + ssize_t l = len - 16; + if (l <= 0) { // len <= 16 + c = b * k1 + HashLen0to16(s, len); + d = Rotate(a + (len >= 8 ? UNALIGNED_LOAD64(s) : c), 32); + } else { // len > 16 + c = HashLen16(UNALIGNED_LOAD64(s + len - 8) + k1, a); + d = HashLen16(b + len, c + UNALIGNED_LOAD64(s + len - 16)); + a += d; + do { + a ^= ShiftMix(UNALIGNED_LOAD64(s) * k1) * k1; + a *= k1; + b ^= a; + c ^= ShiftMix(UNALIGNED_LOAD64(s + 8) * k1) * k1; + c *= k1; + d ^= c; + s += 16; + l -= 16; + } while (l > 0); + } + a = HashLen16(a, c); + b = HashLen16(d, b); + return uint128(a ^ b, HashLen16(b, a)); +} + +uint128 CityHash128WithSeed(const char* s, size_t len, uint128 seed) noexcept { + if (len < 128) { + return CityMurmur(s, len, seed); + } + + // We expect len >= 128 to be the common case. Keep 56 bytes of state: + // v, w, x, y, and z. + pair<uint64, uint64> v, w; + uint64 x = Uint128Low64(seed); + uint64 y = Uint128High64(seed); + uint64 z = len * k1; + v.first = Rotate(y ^ k1, 49) * k1 + UNALIGNED_LOAD64(s); + v.second = Rotate(v.first, 42) * k1 + UNALIGNED_LOAD64(s + 8); + w.first = Rotate(y + z, 35) * k1 + x; + w.second = Rotate(x + UNALIGNED_LOAD64(s + 88), 53) * k1; + + // This is the same inner loop as CityHash64(), manually unrolled. + do { + x = Rotate(x + y + v.first + UNALIGNED_LOAD64(s + 16), 37) * k1; + y = Rotate(y + v.second + UNALIGNED_LOAD64(s + 48), 42) * k1; + x ^= w.second; + y ^= v.first; + z = Rotate(z ^ w.first, 33); + v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first); + w = WeakHashLen32WithSeeds(s + 32, z + w.second, y); + DoSwap(z, x); + s += 64; + x = Rotate(x + y + v.first + UNALIGNED_LOAD64(s + 16), 37) * k1; + y = Rotate(y + v.second + UNALIGNED_LOAD64(s + 48), 42) * k1; + x ^= w.second; + y ^= v.first; + z = Rotate(z ^ w.first, 33); + v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first); + w = WeakHashLen32WithSeeds(s + 32, z + w.second, y); + DoSwap(z, x); + s += 64; + len -= 128; + } while (LIKELY(len >= 128)); + y += Rotate(w.first, 37) * k0 + z; + x += Rotate(v.first + z, 49) * k0; + // If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s. + for (size_t tail_done = 0; tail_done < len;) { + tail_done += 32; + y = Rotate(y - x, 42) * k0 + v.second; + w.first += UNALIGNED_LOAD64(s + len - tail_done + 16); + x = Rotate(x, 49) * k0 + w.first; + w.first += v.first; + v = WeakHashLen32WithSeeds(s + len - tail_done, v.first, v.second); + } + // At this point our 48 bytes of state should contain more than + // enough information for a strong 128-bit hash. We use two + // different 48-byte-to-8-byte hashes to get a 16-byte final result. + x = HashLen16(x, v.first); + y = HashLen16(y, w.first); + return uint128(HashLen16(x + v.second, w.second) + y, + HashLen16(x + w.second, y + v.second)); +} + +uint128 CityHash128(const char* s, size_t len) noexcept { + if (len >= 16) { + return CityHash128WithSeed(s + 16, + len - 16, + uint128(UNALIGNED_LOAD64(s) ^ k3, + UNALIGNED_LOAD64(s + 8))); + } else if (len >= 8) { + return CityHash128WithSeed(nullptr, + 0, + uint128(UNALIGNED_LOAD64(s) ^ (len * k0), + UNALIGNED_LOAD64(s + len - 8) ^ k1)); + } else { + return CityHash128WithSeed(s, len, uint128(k0, k1)); + } +} // TODO(yazevnul): move this function to unittests void TestCompilationOfCityHashTemplates() { - TStringBuf s; - CityHash64(s); - CityHash64WithSeed(s, 1); - CityHash64WithSeeds(s, 1, 2); - CityHash128(s); - CityHash128WithSeed(s, uint128(1, 2)); + TStringBuf s; + CityHash64(s); + CityHash64WithSeed(s, 1); + CityHash64WithSeeds(s, 1, 2); + CityHash128(s); + CityHash128WithSeed(s, uint128(1, 2)); } #endif diff --git a/util/digest/city.h b/util/digest/city.h index 675a798074..3c4b70fc55 100644 --- a/util/digest/city.h +++ b/util/digest/city.h @@ -1,48 +1,48 @@ -#pragma once - -#include <util/generic/utility.h> +#pragma once + +#include <util/generic/utility.h> #include <util/generic/strbuf.h> - + #include <utility> - + // NOTE: These functions provide CityHash 1.0 implementation whose results are *different* from // the mainline version of CityHash. using uint128 = std::pair<ui64, ui64>; constexpr ui64 Uint128Low64(const uint128& x) { - return x.first; -} - + return x.first; +} + constexpr ui64 Uint128High64(const uint128& x) { - return x.second; -} - + return x.second; +} + // Hash functions for a byte array. // http://en.wikipedia.org/wiki/CityHash -Y_PURE_FUNCTION ui64 CityHash64(const char* buf, size_t len) noexcept; - -Y_PURE_FUNCTION ui64 CityHash64WithSeed(const char* buf, size_t len, ui64 seed) noexcept; - -Y_PURE_FUNCTION ui64 CityHash64WithSeeds(const char* buf, size_t len, ui64 seed0, ui64 seed1) noexcept; - -Y_PURE_FUNCTION uint128 CityHash128(const char* s, size_t len) noexcept; - -Y_PURE_FUNCTION uint128 CityHash128WithSeed(const char* s, size_t len, uint128 seed) noexcept; - -// Hash 128 input bits down to 64 bits of output. -// This is intended to be a reasonably good hash function. +Y_PURE_FUNCTION ui64 CityHash64(const char* buf, size_t len) noexcept; + +Y_PURE_FUNCTION ui64 CityHash64WithSeed(const char* buf, size_t len, ui64 seed) noexcept; + +Y_PURE_FUNCTION ui64 CityHash64WithSeeds(const char* buf, size_t len, ui64 seed0, ui64 seed1) noexcept; + +Y_PURE_FUNCTION uint128 CityHash128(const char* s, size_t len) noexcept; + +Y_PURE_FUNCTION uint128 CityHash128WithSeed(const char* s, size_t len, uint128 seed) noexcept; + +// Hash 128 input bits down to 64 bits of output. +// This is intended to be a reasonably good hash function. inline ui64 Hash128to64(const uint128& x) { - // Murmur-inspired hashing. - const ui64 kMul = 0x9ddfea08eb382d69ULL; - ui64 a = (Uint128Low64(x) ^ Uint128High64(x)) * kMul; - a ^= (a >> 47); - ui64 b = (Uint128High64(x) ^ a) * kMul; - b ^= (b >> 47); - b *= kMul; - return b; -} + // Murmur-inspired hashing. + const ui64 kMul = 0x9ddfea08eb382d69ULL; + ui64 a = (Uint128Low64(x) ^ Uint128High64(x)) * kMul; + a ^= (a >> 47); + ui64 b = (Uint128High64(x) ^ a) * kMul; + b ^= (b >> 47); + b *= kMul; + return b; +} namespace NPrivateCityHash { template <class TStringType> diff --git a/util/digest/fnv.cpp b/util/digest/fnv.cpp index 57fc5964c3..6aff124bd7 100644 --- a/util/digest/fnv.cpp +++ b/util/digest/fnv.cpp @@ -1 +1 @@ -#include "fnv.h" +#include "fnv.h" diff --git a/util/digest/fnv.h b/util/digest/fnv.h index 87b41a3de7..e4aa6d3fb8 100644 --- a/util/digest/fnv.h +++ b/util/digest/fnv.h @@ -2,70 +2,70 @@ #include <util/system/defaults.h> -#define FNV32INIT 2166136261U +#define FNV32INIT 2166136261U #define FNV32PRIME 16777619U -#define FNV64INIT ULL(14695981039346656037) +#define FNV64INIT ULL(14695981039346656037) #define FNV64PRIME ULL(1099511628211) -namespace NFnvPrivate { - template <class It> +namespace NFnvPrivate { + template <class It> constexpr ui32 FnvHash32(It b, It e, ui32 init) { - while (b != e) { - init = (init * FNV32PRIME) ^ (unsigned char)*b++; - } - - return init; - } - - template <class It> + while (b != e) { + init = (init * FNV32PRIME) ^ (unsigned char)*b++; + } + + return init; + } + + template <class It> constexpr ui64 FnvHash64(It b, It e, ui64 init) { - while (b != e) { - init = (init * FNV64PRIME) ^ (unsigned char)*b++; - } - - return init; - } - - template <unsigned N> - struct TFnvHelper; - -#define DEF_FNV(t) \ - template <> \ - struct TFnvHelper<t> { \ - static const ui##t Init = FNV##t##INIT; \ - template <class It> \ + while (b != e) { + init = (init * FNV64PRIME) ^ (unsigned char)*b++; + } + + return init; + } + + template <unsigned N> + struct TFnvHelper; + +#define DEF_FNV(t) \ + template <> \ + struct TFnvHelper<t> { \ + static const ui##t Init = FNV##t##INIT; \ + template <class It> \ static constexpr ui##t FnvHash(It b, It e, ui##t init) { \ - return FnvHash##t(b, e, init); \ - } \ - }; - - DEF_FNV(32) - DEF_FNV(64) - -#undef DEF_FNV -} - -template <class T, class It> + return FnvHash##t(b, e, init); \ + } \ + }; + + DEF_FNV(32) + DEF_FNV(64) + +#undef DEF_FNV +} + +template <class T, class It> static constexpr T FnvHash(It b, It e, T init) { - static_assert(sizeof(*b) == 1, "expect sizeof(*b) == 1"); - - return (T)NFnvPrivate::TFnvHelper<8 * sizeof(T)>::FnvHash(b, e, init); -} - -template <class T, class It> + static_assert(sizeof(*b) == 1, "expect sizeof(*b) == 1"); + + return (T)NFnvPrivate::TFnvHelper<8 * sizeof(T)>::FnvHash(b, e, init); +} + +template <class T, class It> static constexpr T FnvHash(It b, It e) { - return FnvHash<T>(b, e, (T)NFnvPrivate::TFnvHelper<8 * sizeof(T)>::Init); -} - -template <class T> + return FnvHash<T>(b, e, (T)NFnvPrivate::TFnvHelper<8 * sizeof(T)>::Init); +} + +template <class T> static constexpr T FnvHash(const void* buf, size_t len, T init) { - return FnvHash<T>((const unsigned char*)buf, (const unsigned char*)buf + len, init); -} - -template <class T> + return FnvHash<T>((const unsigned char*)buf, (const unsigned char*)buf + len, init); +} + +template <class T> static constexpr T FnvHash(const void* buf, size_t len) { - return FnvHash<T>((const unsigned char*)buf, (const unsigned char*)buf + len); -} + return FnvHash<T>((const unsigned char*)buf, (const unsigned char*)buf + len); +} template <class T, class Buf> static constexpr T FnvHash(const Buf& buf) { diff --git a/util/digest/fnv_ut.cpp b/util/digest/fnv_ut.cpp index ce56642b3e..88c2096d77 100644 --- a/util/digest/fnv_ut.cpp +++ b/util/digest/fnv_ut.cpp @@ -1,23 +1,23 @@ -#include "fnv.h" - +#include "fnv.h" + #include <library/cpp/testing/unittest/registar.h> - -Y_UNIT_TEST_SUITE(TFnvTest) { - Y_UNIT_TEST(TestFnv32) { + +Y_UNIT_TEST_SUITE(TFnvTest) { + Y_UNIT_TEST(TestFnv32) { const auto h32 = ULL(2849763999); - UNIT_ASSERT_EQUAL(FnvHash<ui32>("1234567", 7), h32); - UNIT_ASSERT_EQUAL(FnvHash<ui32>(TStringBuf("1234567")), h32); - - UNIT_ASSERT_EQUAL(FnvHash<ui32>(nullptr, 0), FNV32INIT); - UNIT_ASSERT_EQUAL(FnvHash<ui32>(TStringBuf()), FNV32INIT); - } - - Y_UNIT_TEST(TestFnv64) { - const auto h64 = ULL(2449551094593701855); - UNIT_ASSERT_EQUAL(FnvHash<ui64>("1234567", 7), h64); - UNIT_ASSERT_EQUAL(FnvHash<ui64>(TStringBuf("1234567")), h64); + UNIT_ASSERT_EQUAL(FnvHash<ui32>("1234567", 7), h32); + UNIT_ASSERT_EQUAL(FnvHash<ui32>(TStringBuf("1234567")), h32); + + UNIT_ASSERT_EQUAL(FnvHash<ui32>(nullptr, 0), FNV32INIT); + UNIT_ASSERT_EQUAL(FnvHash<ui32>(TStringBuf()), FNV32INIT); + } + + Y_UNIT_TEST(TestFnv64) { + const auto h64 = ULL(2449551094593701855); + UNIT_ASSERT_EQUAL(FnvHash<ui64>("1234567", 7), h64); + UNIT_ASSERT_EQUAL(FnvHash<ui64>(TStringBuf("1234567")), h64); - UNIT_ASSERT_EQUAL(FnvHash<ui64>(nullptr, 0), FNV64INIT); - UNIT_ASSERT_EQUAL(FnvHash<ui64>(TStringBuf()), FNV64INIT); - } -}; + UNIT_ASSERT_EQUAL(FnvHash<ui64>(nullptr, 0), FNV64INIT); + UNIT_ASSERT_EQUAL(FnvHash<ui64>(TStringBuf()), FNV64INIT); + } +}; diff --git a/util/digest/multi.h b/util/digest/multi.h index 8e4597c9dc..20af44f426 100644 --- a/util/digest/multi.h +++ b/util/digest/multi.h @@ -4,11 +4,11 @@ #include "numeric.h" -template <typename TOne> +template <typename TOne> constexpr size_t MultiHash(const TOne& one) noexcept { return THash<TOne>()(one); } -template <typename THead, typename... TTail> +template <typename THead, typename... TTail> constexpr size_t MultiHash(const THead& head, const TTail&... tail) noexcept { return CombineHashes(MultiHash(tail...), THash<THead>()(head)); } diff --git a/util/digest/murmur.cpp b/util/digest/murmur.cpp index b041d3e5f2..86b310a8ab 100644 --- a/util/digest/murmur.cpp +++ b/util/digest/murmur.cpp @@ -127,5 +127,5 @@ namespace NMurmurPrivate { } size_t MurmurHashSizeT(const char* buf, size_t len) noexcept { - return MurmurHash<size_t>(buf, len); -} + return MurmurHash<size_t>(buf, len); +} diff --git a/util/digest/murmur.h b/util/digest/murmur.h index 6b519b430a..4715a2378d 100644 --- a/util/digest/murmur.h +++ b/util/digest/murmur.h @@ -1,20 +1,20 @@ #pragma once - + #include <util/system/defaults.h> #include <util/generic/array_ref.h> - + /* * murmur2 from http://murmurhash.googlepages.com/ * - */ + */ namespace NMurmurPrivate { - Y_PURE_FUNCTION ui32 MurmurHash32(const void* key, size_t len, ui32 seed) noexcept; - - Y_PURE_FUNCTION ui64 MurmurHash64(const void* key, size_t len, ui64 seed) noexcept; + Y_PURE_FUNCTION ui32 MurmurHash32(const void* key, size_t len, ui32 seed) noexcept; + + Y_PURE_FUNCTION ui64 MurmurHash64(const void* key, size_t len, ui64 seed) noexcept; template <unsigned N> struct TMurHelper; - + #define DEF_MUR(t) \ template <> \ struct TMurHelper<t> { \ @@ -27,19 +27,19 @@ namespace NMurmurPrivate { DEF_MUR(64) #undef DEF_MUR -} - -template <class T> +} + +template <class T> static inline T MurmurHash(const void* buf, size_t len, T init) noexcept { return (T)NMurmurPrivate::TMurHelper<8 * sizeof(T)>::MurmurHash(buf, len, init); -} - -template <class T> +} + +template <class T> static inline T MurmurHash(const void* buf, size_t len) noexcept { return MurmurHash<T>(buf, len, (T)0); -} - -//non-inline version +} + +//non-inline version size_t MurmurHashSizeT(const char* buf, size_t len) noexcept; template <typename TOut = size_t> diff --git a/util/digest/murmur_ut.cpp b/util/digest/murmur_ut.cpp index 29287668bc..b12195bc7e 100644 --- a/util/digest/murmur_ut.cpp +++ b/util/digest/murmur_ut.cpp @@ -1,32 +1,32 @@ -#include "murmur.h" - +#include "murmur.h" + #include <library/cpp/testing/unittest/registar.h> - -class TMurmurHashTest: public TTestBase { - UNIT_TEST_SUITE(TMurmurHashTest); - UNIT_TEST(TestHash32) + +class TMurmurHashTest: public TTestBase { + UNIT_TEST_SUITE(TMurmurHashTest); + UNIT_TEST(TestHash32) UNIT_TEST(TestUnalignedHash32) - UNIT_TEST(TestHash64) + UNIT_TEST(TestHash64) UNIT_TEST(TestUnalignedHash64) UNIT_TEST(TestWrapperBiggerTypes) - UNIT_TEST_SUITE_END(); - -private: - inline void TestHash32() { - ui8 buf[256]; - - for (size_t i = 0; i < 256; ++i) { - buf[i] = i; - } - - Test<ui32>(buf, 256, 2373126550UL); + UNIT_TEST_SUITE_END(); + +private: + inline void TestHash32() { + ui8 buf[256]; + + for (size_t i = 0; i < 256; ++i) { + buf[i] = i; + } + + Test<ui32>(buf, 256, 2373126550UL); TestWrapper<ui8, ui32>({buf, buf + 256}, 2373126550UL); - Test<ui32>(buf, 255, 3301607533UL); - Test<ui32>(buf, 254, 2547410121UL); - Test<ui32>(buf, 253, 80030810UL); - } - + Test<ui32>(buf, 255, 3301607533UL); + Test<ui32>(buf, 254, 2547410121UL); + Test<ui32>(buf, 253, 80030810UL); + } + inline void TestUnalignedHash32() { ui8 buf[257]; ui8* unalignedBuf = buf + 1; @@ -38,20 +38,20 @@ private: Test<ui32>(unalignedBuf, 256, 2373126550UL); } - inline void TestHash64() { - ui8 buf[256]; - - for (size_t i = 0; i < 256; ++i) { - buf[i] = i; - } - - Test<ui64>(buf, 256, ULL(12604435678857905857)); + inline void TestHash64() { + ui8 buf[256]; + + for (size_t i = 0; i < 256; ++i) { + buf[i] = i; + } + + Test<ui64>(buf, 256, ULL(12604435678857905857)); TestWrapper<ui8, ui64>({buf, buf + 256}, ULL(12604435678857905857)); - Test<ui64>(buf, 255, ULL(1708835094528446095)); - Test<ui64>(buf, 254, ULL(5077937678736514994)); - Test<ui64>(buf, 253, ULL(11553864555081396353)); - } - + Test<ui64>(buf, 255, ULL(1708835094528446095)); + Test<ui64>(buf, 254, ULL(5077937678736514994)); + Test<ui64>(buf, 253, ULL(11553864555081396353)); + } + inline void TestUnalignedHash64() { ui8 buf[257]; ui8* unalignedBuf = buf + 1; @@ -69,17 +69,17 @@ private: TestWrapper<ui32, ui64>({buf, buf + 2}, MurmurHash<ui64>(buf, sizeof(ui32) * 2)); } -private: - template <class T> - inline void Test(const void* data, size_t len, T expected) { - UNIT_ASSERT_STRINGS_EQUAL(ToString(MurmurHash<T>(data, len)), ToString(expected)); - } +private: + template <class T> + inline void Test(const void* data, size_t len, T expected) { + UNIT_ASSERT_STRINGS_EQUAL(ToString(MurmurHash<T>(data, len)), ToString(expected)); + } template <class E, class T> inline void TestWrapper(const TArrayRef<E>& array, T expected) { auto val = TMurmurHash<T>()(array); UNIT_ASSERT_EQUAL(val, expected); } -}; - -UNIT_TEST_SUITE_REGISTRATION(TMurmurHashTest); +}; + +UNIT_TEST_SUITE_REGISTRATION(TMurmurHashTest); diff --git a/util/digest/numeric.cpp b/util/digest/numeric.cpp index d4d3f063fa..7299191d58 100644 --- a/util/digest/numeric.cpp +++ b/util/digest/numeric.cpp @@ -1 +1 @@ -#include "numeric.h" +#include "numeric.h" diff --git a/util/digest/numeric.h b/util/digest/numeric.h index e20bd908e4..87b8b648d6 100644 --- a/util/digest/numeric.h +++ b/util/digest/numeric.h @@ -1,86 +1,86 @@ #pragma once - + #include <util/generic/typelist.h> #include <util/system/defaults.h> - -/* + +/* * original url (now dead): http://www.cris.com/~Ttwang/tech/inthash.htm * copy: https://gist.github.com/badboy/6267743 - */ - + */ + static constexpr ui8 IntHashImpl(ui8 key8) noexcept { - size_t key = key8; - - key += ~(key << 15); - key ^= (key >> 10); - key += (key << 3); - key ^= (key >> 6); - key += ~(key << 11); - key ^= (key >> 16); - + size_t key = key8; + + key += ~(key << 15); + key ^= (key >> 10); + key += (key << 3); + key ^= (key >> 6); + key += ~(key << 11); + key ^= (key >> 16); + return static_cast<ui8>(key); -} - +} + static constexpr ui16 IntHashImpl(ui16 key16) noexcept { - size_t key = key16; - - key += ~(key << 15); - key ^= (key >> 10); - key += (key << 3); - key ^= (key >> 6); - key += ~(key << 11); - key ^= (key >> 16); - + size_t key = key16; + + key += ~(key << 15); + key ^= (key >> 10); + key += (key << 3); + key ^= (key >> 6); + key += ~(key << 11); + key ^= (key >> 16); + return static_cast<ui16>(key); -} - +} + static constexpr ui32 IntHashImpl(ui32 key) noexcept { - key += ~(key << 15); - key ^= (key >> 10); - key += (key << 3); - key ^= (key >> 6); - key += ~(key << 11); - key ^= (key >> 16); - - return key; -} - + key += ~(key << 15); + key ^= (key >> 10); + key += (key << 3); + key ^= (key >> 6); + key += ~(key << 11); + key ^= (key >> 16); + + return key; +} + static constexpr ui64 IntHashImpl(ui64 key) noexcept { - key += ~(key << 32); - key ^= (key >> 22); - key += ~(key << 13); - key ^= (key >> 8); - key += (key << 3); - key ^= (key >> 15); - key += ~(key << 27); - key ^= (key >> 31); - + key += ~(key << 32); + key ^= (key >> 22); + key += ~(key << 13); + key ^= (key >> 8); + key += (key << 3); + key ^= (key >> 15); + key += ~(key << 27); + key ^= (key >> 31); + return key; -} - -template <class T> +} + +template <class T> static constexpr T IntHash(T t) noexcept { using TCvt = TFixedWidthUnsignedInt<T>; - - return IntHashImpl((TCvt)(t)); -} - -/* - * can handle floats && pointers - */ -template <class T> + + return IntHashImpl((TCvt)(t)); +} + +/* + * can handle floats && pointers + */ +template <class T> static constexpr size_t NumericHash(T t) noexcept { using TCvt = TFixedWidthUnsignedInt<T>; - - union Y_HIDDEN { + + union Y_HIDDEN { T t; - TCvt cvt; + TCvt cvt; } u{t}; - + return (size_t)IntHash(u.cvt); -} - -template <class T> +} + +template <class T> static constexpr T CombineHashes(T l, T r) noexcept { - return IntHash(l) ^ r; -} + return IntHash(l) ^ r; +} diff --git a/util/digest/sequence.h b/util/digest/sequence.h index 712331007b..31a5200617 100644 --- a/util/digest/sequence.h +++ b/util/digest/sequence.h @@ -11,7 +11,7 @@ private: using TBase = std::conditional_t< !std::is_void<ElementHash>::value, ElementHash, - THash<ElementType>>; + THash<ElementType>>; public: template <typename Range> @@ -33,7 +33,7 @@ private: using TBase = std::conditional_t< !std::is_void<RegionHash>::value, RegionHash, - TRangeHash<ElementType>>; + TRangeHash<ElementType>>; public: template <typename ContainerType> diff --git a/util/digest/sequence_ut.cpp b/util/digest/sequence_ut.cpp index 87d6102ee5..5a8c5ddb30 100644 --- a/util/digest/sequence_ut.cpp +++ b/util/digest/sequence_ut.cpp @@ -44,11 +44,11 @@ private: } }; -class TSequenceHashTest: public TTestBase { +class TSequenceHashTest: public TTestBase { UNIT_TEST_SUITE(TSequenceHashTest); UNIT_TEST(TestSimpleBuffer) UNIT_TEST_SUITE_END(); - + private: inline void TestSimpleBuffer() { int arr[] = {1, 2, 3}; diff --git a/util/digest/ut/ya.make b/util/digest/ut/ya.make index 245b2cf6d2..f8eee55a5f 100644 --- a/util/digest/ut/ya.make +++ b/util/digest/ut/ya.make @@ -1,12 +1,12 @@ -UNITTEST_FOR(util) +UNITTEST_FOR(util) OWNER(g:util) SUBSCRIBER(g:util-subscribers) SRCS( - digest/fnv_ut.cpp - digest/murmur_ut.cpp - digest/multi_ut.cpp + digest/fnv_ut.cpp + digest/murmur_ut.cpp + digest/multi_ut.cpp digest/sequence_ut.cpp ) |