// Hash 128 input bits down to 64 bits of output. // This is intended to be a reasonably good hash function. private static ulong Hash128To64(Uint128 x) { // Murmur-inspired hashing. const ulong kMul = 0x9ddfea08eb382d69UL; var a = (x.First ^ x.Second) * kMul; a ^= a >> 47; var b = (x.Second ^ a) * kMul; b ^= b >> 47; b *= kMul; return(b); }
private static unsafe ulong Hash64(byte *s, int len) { const ulong seed = 81; if (len <= 32) { if (len <= 16) { return(HashLen0to16(s, len)); } return(HashLen17to32(s, len)); } if (len <= 64) { return(HashLen33to64(s, len)); } // For strings over 64 bytes we loop. Internal state consists of 56 bytes: v, w, x, y, and z. ulong x = seed; ulong y = unchecked (seed * FarmHashConstants.k1) + 113; ulong z = FarmHash.ShiftMix(y * FarmHashConstants.k2 + 113) * FarmHashConstants.k2; Uint128 v = new Uint128(0, 0); Uint128 w = new Uint128(0, 0); x = x * FarmHashConstants.k2 + Utilities.Fetch64(s); // Set end so that after the loop we have 1 to 64 bytes left to process. int index = 0; int end = (len - 1) / 64 * 64; int last64 = end + ((len - 1) & 63) - 63; do { x = Utilities.RotateWithCheck(x + y + v.Low + Utilities.Fetch64(s, 8), 37) * FarmHashConstants.k1; y = Utilities.RotateWithCheck(y + v.High + Utilities.Fetch64(s, 48), 42) * FarmHashConstants.k1; x ^= w.High; y += v.Low + Utilities.Fetch64(s, 40); z = Utilities.RotateWithCheck(z + w.Low, 33) * FarmHashConstants.k1; v = WeakHashLen32WithSeeds(s, 0, v.High * FarmHashConstants.k1, x + w.Low); w = WeakHashLen32WithSeeds(s, 32, z + w.High, y + Utilities.Fetch64(s, 16)); Utilities.Swap(ref z, ref x); index += 64; } while (index != end); ulong mul = FarmHashConstants.k1 + ((z & 0xff) << 1); // Make s point to the last 64 bytes of input. index = last64; w.Low += ((uint)len - 1) & 63; v.Low += w.Low; w.Low += v.Low; x = Utilities.RotateWithCheck(x + y + v.Low + Utilities.Fetch64(s, index + 8), 37) * mul; y = Utilities.RotateWithCheck(y + v.High + Utilities.Fetch64(s, index + 48), 42) * mul; x ^= w.High * 9; y += v.Low * 9 + Utilities.Fetch64(s, index + 40); z = Utilities.RotateWithCheck(z + w.Low, 33) * mul; v = WeakHashLen32WithSeeds(s, index + 0, v.High * mul, x + w.Low); w = WeakHashLen32WithSeeds(s, index + 32, z + w.High, y + Utilities.Fetch64(s, index + 16)); Utilities.Swap(ref z, ref x); return(HashLen16(HashLen16(v.Low, w.Low, mul) + FarmHash.ShiftMix(y) * FarmHashConstants.k0 + z, HashLen16(v.High, w.High, mul) + x, mul)); }
private static unsafe ulong Hash64WithSeeds(byte *s, int len, ulong seed0, ulong seed1) { if (len <= 64) { return(HashLen16(Hash64(s, len) - seed0, seed1, 0x9ddfea08eb382d69UL)); //PORT NOTE: This used to refer to Hash128to64, which was the same as HashLen16, just with hardcoded mul } // For strings over 64 bytes we loop. Internal state consists of // 64 bytes: u, v, w, x, y, and z. ulong x = seed0; ulong y = seed1 * FarmHashConstants.k2 + 113; ulong z = FarmHash.ShiftMix(y * FarmHashConstants.k2) * FarmHashConstants.k2; Uint128 v = new Uint128(seed0, seed1); Uint128 w = new Uint128(0, 0); ulong u = x - z; x *= FarmHashConstants.k2; ulong mul = FarmHashConstants.k2 + (u & 0x82); // Set end so that after the loop we have 1 to 64 bytes left to process. int index = 0; int end = (len - 1) / 64 * 64; int last64 = end + ((len - 1) & 63) - 63; do { ulong a0 = Utilities.Fetch64(s); ulong a1 = Utilities.Fetch64(s, 8); ulong a2 = Utilities.Fetch64(s, 16); ulong a3 = Utilities.Fetch64(s, 24); ulong a4 = Utilities.Fetch64(s, 32); ulong a5 = Utilities.Fetch64(s, 40); ulong a6 = Utilities.Fetch64(s, 48); ulong a7 = Utilities.Fetch64(s, 56); x += a0 + a1; y += a2; z += a3; v.Low += a4; v.High += a5 + a1; w.Low += a6; w.High += a7; x = Utilities.RotateWithCheck(x, 26); x *= 9; y = Utilities.RotateWithCheck(y, 29); z *= mul; v.Low = Utilities.RotateWithCheck(v.Low, 33); v.High = Utilities.RotateWithCheck(v.High, 30); w.Low ^= x; w.Low *= 9; z = Utilities.RotateWithCheck(z, 32); z += w.High; w.High += z; z *= 9; Utilities.Swap(ref u, ref y); z += a0 + a6; v.Low += a2; v.High += a3; w.Low += a4; w.High += a5 + a6; x += a1; y += a7; y += v.Low; v.Low += x - y; v.High += w.Low; w.Low += v.High; w.High += x - y; x += w.High; w.High = Utilities.RotateWithCheck(w.High, 34); Utilities.Swap(ref u, ref z); index += 64; } while (index != end); // Make s point to the last 64 bytes of input. index = last64; u *= 9; v.High = Utilities.RotateWithCheck(v.High, 28); v.Low = Utilities.RotateWithCheck(v.Low, 20); w.Low += ((uint)len - 1) & 63; u += y; y += u; x = Utilities.RotateWithCheck(y - x + v.Low + Utilities.Fetch64(s, index + 8), 37) * mul; y = Utilities.RotateWithCheck(y ^ v.High ^ Utilities.Fetch64(s, index + 48), 42) * mul; x ^= w.High * 9; y += v.Low + Utilities.Fetch64(s, index + 40); z = Utilities.RotateWithCheck(z + w.Low, 33) * mul; v = WeakHashLen32WithSeeds(s, index + 0, v.High * mul, x + w.Low); w = WeakHashLen32WithSeeds(s, index + 32, z + w.High, y + Utilities.Fetch64(s, index + 16)); return(H(HashLen16(v.Low + x, w.Low ^ y, mul) + z - u, H(v.High + y, w.High + z, FarmHashConstants.k2, 30) ^ x, FarmHashConstants.k2, 31)); }