|
|
|
|
using System;
|
|
|
|
|
|
|
|
|
|
namespace ZeroLevel.Services.HashFunctions
|
|
|
|
|
{
|
|
|
|
|
public class XXHashUnsafe
|
|
|
|
|
: IHash
|
|
|
|
|
{
|
|
|
|
|
private const uint Seed = 0xc58f1a7b;
|
|
|
|
|
|
|
|
|
|
private const uint PRIME1 = 2654435761U;
|
|
|
|
|
private const uint PRIME2 = 2246822519U;
|
|
|
|
|
private const uint PRIME3 = 3266489917U;
|
|
|
|
|
private const uint PRIME4 = 668265263U;
|
|
|
|
|
private const int PRIME5 = 0x165667b1;
|
|
|
|
|
|
|
|
|
|
private uint _bias;
|
|
|
|
|
|
|
|
|
|
public XXHashUnsafe(uint bias = 0) => _bias = bias;
|
|
|
|
|
|
|
|
|
|
public unsafe UInt32 Hash(string s)
|
|
|
|
|
{
|
|
|
|
|
fixed (char* input = s)
|
|
|
|
|
{
|
|
|
|
|
return Hash((byte*)input, (uint)s.Length * sizeof(char), Seed, _bias);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public unsafe uint Hash(byte[] data)
|
|
|
|
|
{
|
|
|
|
|
fixed (byte* input = &data[0])
|
|
|
|
|
{
|
|
|
|
|
return Hash(input, (uint)data.Length, Seed, _bias);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public unsafe uint Hash(byte[] data, int offset, uint len, uint seed)
|
|
|
|
|
{
|
|
|
|
|
fixed (byte* input = &data[offset])
|
|
|
|
|
{
|
|
|
|
|
return Hash(input, len, seed, _bias);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private unsafe static uint Hash(byte* data, uint len, uint seed, uint bias)
|
|
|
|
|
{
|
|
|
|
|
if (len < 16)
|
|
|
|
|
return HashSmall(data, len, seed, bias);
|
|
|
|
|
|
|
|
|
|
uint v1 = seed + PRIME1 + bias;
|
|
|
|
|
uint v2 = v1 * PRIME2 + len;
|
|
|
|
|
uint v3 = v2 * PRIME3;
|
|
|
|
|
uint v4 = v3 * PRIME4;
|
|
|
|
|
|
|
|
|
|
uint* p = (uint*)data;
|
|
|
|
|
uint* limit = (uint*)(data + len - 16);
|
|
|
|
|
|
|
|
|
|
while (p < limit)
|
|
|
|
|
{
|
|
|
|
|
v1 += Rotl32(v1, 13); v1 *= PRIME1; v1 += *p; p++;
|
|
|
|
|
v2 += Rotl32(v2, 11); v2 *= PRIME1; v2 += *p; p++;
|
|
|
|
|
v3 += Rotl32(v3, 17); v3 *= PRIME1; v3 += *p; p++;
|
|
|
|
|
v4 += Rotl32(v4, 19); v4 *= PRIME1; v4 += *p; p++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p = limit;
|
|
|
|
|
v1 += Rotl32(v1, 17); v2 += Rotl32(v2, 19); v3 += Rotl32(v3, 13); v4 += Rotl32(v4, 11);
|
|
|
|
|
v1 *= PRIME1; v2 *= PRIME1; v3 *= PRIME1; v4 *= PRIME1;
|
|
|
|
|
v1 += *p; p++; v2 += *p; p++; v3 += *p; p++; v4 += *p;
|
|
|
|
|
v1 *= PRIME2; v2 *= PRIME2; v3 *= PRIME2; v4 *= PRIME2;
|
|
|
|
|
v1 += Rotl32(v1, 11); v2 += Rotl32(v2, 17); v3 += Rotl32(v3, 19); v4 += Rotl32(v4, 13);
|
|
|
|
|
v1 *= PRIME3; v2 *= PRIME3; v3 *= PRIME3; v4 *= PRIME3;
|
|
|
|
|
|
|
|
|
|
uint crc = v1 + Rotl32(v2, 3) + Rotl32(v3, 6) + Rotl32(v4, 9);
|
|
|
|
|
crc ^= crc >> 11;
|
|
|
|
|
crc += (PRIME4 + len) * PRIME1;
|
|
|
|
|
crc ^= crc >> 15;
|
|
|
|
|
crc *= PRIME2;
|
|
|
|
|
crc ^= crc >> 13;
|
|
|
|
|
return crc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private unsafe static uint HashSmall(byte* data, uint len, uint seed, uint bias)
|
|
|
|
|
{
|
|
|
|
|
byte* p = data;
|
|
|
|
|
byte* bEnd = data + len;
|
|
|
|
|
byte* limit = bEnd - 4;
|
|
|
|
|
|
|
|
|
|
uint idx = seed + PRIME1 + bias;
|
|
|
|
|
uint crc = PRIME5;
|
|
|
|
|
|
|
|
|
|
while (p < limit)
|
|
|
|
|
{
|
|
|
|
|
crc += (*(uint*)p) + idx;
|
|
|
|
|
idx++;
|
|
|
|
|
crc += Rotl32(crc, 17) * PRIME4;
|
|
|
|
|
crc *= PRIME1;
|
|
|
|
|
p += 4;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (p < bEnd)
|
|
|
|
|
{
|
|
|
|
|
crc += (*p) + idx;
|
|
|
|
|
idx++;
|
|
|
|
|
crc *= PRIME1;
|
|
|
|
|
p++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
crc += len;
|
|
|
|
|
|
|
|
|
|
crc ^= crc >> 15;
|
|
|
|
|
crc *= PRIME2;
|
|
|
|
|
crc ^= crc >> 13;
|
|
|
|
|
crc *= PRIME3;
|
|
|
|
|
crc ^= crc >> 16;
|
|
|
|
|
|
|
|
|
|
return crc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static UInt32 Rotl32(UInt32 x, int r)
|
|
|
|
|
{
|
|
|
|
|
return (x << r) | (x >> (32 - r));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|