You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
604 lines
20 KiB
604 lines
20 KiB
4 years ago
|
#if NETSTANDARD
|
||
|
|
||
|
using System.Runtime.CompilerServices;
|
||
|
|
||
|
namespace MessagePack.Internal
|
||
|
{
|
||
|
public static class FarmHash
|
||
|
{
|
||
|
// entry point of 32bit
|
||
|
|
||
|
#region Hash32
|
||
|
|
||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
|
public static unsafe uint Hash32(byte[] bytes, int offset, int count)
|
||
|
{
|
||
|
if (count <= 4)
|
||
|
{
|
||
|
return Hash32Len0to4(bytes, offset, (uint)count);
|
||
|
}
|
||
|
|
||
|
fixed (byte* p = &bytes[offset])
|
||
|
{
|
||
|
return Hash32(p, (uint)count);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// port of farmhash.cc, 32bit only
|
||
|
|
||
|
// Magic numbers for 32-bit hashing. Copied from Murmur3.
|
||
|
const uint c1 = 0xcc9e2d51;
|
||
|
const uint c2 = 0x1b873593;
|
||
|
|
||
|
static unsafe uint Fetch32(byte* p)
|
||
|
{
|
||
|
return *(uint*)p;
|
||
|
}
|
||
|
|
||
|
static uint Rotate32(uint val, int shift)
|
||
|
{
|
||
|
return shift == 0 ? val : ((val >> shift) | (val << (32 - shift)));
|
||
|
}
|
||
|
|
||
|
// A 32-bit to 32-bit integer hash copied from Murmur3.
|
||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
|
static uint fmix(uint h)
|
||
|
{
|
||
|
unchecked
|
||
|
{
|
||
|
h ^= h >> 16;
|
||
|
h *= 0x85ebca6b;
|
||
|
h ^= h >> 13;
|
||
|
h *= 0xc2b2ae35;
|
||
|
h ^= h >> 16;
|
||
|
return h;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
|
static uint Mur(uint a, uint h)
|
||
|
{
|
||
|
unchecked
|
||
|
{
|
||
|
// Helper from Murmur3 for combining two 32-bit values.
|
||
|
a *= c1;
|
||
|
a = Rotate32(a, 17);
|
||
|
a *= c2;
|
||
|
h ^= a;
|
||
|
h = Rotate32(h, 19);
|
||
|
return h * 5 + 0xe6546b64;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 0-4
|
||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
|
static unsafe uint Hash32Len0to4(byte[] s, int offset, uint len)
|
||
|
{
|
||
|
unchecked
|
||
|
{
|
||
|
uint b = 0;
|
||
|
uint c = 9;
|
||
|
var max = offset + len;
|
||
|
for (int i = offset; i < max; i++)
|
||
|
{
|
||
|
b = b * c1 + s[i];
|
||
|
c ^= b;
|
||
|
}
|
||
|
return fmix(Mur(b, Mur(len, c)));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 5-12
|
||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
|
static unsafe uint Hash32Len5to12(byte* s, uint len)
|
||
|
{
|
||
|
unchecked
|
||
|
{
|
||
|
uint a = len, b = len * 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))));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 13-24
|
||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
|
static unsafe uint Hash32Len13to24(byte* s, uint len)
|
||
|
{
|
||
|
unchecked
|
||
|
{
|
||
|
uint a = Fetch32(s - 4 + (len >> 1));
|
||
|
uint b = Fetch32(s + 4);
|
||
|
uint c = Fetch32(s + len - 8);
|
||
|
uint d = Fetch32(s + (len >> 1));
|
||
|
uint e = Fetch32(s);
|
||
|
uint f = Fetch32(s + len - 4);
|
||
|
uint h = d * c1 + len;
|
||
|
a = Rotate32(a, 12) + f;
|
||
|
h = Mur(c, h) + a;
|
||
|
a = Rotate32(a, 3) + c;
|
||
|
h = Mur(e, h) + a;
|
||
|
a = Rotate32(a + f, 12) + d;
|
||
|
h = Mur(b, h) + a;
|
||
|
return fmix(h);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
|
static unsafe uint Hash32(byte* s, uint len)
|
||
|
{
|
||
|
if (len <= 24)
|
||
|
{
|
||
|
return len <= 12 ? Hash32Len5to12(s, len) : Hash32Len13to24(s, len);
|
||
|
}
|
||
|
|
||
|
unchecked
|
||
|
{
|
||
|
// len > 24
|
||
|
uint h = len, g = c1 * len, f = g;
|
||
|
uint a0 = Rotate32(Fetch32(s + len - 4) * c1, 17) * c2;
|
||
|
uint a1 = Rotate32(Fetch32(s + len - 8) * c1, 17) * c2;
|
||
|
uint a2 = Rotate32(Fetch32(s + len - 16) * c1, 17) * c2;
|
||
|
uint a3 = Rotate32(Fetch32(s + len - 12) * c1, 17) * c2;
|
||
|
uint a4 = Rotate32(Fetch32(s + len - 20) * c1, 17) * c2;
|
||
|
h ^= a0;
|
||
|
h = Rotate32(h, 19);
|
||
|
h = h * 5 + 0xe6546b64;
|
||
|
h ^= a2;
|
||
|
h = Rotate32(h, 19);
|
||
|
h = h * 5 + 0xe6546b64;
|
||
|
g ^= a1;
|
||
|
g = Rotate32(g, 19);
|
||
|
g = g * 5 + 0xe6546b64;
|
||
|
g ^= a3;
|
||
|
g = Rotate32(g, 19);
|
||
|
g = g * 5 + 0xe6546b64;
|
||
|
f += a4;
|
||
|
f = Rotate32(f, 19) + 113;
|
||
|
uint iters = (len - 1) / 20;
|
||
|
do
|
||
|
{
|
||
|
uint a = Fetch32(s);
|
||
|
uint b = Fetch32(s + 4);
|
||
|
uint c = Fetch32(s + 8);
|
||
|
uint d = Fetch32(s + 12);
|
||
|
uint e = Fetch32(s + 16);
|
||
|
h += a;
|
||
|
g += b;
|
||
|
f += c;
|
||
|
h = Mur(d, h) + e;
|
||
|
g = Mur(c, g) + a;
|
||
|
f = Mur(b + e * c1, f) + d;
|
||
|
f += g;
|
||
|
g += f;
|
||
|
s += 20;
|
||
|
} while (--iters != 0);
|
||
|
g = Rotate32(g, 11) * c1;
|
||
|
g = Rotate32(g, 17) * c1;
|
||
|
f = Rotate32(f, 11) * c1;
|
||
|
f = Rotate32(f, 17) * c1;
|
||
|
h = Rotate32(h + g, 19);
|
||
|
h = h * 5 + 0xe6546b64;
|
||
|
h = Rotate32(h, 17) * c1;
|
||
|
h = Rotate32(h + f, 19);
|
||
|
h = h * 5 + 0xe6546b64;
|
||
|
h = Rotate32(h, 17) * c1;
|
||
|
return h;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#region hash64
|
||
|
|
||
|
// entry point
|
||
|
|
||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
|
public static unsafe ulong Hash64(byte[] bytes, int offset, int count)
|
||
|
{
|
||
|
fixed (byte* p = &bytes[offset])
|
||
|
{
|
||
|
return Hash64(p, (uint)count);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// port from farmhash.cc
|
||
|
|
||
|
struct pair
|
||
|
{
|
||
|
public ulong first;
|
||
|
public ulong second;
|
||
|
|
||
|
public pair(ulong first, ulong second)
|
||
|
{
|
||
|
this.first = first;
|
||
|
this.second = second;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
|
static pair make_pair(ulong first, ulong second)
|
||
|
{
|
||
|
return new pair(first, second);
|
||
|
}
|
||
|
|
||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
|
static void swap(ref ulong x, ref ulong z)
|
||
|
{
|
||
|
var temp = z;
|
||
|
z = x;
|
||
|
x = temp;
|
||
|
}
|
||
|
|
||
|
// Some primes between 2^63 and 2^64 for various uses.
|
||
|
const ulong k0 = 0xc3a5c85c97cb3127UL;
|
||
|
const ulong k1 = 0xb492b66fbe98f273UL;
|
||
|
const ulong k2 = 0x9ae16a3b2f90404fUL;
|
||
|
|
||
|
static unsafe ulong Fetch64(byte* p)
|
||
|
{
|
||
|
return *(ulong*)p;
|
||
|
}
|
||
|
|
||
|
static ulong Rotate64(ulong val, int shift)
|
||
|
{
|
||
|
return shift == 0 ? val : (val >> shift) | (val << (64 - shift));
|
||
|
}
|
||
|
|
||
|
// farmhashna.cc
|
||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
|
static ulong ShiftMix(ulong val)
|
||
|
{
|
||
|
return val ^ (val >> 47);
|
||
|
}
|
||
|
|
||
|
// farmhashna.cc
|
||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
|
static ulong HashLen16(ulong u, ulong v, ulong mul)
|
||
|
{
|
||
|
unchecked
|
||
|
{
|
||
|
// Murmur-inspired hashing.
|
||
|
ulong a = (u ^ v) * mul;
|
||
|
a ^= a >> 47;
|
||
|
ulong b = (v ^ a) * mul;
|
||
|
b ^= b >> 47;
|
||
|
b *= mul;
|
||
|
return b;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// farmhashxo.cc
|
||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
|
static unsafe ulong Hash64(byte* s, uint len)
|
||
|
{
|
||
|
if (len <= 16)
|
||
|
{
|
||
|
// farmhashna::
|
||
|
return HashLen0to16(s, len);
|
||
|
}
|
||
|
|
||
|
if (len <= 32)
|
||
|
{
|
||
|
// farmhashna::
|
||
|
return HashLen17to32(s, len);
|
||
|
}
|
||
|
|
||
|
if (len <= 64)
|
||
|
{
|
||
|
return HashLen33to64(s, len);
|
||
|
}
|
||
|
|
||
|
if (len <= 96)
|
||
|
{
|
||
|
return HashLen65to96(s, len);
|
||
|
}
|
||
|
|
||
|
if (len <= 256)
|
||
|
{
|
||
|
// farmhashna::
|
||
|
return Hash64NA(s, len);
|
||
|
}
|
||
|
|
||
|
// farmhashuo::
|
||
|
return Hash64UO(s, len);
|
||
|
}
|
||
|
|
||
|
// 0-16 farmhashna.cc
|
||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
|
static unsafe ulong HashLen0to16(byte* s, uint len)
|
||
|
{
|
||
|
unchecked
|
||
|
{
|
||
|
if (len >= 8)
|
||
|
{
|
||
|
ulong mul = k2 + len * 2;
|
||
|
ulong a = Fetch64(s) + k2;
|
||
|
ulong b = Fetch64(s + len - 8);
|
||
|
ulong c = Rotate64(b, 37) * mul + a;
|
||
|
ulong d = (Rotate64(a, 25) + b) * mul;
|
||
|
return HashLen16(c, d, mul);
|
||
|
}
|
||
|
if (len >= 4)
|
||
|
{
|
||
|
ulong mul = k2 + len * 2;
|
||
|
ulong a = Fetch32(s);
|
||
|
return HashLen16(len + (a << 3), Fetch32(s + len - 4), mul);
|
||
|
}
|
||
|
if (len > 0)
|
||
|
{
|
||
|
ushort a = s[0];
|
||
|
ushort b = s[len >> 1];
|
||
|
ushort c = s[len - 1];
|
||
|
uint y = a + ((uint)b << 8);
|
||
|
uint z = len + ((uint)c << 2);
|
||
|
return ShiftMix(y * k2 ^ z * k0) * k2;
|
||
|
}
|
||
|
return k2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 17-32 farmhashna.cc
|
||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
|
static unsafe ulong HashLen17to32(byte* s, uint len)
|
||
|
{
|
||
|
unchecked
|
||
|
{
|
||
|
ulong mul = k2 + len * 2;
|
||
|
ulong a = Fetch64(s) * k1;
|
||
|
ulong b = Fetch64(s + 8);
|
||
|
ulong c = Fetch64(s + len - 8) * mul;
|
||
|
ulong d = Fetch64(s + len - 16) * k2;
|
||
|
return HashLen16(Rotate64(a + b, 43) + Rotate64(c, 30) + d,
|
||
|
a + Rotate64(b + k2, 18) + c, mul);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// farmhashxo.cc
|
||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
|
static unsafe ulong H32(byte* s, uint len, ulong mul, ulong seed0 = 0, ulong seed1 = 0)
|
||
|
{
|
||
|
unchecked
|
||
|
{
|
||
|
ulong a = Fetch64(s) * k1;
|
||
|
ulong b = Fetch64(s + 8);
|
||
|
ulong c = Fetch64(s + len - 8) * mul;
|
||
|
ulong d = Fetch64(s + len - 16) * k2;
|
||
|
ulong u = Rotate64(a + b, 43) + Rotate64(c, 30) + d + seed0;
|
||
|
ulong v = a + Rotate64(b + k2, 18) + c + seed1;
|
||
|
a = ShiftMix((u ^ v) * mul);
|
||
|
b = ShiftMix((v ^ a) * mul);
|
||
|
return b;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 33-64 farmhashxo.cc
|
||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
|
static unsafe ulong HashLen33to64(byte* s, uint len)
|
||
|
{
|
||
|
const ulong mul0 = k2 - 30;
|
||
|
|
||
|
unchecked
|
||
|
{
|
||
|
ulong mul1 = k2 - 30 + 2 * len;
|
||
|
ulong h0 = H32(s, 32, mul0);
|
||
|
ulong h1 = H32(s + len - 32, 32, mul1);
|
||
|
return (h1 * mul1 + h0) * mul1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 65-96 farmhashxo.cc
|
||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
|
static unsafe ulong HashLen65to96(byte* s, uint len)
|
||
|
{
|
||
|
const ulong mul0 = k2 - 114;
|
||
|
|
||
|
unchecked
|
||
|
{
|
||
|
ulong mul1 = k2 - 114 + 2 * len;
|
||
|
ulong h0 = H32(s, 32, mul0);
|
||
|
ulong h1 = H32(s + 32, 32, mul1);
|
||
|
ulong h2 = H32(s + len - 32, 32, mul1, h0, h1);
|
||
|
return (h2 * 9 + (h0 >> 17) + (h1 >> 21)) * mul1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// farmhashna.cc
|
||
|
// Return a 16-byte hash for 48 bytes. Quick and dirty.
|
||
|
// Callers do best to use "random-looking" values for a and b.
|
||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
|
static unsafe pair WeakHashLen32WithSeeds(ulong w, ulong x, ulong y, ulong z, ulong a, ulong b)
|
||
|
{
|
||
|
unchecked
|
||
|
{
|
||
|
a += w;
|
||
|
b = Rotate64(b + a + z, 21);
|
||
|
ulong c = a;
|
||
|
a += x;
|
||
|
a += y;
|
||
|
b += Rotate64(a, 44);
|
||
|
return make_pair(a + z, b + c);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// farmhashna.cc
|
||
|
// Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty.
|
||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
|
static unsafe pair WeakHashLen32WithSeeds(byte* s, ulong a, ulong b)
|
||
|
{
|
||
|
return WeakHashLen32WithSeeds(Fetch64(s),
|
||
|
Fetch64(s + 8),
|
||
|
Fetch64(s + 16),
|
||
|
Fetch64(s + 24),
|
||
|
a,
|
||
|
b);
|
||
|
}
|
||
|
|
||
|
// na(97-256) farmhashna.cc
|
||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
|
static unsafe ulong Hash64NA(byte* s, uint len)
|
||
|
{
|
||
|
const ulong seed = 81;
|
||
|
|
||
|
unchecked
|
||
|
{
|
||
|
// For strings over 64 bytes we loop. Internal state consists of
|
||
|
// 56 bytes: v, w, x, y, and z.
|
||
|
ulong x = seed;
|
||
|
ulong y = seed * k1 + 113;
|
||
|
ulong z = ShiftMix(y * k2 + 113) * k2;
|
||
|
var v = make_pair(0, 0);
|
||
|
var w = make_pair(0, 0);
|
||
|
x = x * k2 + Fetch64(s);
|
||
|
|
||
|
// Set end so that after the loop we have 1 to 64 bytes left to process.
|
||
|
byte* end = s + ((len - 1) / 64) * 64;
|
||
|
byte* last64 = end + ((len - 1) & 63) - 63;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
x = Rotate64(x + y + v.first + Fetch64(s + 8), 37) * k1;
|
||
|
y = Rotate64(y + v.second + Fetch64(s + 48), 42) * k1;
|
||
|
x ^= w.second;
|
||
|
y += v.first + Fetch64(s + 40);
|
||
|
z = Rotate64(z + w.first, 33) * k1;
|
||
|
v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);
|
||
|
w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));
|
||
|
swap(ref z, ref x);
|
||
|
s += 64;
|
||
|
} while (s != end);
|
||
|
ulong mul = k1 + ((z & 0xff) << 1);
|
||
|
// Make s point to the last 64 bytes of input.
|
||
|
s = last64;
|
||
|
w.first += ((len - 1) & 63);
|
||
|
v.first += w.first;
|
||
|
w.first += v.first;
|
||
|
x = Rotate64(x + y + v.first + Fetch64(s + 8), 37) * mul;
|
||
|
y = Rotate64(y + v.second + Fetch64(s + 48), 42) * mul;
|
||
|
x ^= w.second * 9;
|
||
|
y += v.first * 9 + Fetch64(s + 40);
|
||
|
z = Rotate64(z + w.first, 33) * mul;
|
||
|
v = WeakHashLen32WithSeeds(s, v.second * mul, x + w.first);
|
||
|
w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));
|
||
|
swap(ref z, ref x);
|
||
|
return HashLen16(HashLen16(v.first, w.first, mul) + ShiftMix(y) * k0 + z,
|
||
|
HashLen16(v.second, w.second, mul) + x,
|
||
|
mul);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// farmhashuo.cc
|
||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
|
static ulong H(ulong x, ulong y, ulong mul, int r)
|
||
|
{
|
||
|
unchecked
|
||
|
{
|
||
|
ulong a = (x ^ y) * mul;
|
||
|
a ^= (a >> 47);
|
||
|
ulong b = (y ^ a) * mul;
|
||
|
return Rotate64(b, r) * mul;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// uo(257-) farmhashuo.cc, Hash64WithSeeds
|
||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
|
static unsafe ulong Hash64UO(byte* s, uint len)
|
||
|
{
|
||
|
const ulong seed0 = 81;
|
||
|
const ulong seed1 = 0;
|
||
|
|
||
|
unchecked
|
||
|
{
|
||
|
// 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 * k2 + 113;
|
||
|
ulong z = ShiftMix(y * k2) * k2;
|
||
|
var v = make_pair(seed0, seed1);
|
||
|
var w = make_pair(0, 0);
|
||
|
ulong u = x - z;
|
||
|
x *= k2;
|
||
|
ulong mul = k2 + (u & 0x82);
|
||
|
|
||
|
// Set end so that after the loop we have 1 to 64 bytes left to process.
|
||
|
byte* end = s + ((len - 1) / 64) * 64;
|
||
|
byte* last64 = end + ((len - 1) & 63) - 63;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
ulong a0 = Fetch64(s);
|
||
|
ulong a1 = Fetch64(s + 8);
|
||
|
ulong a2 = Fetch64(s + 16);
|
||
|
ulong a3 = Fetch64(s + 24);
|
||
|
ulong a4 = Fetch64(s + 32);
|
||
|
ulong a5 = Fetch64(s + 40);
|
||
|
ulong a6 = Fetch64(s + 48);
|
||
|
ulong a7 = Fetch64(s + 56);
|
||
|
x += a0 + a1;
|
||
|
y += a2;
|
||
|
z += a3;
|
||
|
v.first += a4;
|
||
|
v.second += a5 + a1;
|
||
|
w.first += a6;
|
||
|
w.second += a7;
|
||
|
|
||
|
x = Rotate64(x, 26);
|
||
|
x *= 9;
|
||
|
y = Rotate64(y, 29);
|
||
|
z *= mul;
|
||
|
v.first = Rotate64(v.first, 33);
|
||
|
v.second = Rotate64(v.second, 30);
|
||
|
w.first ^= x;
|
||
|
w.first *= 9;
|
||
|
z = Rotate64(z, 32);
|
||
|
z += w.second;
|
||
|
w.second += z;
|
||
|
z *= 9;
|
||
|
swap(ref u, ref y);
|
||
|
|
||
|
z += a0 + a6;
|
||
|
v.first += a2;
|
||
|
v.second += a3;
|
||
|
w.first += a4;
|
||
|
w.second += a5 + a6;
|
||
|
x += a1;
|
||
|
y += a7;
|
||
|
|
||
|
y += v.first;
|
||
|
v.first += x - y;
|
||
|
v.second += w.first;
|
||
|
w.first += v.second;
|
||
|
w.second += x - y;
|
||
|
x += w.second;
|
||
|
w.second = Rotate64(w.second, 34);
|
||
|
swap(ref u, ref z);
|
||
|
s += 64;
|
||
|
} while (s != end);
|
||
|
// Make s point to the last 64 bytes of input.
|
||
|
s = last64;
|
||
|
u *= 9;
|
||
|
v.second = Rotate64(v.second, 28);
|
||
|
v.first = Rotate64(v.first, 20);
|
||
|
w.first += ((len - 1) & 63);
|
||
|
u += y;
|
||
|
y += u;
|
||
|
x = Rotate64(y - x + v.first + Fetch64(s + 8), 37) * mul;
|
||
|
y = Rotate64(y ^ v.second ^ Fetch64(s + 48), 42) * mul;
|
||
|
x ^= w.second * 9;
|
||
|
y += v.first + Fetch64(s + 40);
|
||
|
z = Rotate64(z + w.first, 33) * mul;
|
||
|
v = WeakHashLen32WithSeeds(s, v.second * mul, x + w.first);
|
||
|
w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));
|
||
|
return H(HashLen16(v.first + x, w.first ^ y, mul) + z - u,
|
||
|
H(v.second + y, w.second + z, k2, 30) ^ x,
|
||
|
k2,
|
||
|
31);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|