diff --git a/City.cpp b/City.cpp index ef57e4ee..f729ec32 100644 --- a/City.cpp +++ b/City.cpp @@ -28,82 +28,104 @@ // compromising on hash quality. #include "City.h" - #include -#include // for memcpy and memset +#include // for memcpy and memset using namespace std; -static uint64 UNALIGNED_LOAD64(const char *p) { - uint64 result; +static uint64_t UNALIGNED_LOAD64(const char *p) { + uint64_t result; memcpy(&result, p, sizeof(result)); return result; } -static uint32 UNALIGNED_LOAD32(const char *p) { - uint32 result; +static uint32_t UNALIGNED_LOAD32(const char *p) { + uint32_t result; memcpy(&result, p, sizeof(result)); return result; } -#if defined _MSC_VER || defined _WIN32 +#ifdef _MSC_VER + #include #define bswap_32(x) _byteswap_ulong(x) #define bswap_64(x) _byteswap_uint64(x) #elif defined(__APPLE__) + // Mac OS X / Darwin features #include #define bswap_32(x) OSSwapInt32(x) #define bswap_64(x) OSSwapInt64(x) +#elif defined(__sun) || defined(sun) + +#include +#define bswap_32(x) BSWAP_32(x) +#define bswap_64(x) BSWAP_64(x) + #elif defined(__FreeBSD__) -// FreeBSD byteswap functinos + #include #define bswap_32(x) bswap32(x) #define bswap_64(x) bswap64(x) +#elif defined(__OpenBSD__) + +#include +#define bswap_32(x) swap32(x) +#define bswap_64(x) swap64(x) + +#elif defined(__NetBSD__) + +#include +#include +#if defined(__BSWAP_RENAME) && !defined(__bswap_32) +#define bswap_32(x) bswap32(x) +#define bswap_64(x) bswap64(x) +#endif + #else + #include + #endif -#ifndef __BIG_ENDIAN__ -#define uint32_in_expected_order(x) (x) -#define uint64_in_expected_order(x) (x) -#else +#ifdef WORDS_BIGENDIAN #define uint32_in_expected_order(x) (bswap_32(x)) #define uint64_in_expected_order(x) (bswap_64(x)) -#endif // __BIG_ENDIAN__ +#else +#define uint32_in_expected_order(x) (x) +#define uint64_in_expected_order(x) (x) +#endif #if !defined(LIKELY) -#if defined(__GNUC__) || defined(__INTEL_COMPILER) +#if HAVE_BUILTIN_EXPECT #define LIKELY(x) (__builtin_expect(!!(x), 1)) #else #define LIKELY(x) (x) #endif #endif -static uint64 Fetch64(const char *p) { +static uint64_t Fetch64(const char *p) { return uint64_in_expected_order(UNALIGNED_LOAD64(p)); } -static uint32 Fetch32(const char *p) { +static uint32_t Fetch32(const char *p) { return uint32_in_expected_order(UNALIGNED_LOAD32(p)); } // 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; +static const uint64_t k0 = 0xc3a5c85c97cb3127ULL; +static const uint64_t k1 = 0xb492b66fbe98f273ULL; +static const uint64_t k2 = 0x9ae16a3b2f90404fULL; // Magic numbers for 32-bit hashing. Copied from Murmur3. static const uint32_t c1 = 0xcc9e2d51; static const uint32_t c2 = 0x1b873593; // A 32-bit to 32-bit integer hash copied from Murmur3. -static uint32 fmix(uint32 h) -{ +static uint32_t fmix(uint32_t h) { h ^= h >> 16; h *= 0x85ebca6b; h ^= h >> 13; @@ -112,15 +134,19 @@ static uint32 fmix(uint32 h) return h; } -static uint32 Rotate32(uint32 val, int shift) { +static uint32_t Rotate32(uint32_t val, int shift) { // Avoid shifting by 32: doing so yields an undefined result. return shift == 0 ? val : ((val >> shift) | (val << (32 - shift))); } #undef PERMUTE3 -#define PERMUTE3(a, b, c) do { std::swap(a, b); std::swap(a, c); } while (0) +#define PERMUTE3(a, b, c) \ + do { \ + std::swap(a, b); \ + std::swap(a, c); \ + } while (0) -static uint32 Mur(uint32 a, uint32 h) { +static uint32_t Mur(uint32_t a, uint32_t h) { // Helper from Murmur3 for combining two 32-bit values. a *= c1; a = Rotate32(a, 17); @@ -130,50 +156,50 @@ static uint32 Mur(uint32 a, uint32 h) { return h * 5 + 0xe6546b64; } -static uint32 Hash32Len13to24(const char *s, size_t len, uint32 seed) { - uint32 a = Fetch32(s - 4 + (len >> 1)); - uint32 b = Fetch32(s + 4); - uint32 c = Fetch32(s + len - 8); - uint32 d = Fetch32(s + (len >> 1)); - uint32 e = Fetch32(s); - uint32 f = Fetch32(s + len - 4); - uint32 h = seed + len; - +static uint32_t Hash32Len13to24(const char *s, size_t len, uint32_t seed) { + uint32_t a = Fetch32(s - 4 + (len >> 1)); + uint32_t b = Fetch32(s + 4); + uint32_t c = Fetch32(s + len - 8); + uint32_t d = Fetch32(s + (len >> 1)); + uint32_t e = Fetch32(s); + uint32_t f = Fetch32(s + len - 4); + uint32_t h = static_cast(len + seed); return fmix(Mur(f, Mur(e, Mur(d, Mur(c, Mur(b, Mur(a, h))))))); } -static uint32 Hash32Len0to4(const char *s, size_t len, uint32 seed) { - uint32 b = seed; - uint32 c = 9; - for (int i = 0; i < len; i++) { - b = b * c1 + s[i]; +static uint32_t Hash32Len0to4(const char *s, size_t len, uint32_t seed) { + uint32_t b = seed; + uint32_t c = 9; + for (size_t i = 0; i < len; i++) { + signed char v = static_cast(s[i]); + b = b * c1 + static_cast(v); c ^= b; } - return fmix(Mur(b, Mur(len, c))); + return fmix(Mur(b, Mur(static_cast(len), c))); } -static uint32 Hash32Len5to12(const char *s, size_t len, uint32 seed) { - uint32 a = len + seed, b = len * 5, c = 9, d = b; +static uint32_t Hash32Len5to12(const char *s, size_t len, uint32_t seed) { + uint32_t a = static_cast(len + seed), b = a * 5, c = 9, d = b; a += Fetch32(s); b += Fetch32(s + len - 4); c += Fetch32(s + ((len >> 1) & 4)); return fmix(Mur(c, Mur(b, Mur(a, d)))); } -uint32 CityHash32WithSeed(const char *s, size_t len, uint32 seed) { +uint32_t CityHash32WithSeed(const char *s, size_t len, uint32_t seed) { if (len <= 24) { - return len <= 12 ? - (len <= 4 ? Hash32Len0to4(s, len, seed) : Hash32Len5to12(s, len, seed)) : - Hash32Len13to24(s, len, seed); + return len <= 12 + ? (len <= 4 ? Hash32Len0to4(s, len, seed) : Hash32Len5to12(s, len, seed)) + : Hash32Len13to24(s, len, seed); } // len > 24 - uint32 h = len + seed, g = c1 * len, f = g; - uint32 a0 = Rotate32(Fetch32(s + len - 4) * c1, 17) * c2; - uint32 a1 = Rotate32(Fetch32(s + len - 8) * c1, 17) * c2; - uint32 a2 = Rotate32(Fetch32(s + len - 16) * c1, 17) * c2; - uint32 a3 = Rotate32(Fetch32(s + len - 12) * c1, 17) * c2; - uint32 a4 = Rotate32(Fetch32(s + len - 20) * c1, 17) * c2; + uint32_t h = static_cast(len + seed), g = c1 * h, f = g; + uint32_t a0 = Rotate32(Fetch32(s + len - 4) * c1, 17) * c2; + uint32_t a1 = Rotate32(Fetch32(s + len - 8) * c1, 17) * c2; + uint32_t a2 = Rotate32(Fetch32(s + len - 16) * c1, 17) * c2; + uint32_t a3 = Rotate32(Fetch32(s + len - 12) * c1, 17) * c2; + uint32_t a4 = Rotate32(Fetch32(s + len - 20) * c1, 17) * c2; h ^= a0; h = Rotate32(h, 19); h = h * 5 + 0xe6546b64; @@ -191,11 +217,11 @@ uint32 CityHash32WithSeed(const char *s, size_t len, uint32 seed) { f = f * 5 + 0xe6546b64; size_t iters = (len - 1) / 20; do { - uint32 a0 = Rotate32(Fetch32(s) * c1, 17) * c2; - uint32 a1 = Fetch32(s + 4); - uint32 a2 = Rotate32(Fetch32(s + 8) * c1, 17) * c2; - uint32 a3 = Rotate32(Fetch32(s + 12) * c1, 17) * c2; - uint32 a4 = Fetch32(s + 16); + uint32_t a0 = Rotate32(Fetch32(s) * c1, 17) * c2; + uint32_t a1 = Fetch32(s + 4); + uint32_t a2 = Rotate32(Fetch32(s + 8) * c1, 17) * c2; + uint32_t a3 = Rotate32(Fetch32(s + 12) * c1, 17) * c2; + uint32_t a4 = Fetch32(s + 16); h ^= a0; h = Rotate32(h, 18); h = h * 5 + 0xe6546b64; @@ -231,65 +257,70 @@ uint32 CityHash32WithSeed(const char *s, size_t len, uint32 seed) { // 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) { +static uint64_t Rotate(uint64_t 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_t ShiftMix(uint64_t val) { return val ^ (val >> 47); } -static uint64 ShiftMix(uint64 val) { - return val ^ (val >> 47); +static uint64_t HashLen16(uint64_t u, uint64_t v) { + return Hash128to64(uint128(u, v)); } -static uint64 HashLen16(uint64 u, uint64 v) { - return Hash128to64(uint128(u, v)); +static uint64_t HashLen16(uint64_t u, uint64_t v, uint64_t mul) { + // Murmur-inspired hashing. + uint64_t a = (u ^ v) * mul; + a ^= (a >> 47); + uint64_t b = (v ^ a) * mul; + b ^= (b >> 47); + b *= mul; + return b; } -static uint64 HashLen0to16(const char *s, size_t len) { - if (len > 8) { - uint64 a = Fetch64(s); - uint64 b = Fetch64(s + len - 8); - return HashLen16(a, RotateByAtLeast1(b + len, len)) ^ b; +static uint64_t HashLen0to16(const char *s, size_t len) { + if (len >= 8) { + uint64_t mul = k2 + len * 2; + uint64_t a = Fetch64(s) + k2; + uint64_t b = Fetch64(s + len - 8); + uint64_t c = Rotate(b, 37) * mul + a; + uint64_t d = (Rotate(a, 25) + b) * mul; + return HashLen16(c, d, mul); } if (len >= 4) { - uint64 a = Fetch32(s); - return HashLen16(len + (a << 3), Fetch32(s + len - 4)); + uint64_t mul = k2 + len * 2; + uint64_t a = Fetch32(s); + return HashLen16(len + (a << 3), Fetch32(s + len - 4), mul); } if (len > 0) { - uint8 a = s[0]; - uint8 b = s[len >> 1]; - uint8 c = s[len - 1]; - uint32 y = static_cast(a) + (static_cast(b) << 8); - uint32 z = len + (static_cast(c) << 2); - return ShiftMix(y * k2 ^ z * k3) * k2; + uint8_t a = static_cast(s[0]); + uint8_t b = static_cast(s[len >> 1]); + uint8_t c = static_cast(s[len - 1]); + uint32_t y = static_cast(a) + (static_cast(b) << 8); + uint32_t z = static_cast(len) + (static_cast(c) << 2); + return ShiftMix(y * k2 ^ z * k0) * 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 = Fetch64(s) * k1; - uint64 b = Fetch64(s + 8); - uint64 c = Fetch64(s + len - 8) * k2; - uint64 d = Fetch64(s + len - 16) * k0; - return HashLen16(Rotate(a - b, 43) + Rotate(c, 30) + d, - a + Rotate(b ^ k3, 20) - c + len); +static uint64_t HashLen17to32(const char *s, size_t len) { + uint64_t mul = k2 + len * 2; + uint64_t a = Fetch64(s) * k1; + uint64_t b = Fetch64(s + 8); + uint64_t c = Fetch64(s + len - 8) * mul; + uint64_t d = Fetch64(s + len - 16) * k2; + return HashLen16(Rotate(a + b, 43) + Rotate(c, 30) + d, + a + Rotate(b + k2, 18) + c, mul); } // 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 WeakHashLen32WithSeeds( - uint64 w, uint64 x, uint64 y, uint64 z, uint64 a, uint64 b) { +static pair WeakHashLen32WithSeeds(uint64_t w, uint64_t x, uint64_t y, uint64_t z, uint64_t a, uint64_t b) { a += w; b = Rotate(b + a + z, 21); - uint64 c = a; + uint64_t c = a; a += x; a += y; b += Rotate(a, 44); @@ -297,41 +328,33 @@ static pair WeakHashLen32WithSeeds( } // Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty. -static pair WeakHashLen32WithSeeds( - const char* s, uint64 a, uint64 b) { - return WeakHashLen32WithSeeds(Fetch64(s), - Fetch64(s + 8), - Fetch64(s + 16), - Fetch64(s + 24), - a, - b); +static pair WeakHashLen32WithSeeds(const char *s, uint64_t a, uint64_t b) { + return WeakHashLen32WithSeeds(Fetch64(s), Fetch64(s + 8), Fetch64(s + 16), Fetch64(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 = Fetch64(s + 24); - uint64 a = Fetch64(s) + (len + Fetch64(s + len - 16)) * k0; - uint64 b = Rotate(a + z, 52); - uint64 c = Rotate(a, 37); - a += Fetch64(s + 8); - c += Rotate(a, 7); - a += Fetch64(s + 16); - uint64 vf = a + z; - uint64 vs = b + Rotate(a, 31) + c; - a = Fetch64(s + 16) + Fetch64(s + len - 32); - z = Fetch64(s + len - 8); - b = Rotate(a + z, 52); - c = Rotate(a, 37); - a += Fetch64(s + len - 24); - c += Rotate(a, 7); - a += Fetch64(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; +static uint64_t HashLen33to64(const char *s, size_t len) { + uint64_t mul = k2 + len * 2; + uint64_t a = Fetch64(s) * k2; + uint64_t b = Fetch64(s + 8); + uint64_t c = Fetch64(s + len - 24); + uint64_t d = Fetch64(s + len - 32); + uint64_t e = Fetch64(s + 16) * k2; + uint64_t f = Fetch64(s + 24) * 9; + uint64_t g = Fetch64(s + len - 8); + uint64_t h = Fetch64(s + len - 16) * mul; + uint64_t u = Rotate(a + g, 43) + (Rotate(b, 30) + c) * 9; + uint64_t v = ((a + g) ^ d) + f + 1; + uint64_t w = bswap_64((u + v) * mul) + h; + uint64_t x = Rotate(e + f, 42) + c; + uint64_t y = (bswap_64((v + w) * mul) + g) * mul; + uint64_t z = e + f + c; + a = bswap_64((x + z) * mul + y) + b; + b = ShiftMix((z + a) * mul + d + h) * mul; + return b + x; } -uint64 CityHash64(const char *s, size_t len) { +uint64_t CityHash64(const char *s, size_t len) { if (len <= 32) { if (len <= 16) { return HashLen0to16(s, len); @@ -344,11 +367,11 @@ uint64 CityHash64(const char *s, size_t 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 = Fetch64(s + len - 40); - uint64 y = Fetch64(s + len - 16) + Fetch64(s + len - 56); - uint64 z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24)); - pair v = WeakHashLen32WithSeeds(s + len - 64, len, z); - pair w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x); + uint64_t x = Fetch64(s + len - 40); + uint64_t y = Fetch64(s + len - 16) + Fetch64(s + len - 56); + uint64_t z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24)); + pair v = WeakHashLen32WithSeeds(s + len - 64, len, z); + pair w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x); x = x * k1 + Fetch64(s); // Decrease len to the nearest multiple of 64, and operate on 64-byte chunks. @@ -369,31 +392,30 @@ uint64 CityHash64(const char *s, size_t len) { HashLen16(v.second, w.second) + x); } -uint64 CityHash64WithSeed(const char *s, size_t len, uint64 seed) { +uint64_t CityHash64WithSeed(const char *s, size_t len, uint64_t seed) { return CityHash64WithSeeds(s, len, k2, seed); } -uint64 CityHash64WithSeeds(const char *s, size_t len, - uint64 seed0, uint64 seed1) { +uint64_t CityHash64WithSeeds(const char *s, size_t len, uint64_t seed0, uint64_t seed1) { return HashLen16(CityHash64(s, len) - seed0, seed1); } // A subroutine for CityHash128(). Returns a decent 128-bit hash for strings // of any length representable in signed long. 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; - signed long l = len - 16; - if (l <= 0) { // len <= 16 + uint64_t a = Uint128Low64(seed); + uint64_t b = Uint128High64(seed); + uint64_t c = 0; + uint64_t d = 0; + if (len <= 16) { a = ShiftMix(a * k1) * k1; c = b * k1 + HashLen0to16(s, len); d = ShiftMix(a + (len >= 8 ? Fetch64(s) : c)); - } else { // len > 16 + } else { c = HashLen16(Fetch64(s + len - 8) + k1, a); d = HashLen16(b + len, c + Fetch64(s + len - 16)); a += d; + // len > 16 here, so do...while is safe do { a ^= ShiftMix(Fetch64(s) * k1) * k1; a *= k1; @@ -402,8 +424,8 @@ static uint128 CityMurmur(const char *s, size_t len, uint128 seed) { c *= k1; d ^= c; s += 16; - l -= 16; - } while (l > 0); + len -= 16; + } while (len > 16); } a = HashLen16(a, c); b = HashLen16(d, b); @@ -417,10 +439,10 @@ uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed) { // We expect len >= 128 to be the common case. Keep 56 bytes of state: // v, w, x, y, and z. - pair v, w; - uint64 x = Uint128Low64(seed); - uint64 y = Uint128High64(seed); - uint64 z = len * k1; + pair v, w; + uint64_t x = Uint128Low64(seed); + uint64_t y = Uint128High64(seed); + uint64_t z = len * k1; v.first = Rotate(y ^ k1, 49) * k1 + Fetch64(s); v.second = Rotate(v.first, 42) * k1 + Fetch64(s + 8); w.first = Rotate(y + z, 35) * k1 + x; @@ -449,9 +471,12 @@ uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed) { len -= 128; } while (LIKELY(len >= 128)); x += Rotate(v.first + z, 49) * k0; - z += Rotate(w.first, 37) * k0; + y = y * k0 + Rotate(w.second, 37); + z = z * k0 + Rotate(w.first, 27); + w.first *= 9; + v.first *= 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; ) { + for (size_t tail_done = 0; tail_done < len;) { tail_done += 32; y = Rotate(x + y, 42) * k0 + v.second; w.first += Fetch64(s + len - tail_done + 16); @@ -459,6 +484,7 @@ uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed) { z += w.second + Fetch64(s + len - tail_done); w.second += v.first; v = WeakHashLen32WithSeeds(s + len - tail_done, v.first + z, v.second); + v.first *= k0; } // At this point our 56 bytes of state should contain more than // enough information for a strong 128-bit hash. We use two @@ -470,86 +496,102 @@ uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed) { } uint128 CityHash128(const char *s, size_t len) { - if (len >= 16) { - return CityHash128WithSeed(s + 16, - len - 16, - uint128(Fetch64(s) ^ k3, - Fetch64(s + 8))); - } else if (len >= 8) { - return CityHash128WithSeed(NULL, - 0, - uint128(Fetch64(s) ^ (len * k0), - Fetch64(s + len - 8) ^ k1)); - } else { - return CityHash128WithSeed(s, len, uint128(k0, k1)); - } + return len >= 16 + ? CityHash128WithSeed(s + 16, len - 16, + uint128(Fetch64(s), Fetch64(s + 8) + k0)) + : CityHash128WithSeed(s, len, uint128(k0, k1)); } -#if defined(__SSE4_2__) && defined(__x86_64__) +#ifdef __SSE4_2__ +#include "CityCrc.h" #include // Requires len >= 240. -static void CityHashCrc256Long(const char *s, size_t len, - uint32 seed, uint64 *result) { - uint64 a = Fetch64(s + 56) + k0; - uint64 b = Fetch64(s + 96) + k0; - uint64 c = result[0] = HashLen16(b, len); - uint64 d = result[1] = Fetch64(s + 120) * k0 + len; - uint64 e = Fetch64(s + 184) + seed; - uint64 f = seed; - uint64 g = 0; - uint64 h = 0; - uint64 i = 0; - uint64 j = 0; - uint64 t = c + d; +static void CityHashCrc256Long(const char *s, size_t len, uint32_t seed, uint64_t *result) { + uint64_t a = Fetch64(s + 56) + k0; + uint64_t b = Fetch64(s + 96) + k0; + uint64_t c = result[0] = HashLen16(b, len); + uint64_t d = result[1] = Fetch64(s + 120) * k0 + len; + uint64_t e = Fetch64(s + 184) + seed; + uint64_t f = 0; + uint64_t g = 0; + uint64_t h = c + d; + uint64_t x = seed; + uint64_t y = 0; + uint64_t z = 0; // 240 bytes of input per iter. size_t iters = len / 240; len -= iters * 240; do { -#define CHUNK(multiplier, z) \ - { \ - uint64 old_a = a; \ - a = Rotate(b, 41 ^ z) * multiplier + Fetch64(s); \ - b = Rotate(c, 27 ^ z) * multiplier + Fetch64(s + 8); \ - c = Rotate(d, 41 ^ z) * multiplier + Fetch64(s + 16); \ - d = Rotate(e, 33 ^ z) * multiplier + Fetch64(s + 24); \ - e = Rotate(t, 25 ^ z) * multiplier + Fetch64(s + 32); \ - t = old_a; \ - } \ - f = _mm_crc32_u64(f, a); \ - g = _mm_crc32_u64(g, b); \ - h = _mm_crc32_u64(h, c); \ - i = _mm_crc32_u64(i, d); \ - j = _mm_crc32_u64(j, e); \ - s += 40 - - CHUNK(1, 1); CHUNK(k0, 0); - CHUNK(1, 1); CHUNK(k0, 0); - CHUNK(1, 1); CHUNK(k0, 0); +#undef CHUNK +#define CHUNK(r) \ + PERMUTE3(x, z, y); \ + b += Fetch64(s); \ + c += Fetch64(s + 8); \ + d += Fetch64(s + 16); \ + e += Fetch64(s + 24); \ + f += Fetch64(s + 32); \ + a += b; \ + h += f; \ + b += c; \ + f += d; \ + g += e; \ + e += z; \ + g += x; \ + z = _mm_crc32_u64(z, b + g); \ + y = _mm_crc32_u64(y, e + h); \ + x = _mm_crc32_u64(x, f + a); \ + e = Rotate(e, r); \ + c += e; \ + s += 40 + + CHUNK(0); + PERMUTE3(a, h, c); + CHUNK(33); + PERMUTE3(a, h, f); + CHUNK(0); + PERMUTE3(b, h, f); + CHUNK(42); + PERMUTE3(b, h, d); + CHUNK(0); + PERMUTE3(b, h, e); + CHUNK(33); + PERMUTE3(a, h, e); } while (--iters > 0); while (len >= 40) { - CHUNK(k0, 0); + CHUNK(29); + e ^= Rotate(a, 20); + h += Rotate(b, 30); + g ^= Rotate(c, 40); + f += Rotate(d, 34); + PERMUTE3(c, h, g); len -= 40; } if (len > 0) { s = s + len - 40; - CHUNK(k0, 0); + CHUNK(33); + e ^= Rotate(a, 43); + h += Rotate(b, 42); + g ^= Rotate(c, 41); + f += Rotate(d, 40); } - j += i << 32; - a = HashLen16(a, j); - h += g << 32; - b += h; - c = HashLen16(c, f) + i; + result[0] ^= h; + result[1] ^= g; + g += h; + a = HashLen16(a, g + z); + x += y << 32; + b += x; + c = HashLen16(c, z) + h; d = HashLen16(d, e + result[0]); - j += e; - i += HashLen16(h, t); - e = HashLen16(a, d) + j; - f = HashLen16(b, c) + a; - g = HashLen16(j, i) + c; - result[0] = e + f + g + h; - a = ShiftMix((a + g) * k0) * k0 + b; + g += e; + h += HashLen16(x, f); + e = HashLen16(a, d) + g; + z = HashLen16(b, c) + a; + y = HashLen16(g, h) + c; + result[0] = e + z + y + x; + a = ShiftMix((a + y) * k0) * k0 + b; result[1] += a + result[0]; a = ShiftMix(a * k0) * k0 + c; result[2] = a + result[1]; @@ -558,14 +600,14 @@ static void CityHashCrc256Long(const char *s, size_t len, } // Requires len < 240. -static void CityHashCrc256Short(const char *s, size_t len, uint64 *result) { +static void CityHashCrc256Short(const char *s, size_t len, uint64_t *result) { char buf[240]; memcpy(buf, s, len); memset(buf + len, 0, 240 - len); - CityHashCrc256Long(buf, 240, ~static_cast(len), result); + CityHashCrc256Long(buf, 240, ~static_cast(len), result); } -void CityHashCrc256(const char *s, size_t len, uint64 *result) { +void CityHashCrc256(const char *s, size_t len, uint64_t *result) { if (LIKELY(len >= 240)) { CityHashCrc256Long(s, len, 0, result); } else { @@ -577,10 +619,10 @@ uint128 CityHashCrc128WithSeed(const char *s, size_t len, uint128 seed) { if (len <= 900) { return CityHash128WithSeed(s, len, seed); } else { - uint64 result[4]; + uint64_t result[4]; CityHashCrc256(s, len, result); - uint64 u = Uint128High64(seed) + result[0]; - uint64 v = Uint128Low64(seed) + result[1]; + uint64_t u = Uint128High64(seed) + result[0]; + uint64_t v = Uint128Low64(seed) + result[1]; return uint128(HashLen16(u, v + result[2]), HashLen16(Rotate(v, 32), u * k0 + result[3])); } @@ -590,7 +632,7 @@ uint128 CityHashCrc128(const char *s, size_t len) { if (len <= 900) { return CityHash128(s, len); } else { - uint64 result[4]; + uint64_t result[4]; CityHashCrc256(s, len, result); return uint128(result[2], result[3]); } diff --git a/City.h b/City.h index baa8ddde..310f4198 100644 --- a/City.h +++ b/City.h @@ -1,10 +1,10 @@ // 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 +// 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 @@ -14,9 +14,9 @@ // 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. +// 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, by Geoff Pike and Jyrki Alakuijala // @@ -33,8 +33,9 @@ // Functions in the CityHash family are not suitable for cryptography. // // WARNING: This code has not been tested on big-endian platforms! -// It is known to work well on little-endian platforms that have a small penalty -// for unaligned reads, such as current Intel and AMD moderate-to-high-end CPUs. +// It is known to work well on little-endian platforms that have a small +// penalty for unaligned reads, such as current Intel and AMD +// moderate-to-high-end CPUs. // // By the way, for some hash functions, given strings a and b, the hash // of a+b is easily derived from the hashes of a and b. This property @@ -44,30 +45,26 @@ #define CITY_HASH_H_ #include "Platform.h" -#include // for size_t. -//#include +#include // for size_t. +// #include #include -typedef uint8_t uint8; -typedef uint32_t uint32; -typedef uint64_t uint64; -typedef std::pair uint128; +typedef std::pair uint128; -inline uint64 Uint128Low64(const uint128& x) { return x.first; } -inline uint64 Uint128High64(const uint128& x) { return x.second; } +inline uint64_t Uint128Low64(const uint128 &x) { return x.first; } +inline uint64_t Uint128High64(const uint128 &x) { return x.second; } // Hash functions for a byte array. -uint32 CityHash32WithSeed(const char *buf, size_t len, uint32 seed); -uint64 CityHash64(const char *buf, size_t len); +uint32_t CityHash32WithSeed(const char *buf, size_t len, uint32_t seed); +uint64_t CityHash64(const char *buf, size_t len); // Hash function for a byte array. For convenience, a 64-bit seed is also // hashed into the result. -uint64 CityHash64WithSeed(const char *buf, size_t len, uint64 seed); +uint64_t CityHash64WithSeed(const char *buf, size_t len, uint64_t seed); // Hash function for a byte array. For convenience, two seeds are also // hashed into the result. -uint64 CityHash64WithSeeds(const char *buf, size_t len, - uint64 seed0, uint64 seed1); +uint64_t CityHash64WithSeeds(const char *buf, size_t len, uint64_t seed0, uint64_t seed1); // Hash function for a byte array. uint128 CityHash128(const char *s, size_t len); @@ -78,12 +75,12 @@ uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed); // Hash 128 input bits down to 64 bits of output. // This is intended to be a reasonably good hash function. -inline uint64 Hash128to64(const uint128& x) { +inline uint64_t Hash128to64(const uint128 &x) { // Murmur-inspired hashing. - const uint64 kMul = 0x9ddfea08eb382d69ULL; - uint64 a = (Uint128Low64(x) ^ Uint128High64(x)) * kMul; + const uint64_t kMul = 0x9ddfea08eb382d69ULL; + uint64_t a = (Uint128Low64(x) ^ Uint128High64(x)) * kMul; a ^= (a >> 47); - uint64 b = (Uint128High64(x) ^ a) * kMul; + uint64_t b = (Uint128High64(x) ^ a) * kMul; b ^= (b >> 47); b *= kMul; return b; @@ -101,8 +98,8 @@ uint128 CityHashCrc128(const char *s, size_t len); uint128 CityHashCrc128WithSeed(const char *s, size_t len, uint128 seed); // Hash function for a byte array. Sets result[0] ... result[3]. -void CityHashCrc256(const char *s, size_t len, uint64 *result); +void CityHashCrc256(const char *s, size_t len, uint64_t *result); -#endif // __SSE4_2__ +#endif // __SSE4_2__ -#endif // CITY_HASH_H_ +#endif // CITY_HASH_H_ diff --git a/CityCrc.h b/CityCrc.h index 6d9a87b1..8affb664 100644 --- a/CityCrc.h +++ b/CityCrc.h @@ -38,6 +38,6 @@ uint128 CityHashCrc128(const char *s, size_t len); uint128 CityHashCrc128WithSeed(const char *s, size_t len, uint128 seed); // Hash function for a byte array. Sets result[0] ... result[3]. -void CityHashCrc256(const char *s, size_t len, uint64 *result); +void CityHashCrc256(const char *s, size_t len, uint64_t *result); #endif // CITY_HASH_CRC_H_ diff --git a/CityTest.cpp b/CityTest.cpp index 67e9d264..d2901067 100644 --- a/CityTest.cpp +++ b/CityTest.cpp @@ -1,40 +1,41 @@ #include "City.h" #include "CityCrc.h" -void CityHash32_test ( const void * key, int len, uint32_t seed, void * out ) -{ +void CityHash32_test(const void *key, int len, uint32_t seed, void *out) { // objsize 0-527: 1319 - *(uint32*)out = CityHash32WithSeed((const char *)key,len,seed); + *(uint32_t *)out = CityHash32WithSeed((const char *)key, len, seed); } -void CityHash64_test ( const void * key, int len, uint32_t seed, void * out ) -{ - // objsize 1038 + a20-a72: 82 = 1120 - *(uint64*)out = CityHash64WithSeed((const char *)key,len,seed); +void CityHash64_test(const void *key, int len, uint32_t seed, void *out) { + // objsize 1038 + a20-a72: 82 = 1120 + *(uint64_t *)out = CityHash64WithSeed((const char *)key, len, seed); } -void CityHash64noSeed_test ( const void * key, int len, uint32_t seed, void * out ) -{ +void CityHash64noSeed_test(const void *key, int len, uint32_t seed, void *out) { // objsize 530-93e: 1038 - *(uint64*)out = CityHash64((const char *)key,len); (void)seed; + *(uint64_t *)out = CityHash64((const char *)key, len); + (void)seed; } #if defined(HAVE_SSE42) && defined(__x86_64__) -void CityHash128_test ( const void * key, int len, uint32_t seed, void * out ) -{ - uint128 s(0,0); +void CityHash128_test(const void *key, int len, uint32_t seed, void *out) { + uint128 s(0, 0); s.first = seed; // objsize ad0-1201: 1841 - *(uint128*)out = CityHash128WithSeed((const char*)key,len,s); + *(uint128 *)out = CityHash128WithSeed((const char *)key, len, s); } -void CityHashCrc128_test ( const void * key, int len, uint32_t seed, void * out ) -{ - uint128 s(0,0); +void CityHashCrc128_test(const void *key, int len, uint32_t seed, void *out) { + uint128 s(0, 0); s.first = seed; // objsize 1940-1a67: 295 - *(uint128*)out = CityHashCrc128WithSeed((const char*)key,len,s); + *(uint128 *)out = CityHashCrc128WithSeed((const char *)key, len, s); +} + +void CityHashCrc256_test(const void *key, int len, uint32_t seed, void *out) { + CityHashCrc256((const char *)key, len, (uint64_t *)out); + (void)seed; } #endif diff --git a/Hashes.h b/Hashes.h index c3f2f52b..4e8e20e6 100644 --- a/Hashes.h +++ b/Hashes.h @@ -87,9 +87,9 @@ static inline bool crc64c_bad_seeds(std::vector &seeds) seeds = std::vector { UINT64_C(0) }; return true; } -void CityHashCrc64_test(const void *key, int len, uint32_t seed, void *out); #if defined(__x86_64__) void CityHashCrc128_test(const void *key, int len, uint32_t seed, void *out); +void CityHashCrc256_test(const void *key, int len, uint32_t seed, void *out); #endif #endif diff --git a/main.cpp b/main.cpp index eeb920ae..f483ec56 100644 --- a/main.cpp +++ b/main.cpp @@ -354,7 +354,7 @@ HashInfo g_hashes[] = # endif # endif #endif -{ CityHash32_test, 32, 0x5C28AD62, "City32", "Google CityHash32WithSeed (old)", POOR, {0x2eb38c9f} /* !! */}, +{ CityHash32_test, 32, 0xEDED9084, "City32", "Google CityHash32WithSeed (v1.1)", POOR, {0x2eb38c9f} /* !! */}, #ifdef HAVE_INT64 { metrohash64_test, 64, 0x6FA828C9, "metrohash64", "MetroHash64, 64-bit", POOR, {} }, { metrohash64_1_test, 64, 0xEE88F7D2, "metrohash64_1", "MetroHash64_1, 64-bit (legacy)", POOR, {} }, @@ -372,8 +372,8 @@ HashInfo g_hashes[] = { metrohash128crc_1_test,128, 0x5E75144E, "metrohash128crc_1", "MetroHash128crc_1 for x64 (legacy)", GOOD, {} }, { metrohash128crc_2_test,128, 0x1ACF3E77, "metrohash128crc_2", "MetroHash128crc_2 for x64 (legacy)", GOOD, {} }, #endif -{ CityHash64noSeed_test, 64, 0x63FC6063, "City64noSeed","Google CityHash64 without seed (default version, misses one final avalanche)", POOR, {} }, -{ CityHash64_test, 64, 0x25A20825, "City64", "Google CityHash64WithSeed (old)", POOR, {} }, +{ CityHash64noSeed_test, 64, 0x4C4E54B1, "City64noSeed","Google CityHash64 without seed (v1.1)(default version, misses one final avalanche)", POOR, {} }, +{ CityHash64_test, 64, 0x5FABC5C5, "City64", "Google CityHash64WithSeed (v1.1)", POOR, {} }, #if defined(HAVE_SSE2) && defined(HAVE_AESNI) && !defined(_MSC_VER) { aesnihash_test, 64, 0xA68E0D42, "aesnihash", "majek's seeded aesnihash with aesenc, 64-bit for x64", POOR, {0x70736575} }, @@ -649,10 +649,11 @@ HashInfo g_hashes[] = { mirhashstrict32low, 32, 0xD50D1F09, "mirhashstrict32low", "mirhashstrict - lower 32bit", POOR, {0x7fcc747f} /* !! */ }, #endif -{ CityHash64_low_test, 32, 0xCC5BC861, "City64low", "Google CityHash64WithSeed (low 32-bits)", GOOD, {} }, +{ CityHash64_low_test, 32, 0x6C4EF416, "City64low", "Google CityHash64WithSeed (v1.1)(low 32-bits)", GOOD, {} }, #if defined(HAVE_SSE42) && defined(__x86_64__) -{ CityHash128_test, 128, 0x6531F54E, "City128", "Google CityHash128WithSeed (old)", GOOD, {} }, -{ CityHashCrc128_test, 128, 0xD4389C97, "CityCrc128", "Google CityHashCrc128WithSeed SSE4.2 (old)", GOOD, {} }, +{ CityHash128_test, 128, 0x305C0D9A, "City128", "Google CityHash128WithSeed (v1.1)", GOOD, {} }, +{ CityHashCrc128_test, 128, 0x98C09AB4, "CityCrc128", "Google CityHashCrc128WithSeed SSE4.2 (v1.1)", GOOD, {} }, +{ CityHashCrc256_test, 256, 0x2A7036C8, "CityCrc256", "Google CityHashCrc256 SSE4.2 (v1.1)", GOOD, {} }, #endif #if defined(__FreeBSD__) || defined(HAVE_ASAN)