예제 #1
0
        /// <summary>
        /// Computes the 128-bit city hash using a specific <paramref name="seed" />.
        /// This algorithm is tuned for strings of at least a few hundred bytes.
        /// </summary>
        /// <param name="value">The string value.</param>
        /// <param name="seed">Specifies the seed for the CityHash algorithm.</param>
        /// <returns>The 128-bit city hash.</returns>
        /// <exception cref="ArgumentNullException">value</exception>
        /// <remarks>This function encodes the string using the unicode block (ISO/IEC 8859-1).</remarks>
        public static uint128 GetCityHash128(this string value, uint128 seed)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }

            return(CityHash.CityHash128(value, seed));
        }
예제 #2
0
        private static ulong Hash128to64(uint128 x)
        {
            const ulong kMul = 0x9ddfea08eb382d69UL;

            var a = (x.Low ^ x.High) * kMul;

            a ^= (a >> 47);

            var b = (x.High ^ a) * kMul;

            b ^= (b >> 47);
            b *= kMul;

            return(b);
        }
예제 #3
0
        protected static uint128 CityMurmur(byte[] value, uint128 seed, int offset)
        {
            var   a = seed.Low;
            var   b = seed.High;
            ulong c;
            ulong d;

            var len = value.Length - offset;
            var l   = len - 16;

            if (l <= 0)    // len <= 16
            {
                a = ShiftMix(a * k1) * k1;
                c = b * k1 + HashLen0to16(value, offset);
                d = ShiftMix(a + (len >= 8 ? Fetch64(value, offset) : c));
            }
            else      // len > 16

            {
                c  = HashLen16(Fetch64(value, offset + len - 8) + k1, a);
                d  = HashLen16(b + (ulong)len, c + Fetch64(value, offset + len - 16));
                a += d;

                var p = offset;
                do
                {
                    a ^= ShiftMix(Fetch64(value, p) * k1) * k1;
                    a *= k1;
                    b ^= a;
                    c ^= ShiftMix(Fetch64(value, p + 8) * k1) * k1;
                    c *= k1;
                    d ^= c;

                    p += 16;
                    l -= 16;
                } while (l > 0);
            }
            a = HashLen16(a, c);
            b = HashLen16(d, b);
            return(new uint128(a ^ b, HashLen16(b, a)));
        }
예제 #4
0
        protected static uint128 CityHash128(byte[] value, uint128 seed, int offset)
        {
            if (value.Length - offset < 128)
            {
                return(CityMurmur(value, seed, offset));
            }

            // We expect len >= 128 to be the common case.  Keep 56 bytes of state:
            // v, w, x, y, and z.
            var len = value.Length - offset;
            var x   = seed.Low;
            var y   = seed.High;
            var z   = (ulong)len * k1;
            var v   = new uint128
            {
                Low = Rotate(seed.High ^ k1, 49) * k1 + Fetch64(value, offset)
            };

            v.High = Rotate(v.Low, 42) * k1 + Fetch64(value, offset + 8);

            var w = new uint128
            {
                Low  = Rotate(y + z, 35) * k1 + x,
                High = Rotate(seed.Low + Fetch64(value, offset + 88), 53) * k1
            };


            // This is the same inner loop as CityHash64(), manually unrolled.
            var s = offset;

            do
            {
                x  = Rotate(x + y + v.Low + Fetch64(value, s + 8), 37) * k1;
                y  = Rotate(y + v.High + Fetch64(value, s + 48), 42) * k1;
                x ^= w.High;
                y += v.Low + Fetch64(value, s + 40);
                z  = Rotate(z + w.Low, 33) * k1;
                v  = WeakHashLen32WithSeeds(value, s, v.High * k1, x + w.Low);
                w  = WeakHashLen32WithSeeds(value, s + 32, z + w.High, y + Fetch64(value, s + 16));

                Swap(ref z, ref x);

                s += 64;

                x  = Rotate(x + y + v.Low + Fetch64(value, s + 8), 37) * k1;
                y  = Rotate(y + v.High + Fetch64(value, s + 48), 42) * k1;
                x ^= w.High;
                y += v.Low + Fetch64(value, s + 40);
                z  = Rotate(z + w.Low, 33) * k1;
                v  = WeakHashLen32WithSeeds(value, s, v.High * k1, x + w.Low);
                w  = WeakHashLen32WithSeeds(value, s + 32, z + w.High, y + Fetch64(value, s + 16));

                Swap(ref z, ref x);

                s   += 64;
                len -= 128;
            } while (len >= 128);

            x     += Rotate(v.Low + z, 49) * k0;
            y      = y * k0 + Rotate(w.High, 37);
            z      = z * k0 + Rotate(w.Low, 27);
            w.Low *= 9;
            v.Low *= k0;

            // If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s.
            for (var tail = 0; tail < len;)
            {
                tail += 32;

                y       = Rotate(x + y, 42) * k0 + v.High;
                w.Low  += Fetch64(value, s + len - tail + 16);
                x       = x * k0 + w.Low;
                z      += w.High + Fetch64(value, s + len - tail);
                w.High += v.Low;
                v       = WeakHashLen32WithSeeds(value, s + len - tail, v.Low + z, v.High);
                v.Low  *= k0;
            }


            // At this point our 56 bytes of state should contain more than
            // enough information for a strong 128-bit hash.  We use two
            // different 56-byte-to-8-byte hashes to get a 16-byte final result.
            x = HashLen16(x, v.Low);
            y = HashLen16(y + z, w.Low);

            return(new uint128
            {
                Low = HashLen16(x + v.High, w.High) + y,
                High = HashLen16(x + w.High, y + v.High)
            });
        }
예제 #5
0
 public static uint128 CityHash128(string value, uint128 seed)
 {
     return(CityHash128(Encoding.GetEncoding("ISO-8859-1").GetBytes(value), seed, 0));
 }