static UInt128 CityHash128WithSeed(byte[] s, int len, UInt128 seed, int off) { if (len < 128) { return(CityMurmur(s, len, seed, off)); } // We expect len >= 128 to be the common case. Keep 56 bytes of state: // v, w, x, y, and z. UInt128 v = new UInt128(), w = new UInt128(); ulong x = seed.Low; ulong y = seed.High; ulong z = (ulong)len * k1; v.Low = Rotate(y ^ k1, 49) * k1 + Fetch64(s, off); v.High = Rotate(v.Low, 42) * k1 + Fetch64(s, off + 8); w.Low = Rotate(y + z, 35) * k1 + x; w.High = Rotate(x + Fetch64(s, off + 88), 53) * k1; // This is the same inner loop as CityHash64(), manually unrolled. ulong swp; do { x = Rotate(x + y + v.Low + Fetch64(s, off + 16), 37) * k1; y = Rotate(y + v.High + Fetch64(s, off + 48), 42) * k1; x ^= w.High; y ^= v.Low; z = Rotate(z ^ w.Low, 33); v = WeakHashLen32WithSeeds(s, v.High * k1, x + w.Low, off); w = WeakHashLen32WithSeeds(s, z + w.High, y, off + 32); swp = z; z = x; x = swp; off += 64; x = Rotate(x + y + v.Low + Fetch64(s, off + 16), 37) * k1; y = Rotate(y + v.High + Fetch64(s, off + 48), 42) * k1; x ^= w.High; y ^= v.Low; z = Rotate(z ^ w.Low, 33); v = WeakHashLen32WithSeeds(s, v.High * k1, x + w.Low, off); w = WeakHashLen32WithSeeds(s, z + w.High, y, off + 32); swp = z; z = x; x = swp; off += 64; len -= 128; } while ((len >= 128)); y += Rotate(w.Low, 37) * k0 + z; x += Rotate(v.Low + z, 49) * k0; // If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s. for (int tail_done = 0; tail_done < len;) { tail_done += 32; y = Rotate(y - x, 42) * k0 + v.High; w.Low += Fetch64(s, off + len - tail_done + 16); x = Rotate(x, 49) * k0 + w.Low; w.Low += v.Low; v = WeakHashLen32WithSeeds(s, v.Low, v.High, off + len - tail_done); } // 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.Low); y = HashLen16(y, w.Low); return(new UInt128(HashLen16(x + v.High, w.High) + y, HashLen16(x + w.High, y + v.High))); }
protected abstract byte[] Decompress(Stream compressed, out UInt128 compressedHash);