//
// Copyright (c) 2015-2019 Sedat Kapanoglu
// MIT License (see LICENSE file for details)
//
// @mfatihmar (Unity): Modified for Unity support
using System.Runtime.CompilerServices;
namespace MLAPI.Editor.CodeGen
{
///
/// XXHash implementation.
///
internal static class XXHash
{
private const ulong k_Prime64v1 = 11400714785074694791ul;
private const ulong k_Prime64v2 = 14029467366897019727ul;
private const ulong k_Prime64v3 = 1609587929392839161ul;
private const ulong k_Prime64v4 = 9650029242287828579ul;
private const ulong k_Prime64v5 = 2870177450012600261ul;
private const uint k_Prime32v1 = 2654435761u;
private const uint k_Prime32v2 = 2246822519u;
private const uint k_Prime32v3 = 3266489917u;
private const uint k_Prime32v4 = 668265263u;
private const uint k_Prime32v5 = 374761393u;
///
/// Generate a 32-bit xxHash value.
///
/// Input buffer.
/// Input buffer length.
/// Optional seed.
/// 32-bit hash value.
public static unsafe uint Hash32(byte* buffer, int bufferLength, uint seed = 0)
{
const int stripeLength = 16;
int len = bufferLength;
int remainingLen = len;
uint acc;
byte* pInput = buffer;
if (len >= stripeLength)
{
uint acc1 = seed + k_Prime32v1 + k_Prime32v2;
uint acc2 = seed + k_Prime32v2;
uint acc3 = seed;
uint acc4 = seed - k_Prime32v1;
do
{
acc = processStripe32(ref pInput, ref acc1, ref acc2, ref acc3, ref acc4);
remainingLen -= stripeLength;
} while (remainingLen >= stripeLength);
}
else
{
acc = seed + k_Prime32v5;
}
acc += (uint)len;
acc = processRemaining32(pInput, acc, remainingLen);
return avalanche32(acc);
}
///
/// Generate a 64-bit xxHash value.
///
/// Input buffer.
/// Input buffer length.
/// Optional seed.
/// Computed 64-bit hash value.
public static unsafe ulong Hash64(byte* buffer, int bufferLength, ulong seed = 0)
{
const int stripeLength = 32;
int len = bufferLength;
int remainingLen = len;
ulong acc;
byte* pInput = buffer;
if (len >= stripeLength)
{
ulong acc1 = seed + k_Prime64v1 + k_Prime64v2;
ulong acc2 = seed + k_Prime64v2;
ulong acc3 = seed;
ulong acc4 = seed - k_Prime64v1;
do
{
acc = processStripe64(ref pInput, ref acc1, ref acc2, ref acc3, ref acc4);
remainingLen -= stripeLength;
} while (remainingLen >= stripeLength);
}
else
{
acc = seed + k_Prime64v5;
}
acc += (ulong)len;
acc = processRemaining64(pInput, acc, remainingLen);
return avalanche64(acc);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe ulong processStripe64(
ref byte* pInput,
ref ulong acc1,
ref ulong acc2,
ref ulong acc3,
ref ulong acc4)
{
processLane64(ref acc1, ref pInput);
processLane64(ref acc2, ref pInput);
processLane64(ref acc3, ref pInput);
processLane64(ref acc4, ref pInput);
ulong acc = Bits.RotateLeft(acc1, 1)
+ Bits.RotateLeft(acc2, 7)
+ Bits.RotateLeft(acc3, 12)
+ Bits.RotateLeft(acc4, 18);
mergeAccumulator64(ref acc, acc1);
mergeAccumulator64(ref acc, acc2);
mergeAccumulator64(ref acc, acc3);
mergeAccumulator64(ref acc, acc4);
return acc;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void processLane64(ref ulong accn, ref byte* pInput)
{
ulong lane = *(ulong*)pInput;
accn = round64(accn, lane);
pInput += 8;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe ulong processRemaining64(
byte* pInput,
ulong acc,
int remainingLen)
{
for (ulong lane; remainingLen >= 8; remainingLen -= 8, pInput += 8)
{
lane = *(ulong*)pInput;
acc ^= round64(0, lane);
acc = Bits.RotateLeft(acc, 27) * k_Prime64v1;
acc += k_Prime64v4;
}
for (uint lane32; remainingLen >= 4; remainingLen -= 4, pInput += 4)
{
lane32 = *(uint*)pInput;
acc ^= lane32 * k_Prime64v1;
acc = Bits.RotateLeft(acc, 23) * k_Prime64v2;
acc += k_Prime64v3;
}
for (byte lane8; remainingLen >= 1; remainingLen--, pInput++)
{
lane8 = *pInput;
acc ^= lane8 * k_Prime64v5;
acc = Bits.RotateLeft(acc, 11) * k_Prime64v1;
}
return acc;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong avalanche64(ulong acc)
{
acc ^= acc >> 33;
acc *= k_Prime64v2;
acc ^= acc >> 29;
acc *= k_Prime64v3;
acc ^= acc >> 32;
return acc;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong round64(ulong accn, ulong lane)
{
accn += lane * k_Prime64v2;
return Bits.RotateLeft(accn, 31) * k_Prime64v1;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void mergeAccumulator64(ref ulong acc, ulong accn)
{
acc ^= round64(0, accn);
acc *= k_Prime64v1;
acc += k_Prime64v4;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe uint processStripe32(
ref byte* pInput,
ref uint acc1,
ref uint acc2,
ref uint acc3,
ref uint acc4)
{
processLane32(ref pInput, ref acc1);
processLane32(ref pInput, ref acc2);
processLane32(ref pInput, ref acc3);
processLane32(ref pInput, ref acc4);
return Bits.RotateLeft(acc1, 1)
+ Bits.RotateLeft(acc2, 7)
+ Bits.RotateLeft(acc3, 12)
+ Bits.RotateLeft(acc4, 18);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void processLane32(ref byte* pInput, ref uint accn)
{
uint lane = *(uint*)pInput;
accn = round32(accn, lane);
pInput += 4;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe uint processRemaining32(
byte* pInput,
uint acc,
int remainingLen)
{
for (uint lane; remainingLen >= 4; remainingLen -= 4, pInput += 4)
{
lane = *(uint*)pInput;
acc += lane * k_Prime32v3;
acc = Bits.RotateLeft(acc, 17) * k_Prime32v4;
}
for (byte lane; remainingLen >= 1; remainingLen--, pInput++)
{
lane = *pInput;
acc += lane * k_Prime32v5;
acc = Bits.RotateLeft(acc, 11) * k_Prime32v1;
}
return acc;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint round32(uint accn, uint lane)
{
accn += lane * k_Prime32v2;
accn = Bits.RotateLeft(accn, 13);
accn *= k_Prime32v1;
return accn;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint avalanche32(uint acc)
{
acc ^= acc >> 15;
acc *= k_Prime32v2;
acc ^= acc >> 13;
acc *= k_Prime32v3;
acc ^= acc >> 16;
return acc;
}
///
/// Bit operations.
///
private static class Bits
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static ulong RotateLeft(ulong value, int bits)
{
return (value << bits) | (value >> (64 - bits));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static uint RotateLeft(uint value, int bits)
{
return (value << bits) | (value >> (32 - bits));
}
}
}
}