Change project structure
This commit is contained in:
parent
7f7fb2cca7
commit
759f74f6a4
@ -7,7 +7,7 @@
|
|||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
BenchmarkRunner.Run<xxHashBenchmark>();
|
BenchmarkRunner.Run<xxHashBenchmark>();
|
||||||
BenchmarkRunner.Run<UnsafeBufferBenchmark>();
|
BenchmarkRunner.Run<UtilsBenchmark>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6,7 +6,7 @@
|
|||||||
[RPlotExporter, RankColumn]
|
[RPlotExporter, RankColumn]
|
||||||
[MinColumn, MaxColumn]
|
[MinColumn, MaxColumn]
|
||||||
[MemoryDiagnoser]
|
[MemoryDiagnoser]
|
||||||
public class UnsafeBufferBenchmark
|
public class UtilsBenchmark
|
||||||
{
|
{
|
||||||
private byte[] src;
|
private byte[] src;
|
||||||
private byte[] des;
|
private byte[] des;
|
||||||
@ -33,7 +33,7 @@
|
|||||||
[Benchmark]
|
[Benchmark]
|
||||||
public void UnsafeBufferCopy()
|
public void UnsafeBufferCopy()
|
||||||
{
|
{
|
||||||
UnsafeBuffer.BlockCopy(src, 0, des, 0, 32);
|
Utils.BlockCopy(src, 0, des, 0, 32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3,7 +3,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
public class UnsafeBufferTest
|
public class UtilsTest
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Copy_different_blocks()
|
public void Copy_different_blocks()
|
||||||
@ -27,7 +27,7 @@
|
|||||||
// Act, Assert
|
// Act, Assert
|
||||||
foreach (int count in counts)
|
foreach (int count in counts)
|
||||||
{
|
{
|
||||||
UnsafeBuffer.BlockCopy(src, 0, dst, 0, count);
|
Utils.BlockCopy(src, 0, dst, 0, count);
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
@ -1,4 +0,0 @@
|
|||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
[assembly: InternalsVisibleTo("Standart.Hash.xxHash.Perf")]
|
|
||||||
[assembly: InternalsVisibleTo("Standart.Hash.xxHash.Test")]
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Standart.Hash.xxHash
|
|
||||||
{
|
|
||||||
internal static class BitUtils
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static uint RotateLeft(uint value, int offset)
|
|
||||||
{
|
|
||||||
#if FCL_BITOPS
|
|
||||||
return System.Numerics.BitOperations.RotateLeft(value, offset);
|
|
||||||
#else
|
|
||||||
return (value << offset) | (value >> (32 - offset));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static ulong RotateLeft(ulong value, int offset) // Taken help from: https://stackoverflow.com/a/48580489/5592276
|
|
||||||
{
|
|
||||||
#if FCL_BITOPS
|
|
||||||
return System.Numerics.BitOperations.RotateLeft(value, offset);
|
|
||||||
#else
|
|
||||||
return (value << offset) | (value >> (64 - offset));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -6,5 +6,10 @@
|
|||||||
<TargetFrameworks>net6.0;</TargetFrameworks>
|
<TargetFrameworks>net6.0;</TargetFrameworks>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<InternalsVisibleTo Include="$(AssemblyName).Test" />
|
||||||
|
<InternalsVisibleTo Include="$(AssemblyName).Perf" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
@ -1,235 +0,0 @@
|
|||||||
namespace Standart.Hash.xxHash
|
|
||||||
{
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
internal static class UnsafeBuffer
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static unsafe void BlockCopy(byte[] src, int srcOffset, byte[] dst, int dstOffset, int count)
|
|
||||||
{
|
|
||||||
Debug.Assert(src != null);
|
|
||||||
Debug.Assert(dst != null);
|
|
||||||
Debug.Assert(srcOffset >= 0 && srcOffset < src.Length);
|
|
||||||
Debug.Assert(dstOffset >= 0 && dstOffset < dst.Length);
|
|
||||||
Debug.Assert(count >= 0);
|
|
||||||
Debug.Assert(count + srcOffset <= src.Length);
|
|
||||||
Debug.Assert(count + dstOffset <= dst.Length);
|
|
||||||
|
|
||||||
fixed (byte* pSrc = &src[srcOffset])
|
|
||||||
fixed (byte* pDst = &dst[dstOffset])
|
|
||||||
{
|
|
||||||
byte* ptrSrc = pSrc;
|
|
||||||
byte* ptrDst = pDst;
|
|
||||||
|
|
||||||
SMALLTABLE:
|
|
||||||
switch (count)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
return;
|
|
||||||
case 1:
|
|
||||||
*ptrDst = *ptrSrc;
|
|
||||||
return;
|
|
||||||
case 2:
|
|
||||||
*(short*)ptrDst = *(short*)ptrSrc;
|
|
||||||
return;
|
|
||||||
case 3:
|
|
||||||
*(short*)(ptrDst + 0) = *(short*)(ptrSrc + 0);
|
|
||||||
*(ptrDst + 2) = *(ptrSrc + 2);
|
|
||||||
return;
|
|
||||||
case 4:
|
|
||||||
*(int*)ptrDst = *(int*)ptrSrc;
|
|
||||||
return;
|
|
||||||
case 5:
|
|
||||||
*(int*)(ptrDst + 0) = *(int*)(ptrSrc + 0);
|
|
||||||
*(ptrDst + 4) = *(ptrSrc + 4);
|
|
||||||
return;
|
|
||||||
case 6:
|
|
||||||
*(int*)(ptrDst + 0) = *(int*)(ptrSrc + 0);
|
|
||||||
*(short*)(ptrDst + 4) = *(short*)(ptrSrc + 4);
|
|
||||||
return;
|
|
||||||
case 7:
|
|
||||||
*(int*)(ptrDst + 0) = *(int*)(ptrSrc + 0);
|
|
||||||
*(short*)(ptrDst + 4) = *(short*)(ptrSrc + 4);
|
|
||||||
*(ptrDst + 6) = *(ptrSrc + 6);
|
|
||||||
return;
|
|
||||||
case 8:
|
|
||||||
*(long*)ptrDst = *(long*)ptrSrc;
|
|
||||||
return;
|
|
||||||
case 9:
|
|
||||||
*(long*)(ptrDst + 0) = *(long*)(ptrSrc + 0);
|
|
||||||
*(ptrDst + 8) = *(ptrSrc + 8);
|
|
||||||
return;
|
|
||||||
case 10:
|
|
||||||
*(long*)(ptrDst + 0) = *(long*)(ptrSrc + 0);
|
|
||||||
*(short*)(ptrDst + 8) = *(short*)(ptrSrc + 8);
|
|
||||||
return;
|
|
||||||
case 11:
|
|
||||||
*(long*)(ptrDst + 0) = *(long*)(ptrSrc + 0);
|
|
||||||
*(short*)(ptrDst + 8) = *(short*)(ptrSrc + 8);
|
|
||||||
*(ptrDst + 10) = *(ptrSrc + 10);
|
|
||||||
return;
|
|
||||||
case 12:
|
|
||||||
*(long*)ptrDst = *(long*)ptrSrc;
|
|
||||||
*(int*)(ptrDst + 8) = *(int*)(ptrSrc + 8);
|
|
||||||
return;
|
|
||||||
case 13:
|
|
||||||
*(long*)(ptrDst + 0) = *(long*)(ptrSrc + 0);
|
|
||||||
*(int*)(ptrDst + 8) = *(int*)(ptrSrc + 8);
|
|
||||||
*(ptrDst + 12) = *(ptrSrc + 12);
|
|
||||||
return;
|
|
||||||
case 14:
|
|
||||||
*(long*)(ptrDst + 0) = *(long*)(ptrSrc + 0);
|
|
||||||
*(int*)(ptrDst + 8) = *(int*)(ptrSrc + 8);
|
|
||||||
*(short*)(ptrDst + 12) = *(short*)(ptrSrc + 12);
|
|
||||||
return;
|
|
||||||
case 15:
|
|
||||||
*(long*)(ptrDst + 0) = *(long*)(ptrSrc + 0);
|
|
||||||
*(int*)(ptrDst + 8) = *(int*)(ptrSrc + 8);
|
|
||||||
*(short*)(ptrDst + 12) = *(short*)(ptrSrc + 12);
|
|
||||||
*(ptrDst + 14) = *(ptrSrc + 14);
|
|
||||||
return;
|
|
||||||
case 16:
|
|
||||||
*(long*)ptrDst = *(long*)ptrSrc;
|
|
||||||
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
|
||||||
return;
|
|
||||||
case 17:
|
|
||||||
*(long*)ptrDst = *(long*)ptrSrc;
|
|
||||||
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
|
||||||
*(ptrDst + 16) = *(ptrSrc + 16);
|
|
||||||
return;
|
|
||||||
case 18:
|
|
||||||
*(long*)ptrDst = *(long*)ptrSrc;
|
|
||||||
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
|
||||||
*(short*)(ptrDst + 16) = *(short*)(ptrSrc + 16);
|
|
||||||
return;
|
|
||||||
case 19:
|
|
||||||
*(long*)ptrDst = *(long*)ptrSrc;
|
|
||||||
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
|
||||||
*(short*)(ptrDst + 16) = *(short*)(ptrSrc + 16);
|
|
||||||
*(ptrDst + 18) = *(ptrSrc + 18);
|
|
||||||
return;
|
|
||||||
case 20:
|
|
||||||
*(long*)ptrDst = *(long*)ptrSrc;
|
|
||||||
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
|
||||||
*(int*)(ptrDst + 16) = *(int*)(ptrSrc + 16);
|
|
||||||
return;
|
|
||||||
|
|
||||||
case 21:
|
|
||||||
*(long*)ptrDst = *(long*)ptrSrc;
|
|
||||||
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
|
||||||
*(int*)(ptrDst + 16) = *(int*)(ptrSrc + 16);
|
|
||||||
*(ptrDst + 20) = *(ptrSrc + 20);
|
|
||||||
return;
|
|
||||||
case 22:
|
|
||||||
*(long*)ptrDst = *(long*)ptrSrc;
|
|
||||||
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
|
||||||
*(int*)(ptrDst + 16) = *(int*)(ptrSrc + 16);
|
|
||||||
*(short*)(ptrDst + 20) = *(short*)(ptrSrc + 20);
|
|
||||||
return;
|
|
||||||
case 23:
|
|
||||||
*(long*)ptrDst = *(long*)ptrSrc;
|
|
||||||
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
|
||||||
*(int*)(ptrDst + 16) = *(int*)(ptrSrc + 16);
|
|
||||||
*(short*)(ptrDst + 20) = *(short*)(ptrSrc + 20);
|
|
||||||
*(ptrDst + 22) = *(ptrSrc + 22);
|
|
||||||
return;
|
|
||||||
case 24:
|
|
||||||
*(long*)ptrDst = *(long*)ptrSrc;
|
|
||||||
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
|
||||||
*(long*)(ptrDst + 16) = *(long*)(ptrSrc + 16);
|
|
||||||
return;
|
|
||||||
case 25:
|
|
||||||
*(long*)ptrDst = *(long*)ptrSrc;
|
|
||||||
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
|
||||||
*(long*)(ptrDst + 16) = *(long*)(ptrSrc + 16);
|
|
||||||
*(ptrDst + 24) = *(ptrSrc + 24);
|
|
||||||
return;
|
|
||||||
case 26:
|
|
||||||
*(long*)ptrDst = *(long*)ptrSrc;
|
|
||||||
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
|
||||||
*(long*)(ptrDst + 16) = *(long*)(ptrSrc + 16);
|
|
||||||
*(short*)(ptrDst + 24) = *(short*)(ptrSrc + 24);
|
|
||||||
return;
|
|
||||||
case 27:
|
|
||||||
*(long*)ptrDst = *(long*)ptrSrc;
|
|
||||||
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
|
||||||
*(long*)(ptrDst + 16) = *(long*)(ptrSrc + 16);
|
|
||||||
*(short*)(ptrDst + 24) = *(short*)(ptrSrc + 24);
|
|
||||||
*(ptrDst + 26) = *(ptrSrc + 26);
|
|
||||||
return;
|
|
||||||
case 28:
|
|
||||||
*(long*)ptrDst = *(long*)ptrSrc;
|
|
||||||
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
|
||||||
*(long*)(ptrDst + 16) = *(long*)(ptrSrc + 16);
|
|
||||||
*(int*)(ptrDst + 24) = *(int*)(ptrSrc + 24);
|
|
||||||
return;
|
|
||||||
case 29:
|
|
||||||
*(long*)ptrDst = *(long*)ptrSrc;
|
|
||||||
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
|
||||||
*(long*)(ptrDst + 16) = *(long*)(ptrSrc + 16);
|
|
||||||
*(int*)(ptrDst + 24) = *(int*)(ptrSrc + 24);
|
|
||||||
*(ptrDst + 28) = *(ptrSrc + 28);
|
|
||||||
return;
|
|
||||||
case 30:
|
|
||||||
*(long*)ptrDst = *(long*)ptrSrc;
|
|
||||||
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
|
||||||
*(long*)(ptrDst + 16) = *(long*)(ptrSrc + 16);
|
|
||||||
*(int*)(ptrDst + 24) = *(int*)(ptrSrc + 24);
|
|
||||||
*(short*)(ptrDst + 28) = *(short*)(ptrSrc + 28);
|
|
||||||
return;
|
|
||||||
case 31:
|
|
||||||
*(long*)ptrDst = *(long*)ptrSrc;
|
|
||||||
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
|
||||||
*(long*)(ptrDst + 16) = *(long*)(ptrSrc + 16);
|
|
||||||
*(int*)(ptrDst + 24) = *(int*)(ptrSrc + 24);
|
|
||||||
*(short*)(ptrDst + 28) = *(short*)(ptrSrc + 28);
|
|
||||||
*(ptrDst + 30) = *(ptrSrc + 30);
|
|
||||||
return;
|
|
||||||
case 32:
|
|
||||||
*(long*)ptrDst = *(long*)ptrSrc;
|
|
||||||
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
|
||||||
*(long*)(ptrDst + 16) = *(long*)(ptrSrc + 16);
|
|
||||||
*(long*)(ptrDst + 24) = *(long*)(ptrSrc + 24);
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
long* lpSrc = (long*)ptrSrc;
|
|
||||||
long* ldSrc = (long*)ptrDst;
|
|
||||||
while (count >= 64)
|
|
||||||
{
|
|
||||||
*(ldSrc + 0) = *(lpSrc + 0);
|
|
||||||
*(ldSrc + 1) = *(lpSrc + 1);
|
|
||||||
*(ldSrc + 2) = *(lpSrc + 2);
|
|
||||||
*(ldSrc + 3) = *(lpSrc + 3);
|
|
||||||
*(ldSrc + 4) = *(lpSrc + 4);
|
|
||||||
*(ldSrc + 5) = *(lpSrc + 5);
|
|
||||||
*(ldSrc + 6) = *(lpSrc + 6);
|
|
||||||
*(ldSrc + 7) = *(lpSrc + 7);
|
|
||||||
if (count == 64)
|
|
||||||
return;
|
|
||||||
count -= 64;
|
|
||||||
lpSrc += 8;
|
|
||||||
ldSrc += 8;
|
|
||||||
}
|
|
||||||
if (count > 32)
|
|
||||||
{
|
|
||||||
*(ldSrc + 0) = *(lpSrc + 0);
|
|
||||||
*(ldSrc + 1) = *(lpSrc + 1);
|
|
||||||
*(ldSrc + 2) = *(lpSrc + 2);
|
|
||||||
*(ldSrc + 3) = *(lpSrc + 3);
|
|
||||||
count -= 32;
|
|
||||||
lpSrc += 4;
|
|
||||||
ldSrc += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
ptrSrc = (byte*)lpSrc;
|
|
||||||
ptrDst = (byte*)ldSrc;
|
|
||||||
goto SMALLTABLE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Standart.Hash.xxHash
|
namespace Standart.Hash.xxHash
|
||||||
@ -19,5 +20,231 @@ namespace Standart.Hash.xxHash
|
|||||||
Unsafe.As<byte, ulong>(ref bytes[8]) = value.low64;
|
Unsafe.As<byte, ulong>(ref bytes[8]) = value.low64;
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
internal static unsafe void BlockCopy(byte[] src, int srcOffset, byte[] dst, int dstOffset, int count)
|
||||||
|
{
|
||||||
|
Debug.Assert(src != null);
|
||||||
|
Debug.Assert(dst != null);
|
||||||
|
Debug.Assert(srcOffset >= 0 && srcOffset < src.Length);
|
||||||
|
Debug.Assert(dstOffset >= 0 && dstOffset < dst.Length);
|
||||||
|
Debug.Assert(count >= 0);
|
||||||
|
Debug.Assert(count + srcOffset <= src.Length);
|
||||||
|
Debug.Assert(count + dstOffset <= dst.Length);
|
||||||
|
|
||||||
|
fixed (byte* pSrc = &src[srcOffset])
|
||||||
|
fixed (byte* pDst = &dst[dstOffset])
|
||||||
|
{
|
||||||
|
byte* ptrSrc = pSrc;
|
||||||
|
byte* ptrDst = pDst;
|
||||||
|
|
||||||
|
SMALLTABLE:
|
||||||
|
switch (count)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return;
|
||||||
|
case 1:
|
||||||
|
*ptrDst = *ptrSrc;
|
||||||
|
return;
|
||||||
|
case 2:
|
||||||
|
*(short*)ptrDst = *(short*)ptrSrc;
|
||||||
|
return;
|
||||||
|
case 3:
|
||||||
|
*(short*)(ptrDst + 0) = *(short*)(ptrSrc + 0);
|
||||||
|
*(ptrDst + 2) = *(ptrSrc + 2);
|
||||||
|
return;
|
||||||
|
case 4:
|
||||||
|
*(int*)ptrDst = *(int*)ptrSrc;
|
||||||
|
return;
|
||||||
|
case 5:
|
||||||
|
*(int*)(ptrDst + 0) = *(int*)(ptrSrc + 0);
|
||||||
|
*(ptrDst + 4) = *(ptrSrc + 4);
|
||||||
|
return;
|
||||||
|
case 6:
|
||||||
|
*(int*)(ptrDst + 0) = *(int*)(ptrSrc + 0);
|
||||||
|
*(short*)(ptrDst + 4) = *(short*)(ptrSrc + 4);
|
||||||
|
return;
|
||||||
|
case 7:
|
||||||
|
*(int*)(ptrDst + 0) = *(int*)(ptrSrc + 0);
|
||||||
|
*(short*)(ptrDst + 4) = *(short*)(ptrSrc + 4);
|
||||||
|
*(ptrDst + 6) = *(ptrSrc + 6);
|
||||||
|
return;
|
||||||
|
case 8:
|
||||||
|
*(long*)ptrDst = *(long*)ptrSrc;
|
||||||
|
return;
|
||||||
|
case 9:
|
||||||
|
*(long*)(ptrDst + 0) = *(long*)(ptrSrc + 0);
|
||||||
|
*(ptrDst + 8) = *(ptrSrc + 8);
|
||||||
|
return;
|
||||||
|
case 10:
|
||||||
|
*(long*)(ptrDst + 0) = *(long*)(ptrSrc + 0);
|
||||||
|
*(short*)(ptrDst + 8) = *(short*)(ptrSrc + 8);
|
||||||
|
return;
|
||||||
|
case 11:
|
||||||
|
*(long*)(ptrDst + 0) = *(long*)(ptrSrc + 0);
|
||||||
|
*(short*)(ptrDst + 8) = *(short*)(ptrSrc + 8);
|
||||||
|
*(ptrDst + 10) = *(ptrSrc + 10);
|
||||||
|
return;
|
||||||
|
case 12:
|
||||||
|
*(long*)ptrDst = *(long*)ptrSrc;
|
||||||
|
*(int*)(ptrDst + 8) = *(int*)(ptrSrc + 8);
|
||||||
|
return;
|
||||||
|
case 13:
|
||||||
|
*(long*)(ptrDst + 0) = *(long*)(ptrSrc + 0);
|
||||||
|
*(int*)(ptrDst + 8) = *(int*)(ptrSrc + 8);
|
||||||
|
*(ptrDst + 12) = *(ptrSrc + 12);
|
||||||
|
return;
|
||||||
|
case 14:
|
||||||
|
*(long*)(ptrDst + 0) = *(long*)(ptrSrc + 0);
|
||||||
|
*(int*)(ptrDst + 8) = *(int*)(ptrSrc + 8);
|
||||||
|
*(short*)(ptrDst + 12) = *(short*)(ptrSrc + 12);
|
||||||
|
return;
|
||||||
|
case 15:
|
||||||
|
*(long*)(ptrDst + 0) = *(long*)(ptrSrc + 0);
|
||||||
|
*(int*)(ptrDst + 8) = *(int*)(ptrSrc + 8);
|
||||||
|
*(short*)(ptrDst + 12) = *(short*)(ptrSrc + 12);
|
||||||
|
*(ptrDst + 14) = *(ptrSrc + 14);
|
||||||
|
return;
|
||||||
|
case 16:
|
||||||
|
*(long*)ptrDst = *(long*)ptrSrc;
|
||||||
|
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
||||||
|
return;
|
||||||
|
case 17:
|
||||||
|
*(long*)ptrDst = *(long*)ptrSrc;
|
||||||
|
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
||||||
|
*(ptrDst + 16) = *(ptrSrc + 16);
|
||||||
|
return;
|
||||||
|
case 18:
|
||||||
|
*(long*)ptrDst = *(long*)ptrSrc;
|
||||||
|
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
||||||
|
*(short*)(ptrDst + 16) = *(short*)(ptrSrc + 16);
|
||||||
|
return;
|
||||||
|
case 19:
|
||||||
|
*(long*)ptrDst = *(long*)ptrSrc;
|
||||||
|
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
||||||
|
*(short*)(ptrDst + 16) = *(short*)(ptrSrc + 16);
|
||||||
|
*(ptrDst + 18) = *(ptrSrc + 18);
|
||||||
|
return;
|
||||||
|
case 20:
|
||||||
|
*(long*)ptrDst = *(long*)ptrSrc;
|
||||||
|
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
||||||
|
*(int*)(ptrDst + 16) = *(int*)(ptrSrc + 16);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case 21:
|
||||||
|
*(long*)ptrDst = *(long*)ptrSrc;
|
||||||
|
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
||||||
|
*(int*)(ptrDst + 16) = *(int*)(ptrSrc + 16);
|
||||||
|
*(ptrDst + 20) = *(ptrSrc + 20);
|
||||||
|
return;
|
||||||
|
case 22:
|
||||||
|
*(long*)ptrDst = *(long*)ptrSrc;
|
||||||
|
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
||||||
|
*(int*)(ptrDst + 16) = *(int*)(ptrSrc + 16);
|
||||||
|
*(short*)(ptrDst + 20) = *(short*)(ptrSrc + 20);
|
||||||
|
return;
|
||||||
|
case 23:
|
||||||
|
*(long*)ptrDst = *(long*)ptrSrc;
|
||||||
|
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
||||||
|
*(int*)(ptrDst + 16) = *(int*)(ptrSrc + 16);
|
||||||
|
*(short*)(ptrDst + 20) = *(short*)(ptrSrc + 20);
|
||||||
|
*(ptrDst + 22) = *(ptrSrc + 22);
|
||||||
|
return;
|
||||||
|
case 24:
|
||||||
|
*(long*)ptrDst = *(long*)ptrSrc;
|
||||||
|
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
||||||
|
*(long*)(ptrDst + 16) = *(long*)(ptrSrc + 16);
|
||||||
|
return;
|
||||||
|
case 25:
|
||||||
|
*(long*)ptrDst = *(long*)ptrSrc;
|
||||||
|
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
||||||
|
*(long*)(ptrDst + 16) = *(long*)(ptrSrc + 16);
|
||||||
|
*(ptrDst + 24) = *(ptrSrc + 24);
|
||||||
|
return;
|
||||||
|
case 26:
|
||||||
|
*(long*)ptrDst = *(long*)ptrSrc;
|
||||||
|
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
||||||
|
*(long*)(ptrDst + 16) = *(long*)(ptrSrc + 16);
|
||||||
|
*(short*)(ptrDst + 24) = *(short*)(ptrSrc + 24);
|
||||||
|
return;
|
||||||
|
case 27:
|
||||||
|
*(long*)ptrDst = *(long*)ptrSrc;
|
||||||
|
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
||||||
|
*(long*)(ptrDst + 16) = *(long*)(ptrSrc + 16);
|
||||||
|
*(short*)(ptrDst + 24) = *(short*)(ptrSrc + 24);
|
||||||
|
*(ptrDst + 26) = *(ptrSrc + 26);
|
||||||
|
return;
|
||||||
|
case 28:
|
||||||
|
*(long*)ptrDst = *(long*)ptrSrc;
|
||||||
|
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
||||||
|
*(long*)(ptrDst + 16) = *(long*)(ptrSrc + 16);
|
||||||
|
*(int*)(ptrDst + 24) = *(int*)(ptrSrc + 24);
|
||||||
|
return;
|
||||||
|
case 29:
|
||||||
|
*(long*)ptrDst = *(long*)ptrSrc;
|
||||||
|
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
||||||
|
*(long*)(ptrDst + 16) = *(long*)(ptrSrc + 16);
|
||||||
|
*(int*)(ptrDst + 24) = *(int*)(ptrSrc + 24);
|
||||||
|
*(ptrDst + 28) = *(ptrSrc + 28);
|
||||||
|
return;
|
||||||
|
case 30:
|
||||||
|
*(long*)ptrDst = *(long*)ptrSrc;
|
||||||
|
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
||||||
|
*(long*)(ptrDst + 16) = *(long*)(ptrSrc + 16);
|
||||||
|
*(int*)(ptrDst + 24) = *(int*)(ptrSrc + 24);
|
||||||
|
*(short*)(ptrDst + 28) = *(short*)(ptrSrc + 28);
|
||||||
|
return;
|
||||||
|
case 31:
|
||||||
|
*(long*)ptrDst = *(long*)ptrSrc;
|
||||||
|
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
||||||
|
*(long*)(ptrDst + 16) = *(long*)(ptrSrc + 16);
|
||||||
|
*(int*)(ptrDst + 24) = *(int*)(ptrSrc + 24);
|
||||||
|
*(short*)(ptrDst + 28) = *(short*)(ptrSrc + 28);
|
||||||
|
*(ptrDst + 30) = *(ptrSrc + 30);
|
||||||
|
return;
|
||||||
|
case 32:
|
||||||
|
*(long*)ptrDst = *(long*)ptrSrc;
|
||||||
|
*(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
|
||||||
|
*(long*)(ptrDst + 16) = *(long*)(ptrSrc + 16);
|
||||||
|
*(long*)(ptrDst + 24) = *(long*)(ptrSrc + 24);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
long* lpSrc = (long*)ptrSrc;
|
||||||
|
long* ldSrc = (long*)ptrDst;
|
||||||
|
while (count >= 64)
|
||||||
|
{
|
||||||
|
*(ldSrc + 0) = *(lpSrc + 0);
|
||||||
|
*(ldSrc + 1) = *(lpSrc + 1);
|
||||||
|
*(ldSrc + 2) = *(lpSrc + 2);
|
||||||
|
*(ldSrc + 3) = *(lpSrc + 3);
|
||||||
|
*(ldSrc + 4) = *(lpSrc + 4);
|
||||||
|
*(ldSrc + 5) = *(lpSrc + 5);
|
||||||
|
*(ldSrc + 6) = *(lpSrc + 6);
|
||||||
|
*(ldSrc + 7) = *(lpSrc + 7);
|
||||||
|
if (count == 64)
|
||||||
|
return;
|
||||||
|
count -= 64;
|
||||||
|
lpSrc += 8;
|
||||||
|
ldSrc += 8;
|
||||||
|
}
|
||||||
|
if (count > 32)
|
||||||
|
{
|
||||||
|
*(ldSrc + 0) = *(lpSrc + 0);
|
||||||
|
*(ldSrc + 1) = *(lpSrc + 1);
|
||||||
|
*(ldSrc + 2) = *(lpSrc + 2);
|
||||||
|
*(ldSrc + 3) = *(lpSrc + 3);
|
||||||
|
count -= 32;
|
||||||
|
lpSrc += 4;
|
||||||
|
ldSrc += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptrSrc = (byte*)lpSrc;
|
||||||
|
ptrDst = (byte*)ldSrc;
|
||||||
|
goto SMALLTABLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,60 +0,0 @@
|
|||||||
namespace Standart.Hash.xxHash
|
|
||||||
{
|
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
public static partial class xxHash32
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Compute xxHash for the data byte array
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">The source of data</param>
|
|
||||||
/// <param name="length">The length of the data for hashing</param>
|
|
||||||
/// <param name="seed">The seed number</param>
|
|
||||||
/// <returns>hash</returns>
|
|
||||||
public static unsafe uint ComputeHash(byte[] data, int length, uint seed = 0)
|
|
||||||
{
|
|
||||||
Debug.Assert(data != null);
|
|
||||||
Debug.Assert(length >= 0);
|
|
||||||
Debug.Assert(length <= data.Length);
|
|
||||||
|
|
||||||
fixed (byte* pData = &data[0])
|
|
||||||
{
|
|
||||||
return UnsafeComputeHash(pData, length, seed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Compute xxHash for the data byte array
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">The source of data</param>
|
|
||||||
/// <param name="offset">The offset of the data for hashing</param>
|
|
||||||
/// <param name="length">The length of the data for hashing</param>
|
|
||||||
/// <param name="seed">The seed number</param>
|
|
||||||
/// <returns>hash</returns>
|
|
||||||
public static unsafe uint ComputeHash(byte[] data, int offset, int length, uint seed = 0)
|
|
||||||
{
|
|
||||||
Debug.Assert(data != null);
|
|
||||||
Debug.Assert(length >= 0);
|
|
||||||
Debug.Assert(offset < data.Length);
|
|
||||||
Debug.Assert(length <= data.Length - offset);
|
|
||||||
|
|
||||||
fixed (byte* pData = &data[0 + offset])
|
|
||||||
{
|
|
||||||
return UnsafeComputeHash(pData, length, seed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Compute xxHash for the data byte array
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">The source of data</param>
|
|
||||||
/// <param name="seed">The seed number</param>
|
|
||||||
/// <returns>hash</returns>
|
|
||||||
public static unsafe ulong ComputeHash(System.ArraySegment<byte> data, uint seed = 0)
|
|
||||||
{
|
|
||||||
Debug.Assert(data != null);
|
|
||||||
|
|
||||||
return ComputeHash(data.Array, data.Offset, data.Count, seed);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,89 +0,0 @@
|
|||||||
namespace Standart.Hash.xxHash
|
|
||||||
{
|
|
||||||
using System.Buffers;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
public static partial class xxHash32
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Compute xxHash for the async stream
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="stream">The stream of data</param>
|
|
||||||
/// <param name="bufferSize">The buffer size</param>
|
|
||||||
/// <param name="seed">The seed number</param>
|
|
||||||
/// <returns>The hash</returns>
|
|
||||||
public static async ValueTask<uint> ComputeHashAsync(Stream stream, int bufferSize = 4096, uint seed = 0)
|
|
||||||
{
|
|
||||||
return await ComputeHashAsync(stream, bufferSize, seed, CancellationToken.None);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Compute xxHash for the async stream
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="stream">The stream of data</param>
|
|
||||||
/// <param name="bufferSize">The buffer size</param>
|
|
||||||
/// <param name="seed">The seed number</param>
|
|
||||||
/// <param name="cancellationToken">The cancellation token</param>
|
|
||||||
/// <returns>The hash</returns>
|
|
||||||
public static async ValueTask<uint> ComputeHashAsync(Stream stream, int bufferSize, uint seed, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
Debug.Assert(stream != null);
|
|
||||||
Debug.Assert(bufferSize > 16);
|
|
||||||
|
|
||||||
// Optimizing memory allocation
|
|
||||||
byte[] buffer = ArrayPool<byte>.Shared.Rent(bufferSize + 16);
|
|
||||||
|
|
||||||
int readBytes;
|
|
||||||
int offset = 0;
|
|
||||||
long length = 0;
|
|
||||||
|
|
||||||
// Prepare the seed vector
|
|
||||||
uint v1 = seed + p1 + p2;
|
|
||||||
uint v2 = seed + p2;
|
|
||||||
uint v3 = seed + 0;
|
|
||||||
uint v4 = seed - p1;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Read flow of bytes
|
|
||||||
while ((readBytes = await stream.ReadAsync(buffer, offset, bufferSize, cancellationToken).ConfigureAwait(false)) > 0)
|
|
||||||
{
|
|
||||||
// Exit if the operation is canceled
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
return await Task.FromCanceled<uint>(cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
length = length + readBytes;
|
|
||||||
offset = offset + readBytes;
|
|
||||||
|
|
||||||
if (offset < 16) continue;
|
|
||||||
|
|
||||||
int r = offset % 16; // remain
|
|
||||||
int l = offset - r; // length
|
|
||||||
|
|
||||||
// Process the next chunk
|
|
||||||
UnsafeAlign(buffer, l, ref v1, ref v2, ref v3, ref v4);
|
|
||||||
|
|
||||||
// Put remaining bytes to buffer
|
|
||||||
UnsafeBuffer.BlockCopy(buffer, l, buffer, 0, r);
|
|
||||||
offset = r;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process the final chunk
|
|
||||||
uint h32 = UnsafeFinal(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed);
|
|
||||||
|
|
||||||
return h32;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
// Free memory
|
|
||||||
ArrayPool<byte>.Shared.Return(buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
namespace Standart.Hash.xxHash
|
|
||||||
{
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
public static partial class xxHash32
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Compute xxHash for the data byte span
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">The source of data</param>
|
|
||||||
/// <param name="length">The length of the data for hashing</param>
|
|
||||||
/// <param name="seed">The seed number</param>
|
|
||||||
/// <returns>hash</returns>
|
|
||||||
public static unsafe uint ComputeHash(Span<byte> data, int length, uint seed = 0)
|
|
||||||
{
|
|
||||||
Debug.Assert(data != null);
|
|
||||||
Debug.Assert(length >= 0);
|
|
||||||
Debug.Assert(length <= data.Length);
|
|
||||||
|
|
||||||
fixed (byte* pData = &MemoryMarshal.GetReference(data))
|
|
||||||
{
|
|
||||||
return UnsafeComputeHash(pData, length, seed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Compute xxHash for the data byte span
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">The source of data</param>
|
|
||||||
/// <param name="length">The length of the data for hashing</param>
|
|
||||||
/// <param name="seed">The seed number</param>
|
|
||||||
/// <returns>hash</returns>
|
|
||||||
public static unsafe uint ComputeHash(ReadOnlySpan<byte> data, int length, uint seed = 0)
|
|
||||||
{
|
|
||||||
Debug.Assert(data != null);
|
|
||||||
Debug.Assert(length >= 0);
|
|
||||||
Debug.Assert(length <= data.Length);
|
|
||||||
|
|
||||||
fixed (byte* pData = &MemoryMarshal.GetReference(data))
|
|
||||||
{
|
|
||||||
return UnsafeComputeHash(pData, length, seed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,67 +0,0 @@
|
|||||||
namespace Standart.Hash.xxHash
|
|
||||||
{
|
|
||||||
using System.Buffers;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
public static partial class xxHash32
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Compute xxHash for the stream
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="stream">The stream of data</param>
|
|
||||||
/// <param name="bufferSize">The buffer size</param>
|
|
||||||
/// <param name="seed">The seed number</param>
|
|
||||||
/// <returns>The hash</returns>
|
|
||||||
public static uint ComputeHash(Stream stream, int bufferSize = 4096, uint seed = 0)
|
|
||||||
{
|
|
||||||
Debug.Assert(stream != null);
|
|
||||||
Debug.Assert(bufferSize > 16);
|
|
||||||
|
|
||||||
// Optimizing memory allocation
|
|
||||||
byte[] buffer = ArrayPool<byte>.Shared.Rent(bufferSize + 16);
|
|
||||||
|
|
||||||
int readBytes;
|
|
||||||
int offset = 0;
|
|
||||||
long length = 0;
|
|
||||||
|
|
||||||
// Prepare the seed vector
|
|
||||||
uint v1 = seed + p1 + p2;
|
|
||||||
uint v2 = seed + p2;
|
|
||||||
uint v3 = seed + 0;
|
|
||||||
uint v4 = seed - p1;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Read flow of bytes
|
|
||||||
while ((readBytes = stream.Read(buffer, offset, bufferSize)) > 0)
|
|
||||||
{
|
|
||||||
length = length + readBytes;
|
|
||||||
offset = offset + readBytes;
|
|
||||||
|
|
||||||
if (offset < 16) continue;
|
|
||||||
|
|
||||||
int r = offset % 16; // remain
|
|
||||||
int l = offset - r; // length
|
|
||||||
|
|
||||||
// Process the next chunk
|
|
||||||
UnsafeAlign(buffer, l, ref v1, ref v2, ref v3, ref v4);
|
|
||||||
|
|
||||||
// Put remaining bytes to buffer
|
|
||||||
UnsafeBuffer.BlockCopy(buffer, l, buffer, 0, r);
|
|
||||||
offset = r;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process the last chunk
|
|
||||||
uint h32 = UnsafeFinal(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed);
|
|
||||||
|
|
||||||
return h32;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
// Free memory
|
|
||||||
ArrayPool<byte>.Shared.Return(buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,200 +0,0 @@
|
|||||||
namespace Standart.Hash.xxHash
|
|
||||||
{
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
public static partial class xxHash32
|
|
||||||
{
|
|
||||||
private const uint p1 = 2654435761U;
|
|
||||||
private const uint p2 = 2246822519U;
|
|
||||||
private const uint p3 = 3266489917U;
|
|
||||||
private const uint p4 = 668265263U;
|
|
||||||
private const uint p5 = 374761393U;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Compute xxhash32 for the unsafe array of memory
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="ptr"></param>
|
|
||||||
/// <param name="length"></param>
|
|
||||||
/// <param name="seed"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private static unsafe uint UnsafeComputeHash(byte* ptr, int length, uint seed)
|
|
||||||
{
|
|
||||||
byte* end = ptr + length;
|
|
||||||
uint h32;
|
|
||||||
|
|
||||||
if (length >= 16)
|
|
||||||
{
|
|
||||||
byte* limit = end - 16;
|
|
||||||
|
|
||||||
uint v1 = seed + p1 + p2;
|
|
||||||
uint v2 = seed + p2;
|
|
||||||
uint v3 = seed + 0;
|
|
||||||
uint v4 = seed - p1;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
v1 += *((uint*)ptr) * p2;
|
|
||||||
v1 = BitUtils.RotateLeft(v1, 13); // rotl 13
|
|
||||||
v1 *= p1;
|
|
||||||
ptr += 4;
|
|
||||||
|
|
||||||
v2 += *((uint*)ptr) * p2;
|
|
||||||
v2 = BitUtils.RotateLeft(v2, 13); // rotl 13
|
|
||||||
v2 *= p1;
|
|
||||||
ptr += 4;
|
|
||||||
|
|
||||||
v3 += *((uint*)ptr) * p2;
|
|
||||||
v3 = BitUtils.RotateLeft(v3, 13); // rotl 13
|
|
||||||
v3 *= p1;
|
|
||||||
ptr += 4;
|
|
||||||
|
|
||||||
v4 += *((uint*)ptr) * p2;
|
|
||||||
v4 = BitUtils.RotateLeft(v4, 13); // rotl 13
|
|
||||||
v4 *= p1;
|
|
||||||
ptr += 4;
|
|
||||||
|
|
||||||
} while (ptr <= limit);
|
|
||||||
|
|
||||||
h32 = BitUtils.RotateLeft(v1, 1) + // rotl 1
|
|
||||||
BitUtils.RotateLeft(v2, 7) + // rotl 7
|
|
||||||
BitUtils.RotateLeft(v3, 12) + // rotl 12
|
|
||||||
BitUtils.RotateLeft(v4, 18); // rotl 18
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
h32 = seed + p5;
|
|
||||||
}
|
|
||||||
|
|
||||||
h32 += (uint)length;
|
|
||||||
|
|
||||||
// finalize
|
|
||||||
while (ptr <= end - 4)
|
|
||||||
{
|
|
||||||
h32 += *((uint*)ptr) * p3;
|
|
||||||
h32 = BitUtils.RotateLeft(h32, 17) * p4; // (rotl 17) * p4
|
|
||||||
ptr += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (ptr < end)
|
|
||||||
{
|
|
||||||
h32 += *((byte*)ptr) * p5;
|
|
||||||
h32 = BitUtils.RotateLeft(h32, 11) * p1; // (rotl 11) * p1
|
|
||||||
ptr += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// avalanche
|
|
||||||
h32 ^= h32 >> 15;
|
|
||||||
h32 *= p2;
|
|
||||||
h32 ^= h32 >> 13;
|
|
||||||
h32 *= p3;
|
|
||||||
h32 ^= h32 >> 16;
|
|
||||||
|
|
||||||
return h32;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Compute the first part of xxhash32 (need for the streaming api)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data"></param>
|
|
||||||
/// <param name="l"></param>
|
|
||||||
/// <param name="v1"></param>
|
|
||||||
/// <param name="v2"></param>
|
|
||||||
/// <param name="v3"></param>
|
|
||||||
/// <param name="v4"></param>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private static unsafe void UnsafeAlign(byte[] data, int l, ref uint v1, ref uint v2, ref uint v3, ref uint v4)
|
|
||||||
{
|
|
||||||
fixed (byte* pData = &data[0])
|
|
||||||
{
|
|
||||||
byte* ptr = pData;
|
|
||||||
byte* limit = ptr + l;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
v1 += *((uint*)ptr) * p2;
|
|
||||||
v1 = BitUtils.RotateLeft(v1, 13); // rotl 13
|
|
||||||
v1 *= p1;
|
|
||||||
ptr += 4;
|
|
||||||
|
|
||||||
v2 += *((uint*)ptr) * p2;
|
|
||||||
v2 = BitUtils.RotateLeft(v2, 13); // rotl 13
|
|
||||||
v2 *= p1;
|
|
||||||
ptr += 4;
|
|
||||||
|
|
||||||
v3 += *((uint*)ptr) * p2;
|
|
||||||
v3 = BitUtils.RotateLeft(v3, 13); // rotl 13
|
|
||||||
v3 *= p1;
|
|
||||||
ptr += 4;
|
|
||||||
|
|
||||||
v4 += *((uint*)ptr) * p2;
|
|
||||||
v4 = BitUtils.RotateLeft(v4, 13); // rotl 13
|
|
||||||
v4 *= p1;
|
|
||||||
ptr += 4;
|
|
||||||
|
|
||||||
} while (ptr < limit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Compute the second part of xxhash32 (need for the streaming api)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data"></param>
|
|
||||||
/// <param name="l"></param>
|
|
||||||
/// <param name="v1"></param>
|
|
||||||
/// <param name="v2"></param>
|
|
||||||
/// <param name="v3"></param>
|
|
||||||
/// <param name="v4"></param>
|
|
||||||
/// <param name="length"></param>
|
|
||||||
/// <param name="seed"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private static unsafe uint UnsafeFinal(byte[] data, int l, ref uint v1, ref uint v2, ref uint v3, ref uint v4, long length, uint seed)
|
|
||||||
{
|
|
||||||
fixed (byte* pData = &data[0])
|
|
||||||
{
|
|
||||||
byte* ptr = pData;
|
|
||||||
byte* end = pData + l;
|
|
||||||
uint h32;
|
|
||||||
|
|
||||||
if (length >= 16)
|
|
||||||
{
|
|
||||||
h32 = BitUtils.RotateLeft(v1, 1) + // rotl 1
|
|
||||||
BitUtils.RotateLeft(v2, 7) + // rotl 7
|
|
||||||
BitUtils.RotateLeft(v3, 12) + // rotl 12
|
|
||||||
BitUtils.RotateLeft(v4, 18); // rotl 18
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
h32 = seed + p5;
|
|
||||||
}
|
|
||||||
|
|
||||||
h32 += (uint)length;
|
|
||||||
|
|
||||||
// finalize
|
|
||||||
while (ptr <= end - 4)
|
|
||||||
{
|
|
||||||
h32 += *((uint*)ptr) * p3;
|
|
||||||
h32 = BitUtils.RotateLeft(h32, 17) * p4; // (rotl 17) * p4
|
|
||||||
ptr += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (ptr < end)
|
|
||||||
{
|
|
||||||
h32 += *((byte*)ptr) * p5;
|
|
||||||
h32 = BitUtils.RotateLeft(h32, 11) * p1; // (rotl 11) * p1
|
|
||||||
ptr += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// avalanche
|
|
||||||
h32 ^= h32 >> 15;
|
|
||||||
h32 *= p2;
|
|
||||||
h32 ^= h32 >> 13;
|
|
||||||
h32 *= p3;
|
|
||||||
h32 ^= h32 >> 16;
|
|
||||||
|
|
||||||
return h32;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
20
src/Standart.Hash.xxHash/xxHash32.XXH.cs
Normal file
20
src/Standart.Hash.xxHash/xxHash32.XXH.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// ReSharper disable InconsistentNaming
|
||||||
|
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace Standart.Hash.xxHash;
|
||||||
|
|
||||||
|
public static partial class xxHash32
|
||||||
|
{
|
||||||
|
private const uint XXH_PRIME32_1 = 2654435761U;
|
||||||
|
private const uint XXH_PRIME32_2 = 2246822519U;
|
||||||
|
private const uint XXH_PRIME32_3 = 3266489917U;
|
||||||
|
private const uint XXH_PRIME32_4 = 668265263U;
|
||||||
|
private const uint XXH_PRIME32_5 = 374761393U;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static uint XXH_rotl32(uint x, int r)
|
||||||
|
{
|
||||||
|
return (x << r) | (x >> (32 - r));
|
||||||
|
}
|
||||||
|
}
|
||||||
176
src/Standart.Hash.xxHash/xxHash32.XXH32.cs
Normal file
176
src/Standart.Hash.xxHash/xxHash32.XXH32.cs
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
// ReSharper disable InconsistentNaming
|
||||||
|
|
||||||
|
namespace Standart.Hash.xxHash
|
||||||
|
{
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
public static partial class xxHash32
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static unsafe uint XXH32_internal(byte* input, int len, uint seed)
|
||||||
|
{
|
||||||
|
byte* end = input + len;
|
||||||
|
uint h32;
|
||||||
|
|
||||||
|
if (len >= 16)
|
||||||
|
{
|
||||||
|
byte* limit = end - 16;
|
||||||
|
|
||||||
|
uint v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2;
|
||||||
|
uint v2 = seed + XXH_PRIME32_2;
|
||||||
|
uint v3 = seed + 0;
|
||||||
|
uint v4 = seed - XXH_PRIME32_1;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// XXH32_round
|
||||||
|
v1 += *((uint*)input) * XXH_PRIME32_2;
|
||||||
|
v1 = XXH_rotl32(v1, 13);
|
||||||
|
v1 *= XXH_PRIME32_1;
|
||||||
|
input += 4;
|
||||||
|
|
||||||
|
// XXH32_round
|
||||||
|
v2 += *((uint*)input) * XXH_PRIME32_2;
|
||||||
|
v2 = XXH_rotl32(v2, 13);
|
||||||
|
v2 *= XXH_PRIME32_1;
|
||||||
|
input += 4;
|
||||||
|
|
||||||
|
// XXH32_round
|
||||||
|
v3 += *((uint*)input) * XXH_PRIME32_2;
|
||||||
|
v3 = XXH_rotl32(v3, 13);
|
||||||
|
v3 *= XXH_PRIME32_1;
|
||||||
|
input += 4;
|
||||||
|
|
||||||
|
// XXH32_round
|
||||||
|
v4 += *((uint*)input) * XXH_PRIME32_2;
|
||||||
|
v4 = XXH_rotl32(v4, 13);
|
||||||
|
v4 *= XXH_PRIME32_1;
|
||||||
|
input += 4;
|
||||||
|
|
||||||
|
} while (input <= limit);
|
||||||
|
|
||||||
|
h32 = XXH_rotl32(v1, 1) +
|
||||||
|
XXH_rotl32(v2, 7) +
|
||||||
|
XXH_rotl32(v3, 12) +
|
||||||
|
XXH_rotl32(v4, 18);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
h32 = seed + XXH_PRIME32_5;
|
||||||
|
}
|
||||||
|
|
||||||
|
h32 += (uint)len;
|
||||||
|
|
||||||
|
// XXH32_finalize
|
||||||
|
while (input <= end - 4)
|
||||||
|
{
|
||||||
|
h32 += *((uint*)input) * XXH_PRIME32_3;
|
||||||
|
h32 = XXH_rotl32(h32, 17) * XXH_PRIME32_4;
|
||||||
|
input += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (input < end)
|
||||||
|
{
|
||||||
|
h32 += *((byte*)input) * XXH_PRIME32_5;
|
||||||
|
h32 = XXH_rotl32(h32, 11) * XXH_PRIME32_1;
|
||||||
|
input += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXH32_avalanche
|
||||||
|
h32 ^= h32 >> 15;
|
||||||
|
h32 *= XXH_PRIME32_2;
|
||||||
|
h32 ^= h32 >> 13;
|
||||||
|
h32 *= XXH_PRIME32_3;
|
||||||
|
h32 ^= h32 >> 16;
|
||||||
|
|
||||||
|
return h32;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static unsafe void __XXH32_stream_align(byte[] input, int len, ref uint v1, ref uint v2, ref uint v3, ref uint v4)
|
||||||
|
{
|
||||||
|
fixed (byte* pData = &input[0])
|
||||||
|
{
|
||||||
|
byte* ptr = pData;
|
||||||
|
byte* limit = ptr + len;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// XXH32_round
|
||||||
|
v1 += *((uint*)ptr) * XXH_PRIME32_2;
|
||||||
|
v1 = XXH_rotl32(v1, 13);
|
||||||
|
v1 *= XXH_PRIME32_1;
|
||||||
|
ptr += 4;
|
||||||
|
|
||||||
|
// XXH32_round
|
||||||
|
v2 += *((uint*)ptr) * XXH_PRIME32_2;
|
||||||
|
v2 = XXH_rotl32(v2, 13);
|
||||||
|
v2 *= XXH_PRIME32_1;
|
||||||
|
ptr += 4;
|
||||||
|
|
||||||
|
// XXH32_round
|
||||||
|
v3 += *((uint*)ptr) * XXH_PRIME32_2;
|
||||||
|
v3 = XXH_rotl32(v3, 13);
|
||||||
|
v3 *= XXH_PRIME32_1;
|
||||||
|
ptr += 4;
|
||||||
|
|
||||||
|
// XXH32_round
|
||||||
|
v4 += *((uint*)ptr) * XXH_PRIME32_2;
|
||||||
|
v4 = XXH_rotl32(v4, 13);
|
||||||
|
v4 *= XXH_PRIME32_1;
|
||||||
|
ptr += 4;
|
||||||
|
|
||||||
|
} while (ptr < limit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static unsafe uint __XXH32_stream_finalize(byte[] input, int len, ref uint v1, ref uint v2, ref uint v3, ref uint v4, long length, uint seed)
|
||||||
|
{
|
||||||
|
fixed (byte* pData = &input[0])
|
||||||
|
{
|
||||||
|
byte* ptr = pData;
|
||||||
|
byte* end = pData + len;
|
||||||
|
uint h32;
|
||||||
|
|
||||||
|
if (length >= 16)
|
||||||
|
{
|
||||||
|
h32 = XXH_rotl32(v1, 1) +
|
||||||
|
XXH_rotl32(v2, 7) +
|
||||||
|
XXH_rotl32(v3, 12) +
|
||||||
|
XXH_rotl32(v4, 18);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
h32 = seed + XXH_PRIME32_5;
|
||||||
|
}
|
||||||
|
|
||||||
|
h32 += (uint)length;
|
||||||
|
|
||||||
|
// XXH32_finalize
|
||||||
|
while (ptr <= end - 4)
|
||||||
|
{
|
||||||
|
h32 += *((uint*)ptr) * XXH_PRIME32_3;
|
||||||
|
h32 = XXH_rotl32(h32, 17) * XXH_PRIME32_4;
|
||||||
|
ptr += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (ptr < end)
|
||||||
|
{
|
||||||
|
h32 += *((byte*)ptr) * XXH_PRIME32_5;
|
||||||
|
h32 = XXH_rotl32(h32, 11) * XXH_PRIME32_1;
|
||||||
|
ptr += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXH32_avalanche
|
||||||
|
h32 ^= h32 >> 15;
|
||||||
|
h32 *= XXH_PRIME32_2;
|
||||||
|
h32 ^= h32 >> 13;
|
||||||
|
h32 *= XXH_PRIME32_3;
|
||||||
|
h32 ^= h32 >> 16;
|
||||||
|
|
||||||
|
return h32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
262
src/Standart.Hash.xxHash/xxHash32.cs
Normal file
262
src/Standart.Hash.xxHash/xxHash32.cs
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
// ReSharper disable InconsistentNaming
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Standart.Hash.xxHash;
|
||||||
|
|
||||||
|
public static partial class xxHash32
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Compute xxHash for the data byte array
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">The source of data</param>
|
||||||
|
/// <param name="length">The length of the data for hashing</param>
|
||||||
|
/// <param name="seed">The seed number</param>
|
||||||
|
/// <returns>hash</returns>
|
||||||
|
public static unsafe uint ComputeHash(byte[] data, int length, uint seed = 0)
|
||||||
|
{
|
||||||
|
Debug.Assert(data != null);
|
||||||
|
Debug.Assert(length >= 0);
|
||||||
|
Debug.Assert(length <= data.Length);
|
||||||
|
|
||||||
|
fixed (byte* pData = &data[0])
|
||||||
|
{
|
||||||
|
return UnsafeComputeHash(pData, length, seed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compute xxHash for the data byte array
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">The source of data</param>
|
||||||
|
/// <param name="offset">The offset of the data for hashing</param>
|
||||||
|
/// <param name="length">The length of the data for hashing</param>
|
||||||
|
/// <param name="seed">The seed number</param>
|
||||||
|
/// <returns>hash</returns>
|
||||||
|
public static unsafe uint ComputeHash(byte[] data, int offset, int length, uint seed = 0)
|
||||||
|
{
|
||||||
|
Debug.Assert(data != null);
|
||||||
|
Debug.Assert(length >= 0);
|
||||||
|
Debug.Assert(offset < data.Length);
|
||||||
|
Debug.Assert(length <= data.Length - offset);
|
||||||
|
|
||||||
|
fixed (byte* pData = &data[0 + offset])
|
||||||
|
{
|
||||||
|
return UnsafeComputeHash(pData, length, seed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compute xxHash for the data byte array
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">The source of data</param>
|
||||||
|
/// <param name="seed">The seed number</param>
|
||||||
|
/// <returns>hash</returns>
|
||||||
|
public static ulong ComputeHash(ArraySegment<byte> data, uint seed = 0)
|
||||||
|
{
|
||||||
|
Debug.Assert(data != null);
|
||||||
|
|
||||||
|
return ComputeHash(data.Array, data.Offset, data.Count, seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compute xxHash for the async stream
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The stream of data</param>
|
||||||
|
/// <param name="bufferSize">The buffer size</param>
|
||||||
|
/// <param name="seed">The seed number</param>
|
||||||
|
/// <returns>The hash</returns>
|
||||||
|
public static async ValueTask<uint> ComputeHashAsync(Stream stream, int bufferSize = 4096, uint seed = 0)
|
||||||
|
{
|
||||||
|
return await ComputeHashAsync(stream, bufferSize, seed, CancellationToken.None);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compute xxHash for the async stream
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The stream of data</param>
|
||||||
|
/// <param name="bufferSize">The buffer size</param>
|
||||||
|
/// <param name="seed">The seed number</param>
|
||||||
|
/// <param name="cancellationToken">The cancellation token</param>
|
||||||
|
/// <returns>The hash</returns>
|
||||||
|
public static async ValueTask<uint> ComputeHashAsync(Stream stream, int bufferSize, uint seed,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
Debug.Assert(stream != null);
|
||||||
|
Debug.Assert(bufferSize > 16);
|
||||||
|
|
||||||
|
// Optimizing memory allocation
|
||||||
|
byte[] buffer = ArrayPool<byte>.Shared.Rent(bufferSize + 16);
|
||||||
|
|
||||||
|
int readBytes;
|
||||||
|
int offset = 0;
|
||||||
|
long length = 0;
|
||||||
|
|
||||||
|
// Prepare the seed vector
|
||||||
|
uint v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2;
|
||||||
|
uint v2 = seed + XXH_PRIME32_2;
|
||||||
|
uint v3 = seed + 0;
|
||||||
|
uint v4 = seed - XXH_PRIME32_1;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Read flow of bytes
|
||||||
|
while ((readBytes =
|
||||||
|
await stream.ReadAsync(buffer, offset, bufferSize, cancellationToken).ConfigureAwait(false)) > 0)
|
||||||
|
{
|
||||||
|
length = length + readBytes;
|
||||||
|
offset = offset + readBytes;
|
||||||
|
|
||||||
|
if (offset < 16) continue;
|
||||||
|
|
||||||
|
int r = offset % 16; // remain
|
||||||
|
int l = offset - r; // length
|
||||||
|
|
||||||
|
// Process the next chunk
|
||||||
|
__XXH32_stream_align(buffer, l, ref v1, ref v2, ref v3, ref v4);
|
||||||
|
|
||||||
|
// Put remaining bytes to buffer
|
||||||
|
Utils.BlockCopy(buffer, l, buffer, 0, r);
|
||||||
|
offset = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the final chunk
|
||||||
|
uint h32 = __XXH32_stream_finalize(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed);
|
||||||
|
|
||||||
|
return h32;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// Free memory
|
||||||
|
ArrayPool<byte>.Shared.Return(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compute xxHash for the data byte span
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">The source of data</param>
|
||||||
|
/// <param name="length">The length of the data for hashing</param>
|
||||||
|
/// <param name="seed">The seed number</param>
|
||||||
|
/// <returns>hash</returns>
|
||||||
|
public static unsafe uint ComputeHash(Span<byte> data, int length, uint seed = 0)
|
||||||
|
{
|
||||||
|
Debug.Assert(data != null);
|
||||||
|
Debug.Assert(length >= 0);
|
||||||
|
Debug.Assert(length <= data.Length);
|
||||||
|
|
||||||
|
fixed (byte* pData = &MemoryMarshal.GetReference(data))
|
||||||
|
{
|
||||||
|
return UnsafeComputeHash(pData, length, seed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compute xxHash for the data byte span
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">The source of data</param>
|
||||||
|
/// <param name="length">The length of the data for hashing</param>
|
||||||
|
/// <param name="seed">The seed number</param>
|
||||||
|
/// <returns>hash</returns>
|
||||||
|
public static unsafe uint ComputeHash(ReadOnlySpan<byte> data, int length, uint seed = 0)
|
||||||
|
{
|
||||||
|
Debug.Assert(data != null);
|
||||||
|
Debug.Assert(length >= 0);
|
||||||
|
Debug.Assert(length <= data.Length);
|
||||||
|
|
||||||
|
fixed (byte* pData = &MemoryMarshal.GetReference(data))
|
||||||
|
{
|
||||||
|
return UnsafeComputeHash(pData, length, seed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compute xxHash for the stream
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The stream of data</param>
|
||||||
|
/// <param name="bufferSize">The buffer size</param>
|
||||||
|
/// <param name="seed">The seed number</param>
|
||||||
|
/// <returns>The hash</returns>
|
||||||
|
public static uint ComputeHash(Stream stream, int bufferSize = 4096, uint seed = 0)
|
||||||
|
{
|
||||||
|
Debug.Assert(stream != null);
|
||||||
|
Debug.Assert(bufferSize > 16);
|
||||||
|
|
||||||
|
// Optimizing memory allocation
|
||||||
|
byte[] buffer = ArrayPool<byte>.Shared.Rent(bufferSize + 16);
|
||||||
|
|
||||||
|
int readBytes;
|
||||||
|
int offset = 0;
|
||||||
|
long length = 0;
|
||||||
|
|
||||||
|
// Prepare the seed vector
|
||||||
|
uint v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2;
|
||||||
|
uint v2 = seed + XXH_PRIME32_2;
|
||||||
|
uint v3 = seed + 0;
|
||||||
|
uint v4 = seed - XXH_PRIME32_1;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Read flow of bytes
|
||||||
|
while ((readBytes = stream.Read(buffer, offset, bufferSize)) > 0)
|
||||||
|
{
|
||||||
|
length = length + readBytes;
|
||||||
|
offset = offset + readBytes;
|
||||||
|
|
||||||
|
if (offset < 16) continue;
|
||||||
|
|
||||||
|
int r = offset % 16; // remain
|
||||||
|
int l = offset - r; // length
|
||||||
|
|
||||||
|
// Process the next chunk
|
||||||
|
__XXH32_stream_align(buffer, l, ref v1, ref v2, ref v3, ref v4);
|
||||||
|
|
||||||
|
// Put remaining bytes to buffer
|
||||||
|
Utils.BlockCopy(buffer, l, buffer, 0, r);
|
||||||
|
offset = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the last chunk
|
||||||
|
uint h32 = __XXH32_stream_finalize(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed);
|
||||||
|
|
||||||
|
return h32;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// Free memory
|
||||||
|
ArrayPool<byte>.Shared.Return(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compute xxHash for the string
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="str">The source of data</param>
|
||||||
|
/// <param name="seed">The seed number</param>
|
||||||
|
/// <returns>hash</returns>
|
||||||
|
public static unsafe uint ComputeHash(string str, uint seed = 0)
|
||||||
|
{
|
||||||
|
Debug.Assert(str != null);
|
||||||
|
|
||||||
|
fixed (char* c = str)
|
||||||
|
{
|
||||||
|
byte* ptr = (byte*) c;
|
||||||
|
int length = str.Length;
|
||||||
|
|
||||||
|
return UnsafeComputeHash(ptr, length, seed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static unsafe uint UnsafeComputeHash(byte* ptr, int length, uint seed)
|
||||||
|
{
|
||||||
|
return XXH32_internal(ptr, length, seed);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,58 +0,0 @@
|
|||||||
namespace Standart.Hash.xxHash
|
|
||||||
{
|
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
public static partial class xxHash64
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Compute xxHash for the data byte array
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">The source of data</param>
|
|
||||||
/// <param name="length">The length of the data for hashing</param>
|
|
||||||
/// <param name="seed">The seed number</param>
|
|
||||||
/// <returns>hash</returns>
|
|
||||||
public static unsafe ulong ComputeHash(byte[] data, int length, ulong seed = 0)
|
|
||||||
{
|
|
||||||
Debug.Assert(data != null);
|
|
||||||
Debug.Assert(length >= 0);
|
|
||||||
Debug.Assert(length <= data.Length);
|
|
||||||
|
|
||||||
fixed (byte* pData = &data[0])
|
|
||||||
{
|
|
||||||
return UnsafeComputeHash(pData, length, seed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Compute xxHash for the data byte array
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">The source of data</param>
|
|
||||||
/// <param name="length">The length of the data for hashing</param>
|
|
||||||
/// <param name="seed">The seed number</param>
|
|
||||||
/// <returns>hash</returns>
|
|
||||||
public static unsafe ulong ComputeHash(byte[] data, int offset, int length, ulong seed = 0)
|
|
||||||
{
|
|
||||||
Debug.Assert(data != null);
|
|
||||||
Debug.Assert(length >= 0);
|
|
||||||
Debug.Assert(offset < data.Length);
|
|
||||||
Debug.Assert(length <= data.Length - offset);
|
|
||||||
|
|
||||||
fixed (byte* pData = &data[0 + offset])
|
|
||||||
{
|
|
||||||
return UnsafeComputeHash(pData, length, seed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Compute xxHash for the data byte array
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">The source of data</param>
|
|
||||||
/// <param name="seed">The seed number</param>
|
|
||||||
/// <returns>hash</returns>
|
|
||||||
public static unsafe ulong ComputeHash(System.ArraySegment<byte> data, ulong seed = 0)
|
|
||||||
{
|
|
||||||
Debug.Assert(data != null);
|
|
||||||
|
|
||||||
return ComputeHash(data.Array, data.Offset, data.Count, seed);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,88 +0,0 @@
|
|||||||
namespace Standart.Hash.xxHash
|
|
||||||
{
|
|
||||||
using System.Buffers;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
public static partial class xxHash64
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Compute xxHash for the async stream
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="stream">The stream of data</param>
|
|
||||||
/// <param name="bufferSize">The buffer size</param>
|
|
||||||
/// <param name="seed">The seed number</param>
|
|
||||||
/// <returns>The hash</returns>
|
|
||||||
public static async ValueTask<ulong> ComputeHashAsync(Stream stream, int bufferSize = 8192, ulong seed = 0)
|
|
||||||
{
|
|
||||||
return await ComputeHashAsync(stream, bufferSize, seed, CancellationToken.None);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Compute xxHash for the async stream
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="stream">The stream of data</param>
|
|
||||||
/// <param name="bufferSize">The buffer size</param>
|
|
||||||
/// <param name="seed">The seed number</param>
|
|
||||||
/// <param name="cancellationToken">The cancelation token</param>
|
|
||||||
/// <returns>The hash</returns>
|
|
||||||
public static async ValueTask<ulong> ComputeHashAsync(Stream stream, int bufferSize, ulong seed, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
Debug.Assert(stream != null);
|
|
||||||
Debug.Assert(bufferSize > 32);
|
|
||||||
|
|
||||||
// Optimizing memory allocation
|
|
||||||
byte[] buffer = ArrayPool<byte>.Shared.Rent(bufferSize + 32);
|
|
||||||
|
|
||||||
int readBytes;
|
|
||||||
int offset = 0;
|
|
||||||
long length = 0;
|
|
||||||
|
|
||||||
// Prepare the seed vector
|
|
||||||
ulong v1 = seed + p1 + p2;
|
|
||||||
ulong v2 = seed + p2;
|
|
||||||
ulong v3 = seed + 0;
|
|
||||||
ulong v4 = seed - p1;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Read flow of bytes
|
|
||||||
while ((readBytes = await stream.ReadAsync(buffer, offset, bufferSize, cancellationToken).ConfigureAwait(false)) > 0)
|
|
||||||
{
|
|
||||||
// Exit if the operation is canceled
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
return await Task.FromCanceled<ulong>(cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
length = length + readBytes;
|
|
||||||
offset = offset + readBytes;
|
|
||||||
|
|
||||||
if (offset < 32) continue;
|
|
||||||
|
|
||||||
int r = offset % 32; // remain
|
|
||||||
int l = offset - r; // length
|
|
||||||
|
|
||||||
// Process the next chunk
|
|
||||||
UnsafeAlign(buffer, l, ref v1, ref v2, ref v3, ref v4);
|
|
||||||
|
|
||||||
// Put remaining bytes to buffer
|
|
||||||
UnsafeBuffer.BlockCopy(buffer, l, buffer, 0, r);
|
|
||||||
offset = r;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process the final chunk
|
|
||||||
ulong h64 = UnsafeFinal(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed);
|
|
||||||
|
|
||||||
return h64;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
// Free memory
|
|
||||||
ArrayPool<byte>.Shared.Return(buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,47 +0,0 @@
|
|||||||
namespace Standart.Hash.xxHash
|
|
||||||
{
|
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
public static partial class xxHash64
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Compute xxHash for the data byte span
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">The source of data</param>
|
|
||||||
/// <param name="length">The length of the data for hashing</param>
|
|
||||||
/// <param name="seed">The seed number</param>
|
|
||||||
/// <returns>hash</returns>
|
|
||||||
public static unsafe ulong ComputeHash(Span<byte> data, int length, ulong seed = 0)
|
|
||||||
{
|
|
||||||
Debug.Assert(data != null);
|
|
||||||
Debug.Assert(length >= 0);
|
|
||||||
Debug.Assert(length <= data.Length);
|
|
||||||
|
|
||||||
fixed (byte* pData = &MemoryMarshal.GetReference(data))
|
|
||||||
{
|
|
||||||
return UnsafeComputeHash(pData, length, seed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Compute xxHash for the data byte span
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">The source of data</param>
|
|
||||||
/// <param name="length">The length of the data for hashing</param>
|
|
||||||
/// <param name="seed">The seed number</param>
|
|
||||||
/// <returns>hash</returns>
|
|
||||||
public static unsafe ulong ComputeHash(ReadOnlySpan<byte> data, int length, ulong seed = 0)
|
|
||||||
{
|
|
||||||
Debug.Assert(data != null);
|
|
||||||
Debug.Assert(length >= 0);
|
|
||||||
Debug.Assert(length <= data.Length);
|
|
||||||
|
|
||||||
fixed (byte* pData = &MemoryMarshal.GetReference(data))
|
|
||||||
{
|
|
||||||
return UnsafeComputeHash(pData, length, seed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,67 +0,0 @@
|
|||||||
namespace Standart.Hash.xxHash
|
|
||||||
{
|
|
||||||
using System.Buffers;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
public static partial class xxHash64
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Compute xxHash for the stream
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="stream">The stream of data</param>
|
|
||||||
/// <param name="bufferSize">The buffer size</param>
|
|
||||||
/// <param name="seed">The seed number</param>
|
|
||||||
/// <returns>The hash</returns>
|
|
||||||
public static ulong ComputeHash(Stream stream, int bufferSize = 8192, ulong seed = 0)
|
|
||||||
{
|
|
||||||
Debug.Assert(stream != null);
|
|
||||||
Debug.Assert(bufferSize > 32);
|
|
||||||
|
|
||||||
// Optimizing memory allocation
|
|
||||||
byte[] buffer = ArrayPool<byte>.Shared.Rent(bufferSize + 32);
|
|
||||||
|
|
||||||
int readBytes;
|
|
||||||
int offset = 0;
|
|
||||||
long length = 0;
|
|
||||||
|
|
||||||
// Prepare the seed vector
|
|
||||||
ulong v1 = seed + p1 + p2;
|
|
||||||
ulong v2 = seed + p2;
|
|
||||||
ulong v3 = seed + 0;
|
|
||||||
ulong v4 = seed - p1;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Read flow of bytes
|
|
||||||
while ((readBytes = stream.Read(buffer, offset, bufferSize)) > 0)
|
|
||||||
{
|
|
||||||
length = length + readBytes;
|
|
||||||
offset = offset + readBytes;
|
|
||||||
|
|
||||||
if (offset < 32) continue;
|
|
||||||
|
|
||||||
int r = offset % 32; // remain
|
|
||||||
int l = offset - r; // length
|
|
||||||
|
|
||||||
// Process the next chunk
|
|
||||||
UnsafeAlign(buffer, l, ref v1, ref v2, ref v3, ref v4);
|
|
||||||
|
|
||||||
// Put remaining bytes to buffer
|
|
||||||
UnsafeBuffer.BlockCopy(buffer, l, buffer, 0, r);
|
|
||||||
offset = r;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process the final chunk
|
|
||||||
ulong h64 = UnsafeFinal(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed);
|
|
||||||
|
|
||||||
return h64;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
// Free memory
|
|
||||||
ArrayPool<byte>.Shared.Return(buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,278 +0,0 @@
|
|||||||
namespace Standart.Hash.xxHash
|
|
||||||
{
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
public static partial class xxHash64
|
|
||||||
{
|
|
||||||
private const ulong p1 = 11400714785074694791UL;
|
|
||||||
private const ulong p2 = 14029467366897019727UL;
|
|
||||||
private const ulong p3 = 1609587929392839161UL;
|
|
||||||
private const ulong p4 = 9650029242287828579UL;
|
|
||||||
private const ulong p5 = 2870177450012600261UL;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Compute xxhash64 for the unsafe array of memory
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="ptr"></param>
|
|
||||||
/// <param name="length"></param>
|
|
||||||
/// <param name="seed"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private static unsafe ulong UnsafeComputeHash(byte* ptr, int length, ulong seed)
|
|
||||||
{
|
|
||||||
byte* end = ptr + length;
|
|
||||||
ulong h64;
|
|
||||||
|
|
||||||
if (length >= 32)
|
|
||||||
|
|
||||||
{
|
|
||||||
byte* limit = end - 32;
|
|
||||||
|
|
||||||
ulong v1 = seed + p1 + p2;
|
|
||||||
ulong v2 = seed + p2;
|
|
||||||
ulong v3 = seed + 0;
|
|
||||||
ulong v4 = seed - p1;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
v1 += *((ulong*)ptr) * p2;
|
|
||||||
v1 = BitUtils.RotateLeft(v1, 31); // rotl 31
|
|
||||||
v1 *= p1;
|
|
||||||
ptr += 8;
|
|
||||||
|
|
||||||
v2 += *((ulong*)ptr) * p2;
|
|
||||||
v2 = BitUtils.RotateLeft(v2, 31); // rotl 31
|
|
||||||
v2 *= p1;
|
|
||||||
ptr += 8;
|
|
||||||
|
|
||||||
v3 += *((ulong*)ptr) * p2;
|
|
||||||
v3 = BitUtils.RotateLeft(v3, 31); // rotl 31
|
|
||||||
v3 *= p1;
|
|
||||||
ptr += 8;
|
|
||||||
|
|
||||||
v4 += *((ulong*)ptr) * p2;
|
|
||||||
v4 = BitUtils.RotateLeft(v4, 31); // rotl 31
|
|
||||||
v4 *= p1;
|
|
||||||
ptr += 8;
|
|
||||||
|
|
||||||
} while (ptr <= limit);
|
|
||||||
|
|
||||||
h64 = BitUtils.RotateLeft(v1, 1) + // rotl 1
|
|
||||||
BitUtils.RotateLeft(v2, 7) + // rotl 7
|
|
||||||
BitUtils.RotateLeft(v3, 12) + // rotl 12
|
|
||||||
BitUtils.RotateLeft(v4, 18); // rotl 18
|
|
||||||
|
|
||||||
// merge round
|
|
||||||
v1 *= p2;
|
|
||||||
v1 = BitUtils.RotateLeft(v1, 31); // rotl 31
|
|
||||||
v1 *= p1;
|
|
||||||
h64 ^= v1;
|
|
||||||
h64 = h64 * p1 + p4;
|
|
||||||
|
|
||||||
// merge round
|
|
||||||
v2 *= p2;
|
|
||||||
v2 = BitUtils.RotateLeft(v2, 31); // rotl 31
|
|
||||||
v2 *= p1;
|
|
||||||
h64 ^= v2;
|
|
||||||
h64 = h64 * p1 + p4;
|
|
||||||
|
|
||||||
// merge round
|
|
||||||
v3 *= p2;
|
|
||||||
v3 = BitUtils.RotateLeft(v3, 31); // rotl 31
|
|
||||||
v3 *= p1;
|
|
||||||
h64 ^= v3;
|
|
||||||
h64 = h64 * p1 + p4;
|
|
||||||
|
|
||||||
// merge round
|
|
||||||
v4 *= p2;
|
|
||||||
v4 = BitUtils.RotateLeft(v4, 31); // rotl 31
|
|
||||||
v4 *= p1;
|
|
||||||
h64 ^= v4;
|
|
||||||
h64 = h64 * p1 + p4;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
h64 = seed + p5;
|
|
||||||
}
|
|
||||||
|
|
||||||
h64 += (ulong)length;
|
|
||||||
|
|
||||||
// finalize
|
|
||||||
while (ptr <= end - 8)
|
|
||||||
{
|
|
||||||
ulong t1 = *((ulong*)ptr) * p2;
|
|
||||||
t1 = BitUtils.RotateLeft(t1, 31); // rotl 31
|
|
||||||
t1 *= p1;
|
|
||||||
h64 ^= t1;
|
|
||||||
h64 = BitUtils.RotateLeft(h64, 27) * p1 + p4; // (rotl 27) * p1 + p4
|
|
||||||
ptr += 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ptr <= end - 4)
|
|
||||||
{
|
|
||||||
h64 ^= *((uint*)ptr) * p1;
|
|
||||||
h64 = BitUtils.RotateLeft(h64, 23) * p2 + p3; // (rotl 23) * p2 + p3
|
|
||||||
ptr += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (ptr < end)
|
|
||||||
{
|
|
||||||
h64 ^= *((byte*)ptr) * p5;
|
|
||||||
h64 = BitUtils.RotateLeft(h64, 11) * p1; // (rotl 11) * p1
|
|
||||||
ptr += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// avalanche
|
|
||||||
h64 ^= h64 >> 33;
|
|
||||||
h64 *= p2;
|
|
||||||
h64 ^= h64 >> 29;
|
|
||||||
h64 *= p3;
|
|
||||||
h64 ^= h64 >> 32;
|
|
||||||
|
|
||||||
return h64;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Compute the first part of xxhash64 (need for the streaming api)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data"></param>
|
|
||||||
/// <param name="l"></param>
|
|
||||||
/// <param name="v1"></param>
|
|
||||||
/// <param name="v2"></param>
|
|
||||||
/// <param name="v3"></param>
|
|
||||||
/// <param name="v4"></param>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private static unsafe void UnsafeAlign(byte[] data, int l, ref ulong v1, ref ulong v2, ref ulong v3, ref ulong v4)
|
|
||||||
{
|
|
||||||
fixed (byte* pData = &data[0])
|
|
||||||
{
|
|
||||||
byte* ptr = pData;
|
|
||||||
byte* limit = ptr + l;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
v1 += *((ulong*)ptr) * p2;
|
|
||||||
v1 = BitUtils.RotateLeft(v1, 31); // rotl 31
|
|
||||||
v1 *= p1;
|
|
||||||
ptr += 8;
|
|
||||||
|
|
||||||
v2 += *((ulong*)ptr) * p2;
|
|
||||||
v2 = BitUtils.RotateLeft(v2, 31); // rotl 31
|
|
||||||
v2 *= p1;
|
|
||||||
ptr += 8;
|
|
||||||
|
|
||||||
v3 += *((ulong*)ptr) * p2;
|
|
||||||
v3 = BitUtils.RotateLeft(v3, 31); // rotl 31
|
|
||||||
v3 *= p1;
|
|
||||||
ptr += 8;
|
|
||||||
|
|
||||||
v4 += *((ulong*)ptr) * p2;
|
|
||||||
v4 = BitUtils.RotateLeft(v4, 31); // rotl 31
|
|
||||||
v4 *= p1;
|
|
||||||
ptr += 8;
|
|
||||||
|
|
||||||
} while (ptr < limit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Compute the second part of xxhash64 (need for the streaming api)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data"></param>
|
|
||||||
/// <param name="l"></param>
|
|
||||||
/// <param name="v1"></param>
|
|
||||||
/// <param name="v2"></param>
|
|
||||||
/// <param name="v3"></param>
|
|
||||||
/// <param name="v4"></param>
|
|
||||||
/// <param name="length"></param>
|
|
||||||
/// <param name="seed"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private static unsafe ulong UnsafeFinal(byte[] data, int l, ref ulong v1, ref ulong v2, ref ulong v3, ref ulong v4, long length, ulong seed)
|
|
||||||
{
|
|
||||||
fixed (byte* pData = &data[0])
|
|
||||||
{
|
|
||||||
byte* ptr = pData;
|
|
||||||
byte* end = pData + l;
|
|
||||||
ulong h64;
|
|
||||||
|
|
||||||
if (length >= 32)
|
|
||||||
{
|
|
||||||
h64 = BitUtils.RotateLeft(v1, 1) + // rotl 1
|
|
||||||
BitUtils.RotateLeft(v2, 7) + // rotl 7
|
|
||||||
BitUtils.RotateLeft(v3, 12) + // rotl 12
|
|
||||||
BitUtils.RotateLeft(v4, 18); // rotl 18
|
|
||||||
|
|
||||||
// merge round
|
|
||||||
v1 *= p2;
|
|
||||||
v1 = BitUtils.RotateLeft(v1, 31); // rotl 31
|
|
||||||
v1 *= p1;
|
|
||||||
h64 ^= v1;
|
|
||||||
h64 = h64 * p1 + p4;
|
|
||||||
|
|
||||||
// merge round
|
|
||||||
v2 *= p2;
|
|
||||||
v2 = BitUtils.RotateLeft(v2, 31); // rotl 31
|
|
||||||
v2 *= p1;
|
|
||||||
h64 ^= v2;
|
|
||||||
h64 = h64 * p1 + p4;
|
|
||||||
|
|
||||||
// merge round
|
|
||||||
v3 *= p2;
|
|
||||||
v3 = BitUtils.RotateLeft(v3, 31); // rotl 31
|
|
||||||
v3 *= p1;
|
|
||||||
h64 ^= v3;
|
|
||||||
h64 = h64 * p1 + p4;
|
|
||||||
|
|
||||||
// merge round
|
|
||||||
v4 *= p2;
|
|
||||||
v4 = BitUtils.RotateLeft(v4, 31); // rotl 31
|
|
||||||
v4 *= p1;
|
|
||||||
h64 ^= v4;
|
|
||||||
h64 = h64 * p1 + p4;
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
h64 = seed + p5;
|
|
||||||
}
|
|
||||||
|
|
||||||
h64 += (ulong)length;
|
|
||||||
|
|
||||||
// finalize
|
|
||||||
while (ptr <= end - 8)
|
|
||||||
{
|
|
||||||
ulong t1 = *((ulong*)ptr) * p2;
|
|
||||||
t1 = BitUtils.RotateLeft(t1, 31); // rotl 31
|
|
||||||
t1 *= p1;
|
|
||||||
h64 ^= t1;
|
|
||||||
h64 = BitUtils.RotateLeft(h64, 27) * p1 + p4; // (rotl 27) * p1 + p4
|
|
||||||
ptr += 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ptr <= end - 4)
|
|
||||||
{
|
|
||||||
h64 ^= *((uint*)ptr) * p1;
|
|
||||||
h64 = BitUtils.RotateLeft(h64, 23) * p2 + p3; // (rotl 27) * p2 + p3
|
|
||||||
ptr += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (ptr < end)
|
|
||||||
{
|
|
||||||
h64 ^= *((byte*)ptr) * p5;
|
|
||||||
h64 = BitUtils.RotateLeft(h64, 11) * p1; // (rotl 11) * p1
|
|
||||||
ptr += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// avalanche
|
|
||||||
h64 ^= h64 >> 33;
|
|
||||||
h64 *= p2;
|
|
||||||
h64 ^= h64 >> 29;
|
|
||||||
h64 *= p3;
|
|
||||||
h64 ^= h64 >> 32;
|
|
||||||
|
|
||||||
return h64;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
20
src/Standart.Hash.xxHash/xxHash64.XXH.cs
Normal file
20
src/Standart.Hash.xxHash/xxHash64.XXH.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// ReSharper disable InconsistentNaming
|
||||||
|
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace Standart.Hash.xxHash;
|
||||||
|
|
||||||
|
public static partial class xxHash64
|
||||||
|
{
|
||||||
|
private const ulong XXH_PRIME64_1 = 11400714785074694791UL;
|
||||||
|
private const ulong XXH_PRIME64_2 = 14029467366897019727UL;
|
||||||
|
private const ulong XXH_PRIME64_3 = 1609587929392839161UL;
|
||||||
|
private const ulong XXH_PRIME64_4 = 9650029242287828579UL;
|
||||||
|
private const ulong XXH_PRIME64_5 = 2870177450012600261UL;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static ulong XXH_rotl64(ulong x, int r)
|
||||||
|
{
|
||||||
|
return (x << r) | (x >> (64 - r));
|
||||||
|
}
|
||||||
|
}
|
||||||
253
src/Standart.Hash.xxHash/xxHash64.XXH64.cs
Normal file
253
src/Standart.Hash.xxHash/xxHash64.XXH64.cs
Normal file
@ -0,0 +1,253 @@
|
|||||||
|
// ReSharper disable InconsistentNaming
|
||||||
|
|
||||||
|
namespace Standart.Hash.xxHash
|
||||||
|
{
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
public static partial class xxHash64
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static unsafe ulong XXH64_internal(byte* input, int len, ulong seed)
|
||||||
|
{
|
||||||
|
byte* end = input + len;
|
||||||
|
ulong h64;
|
||||||
|
|
||||||
|
if (len >= 32)
|
||||||
|
|
||||||
|
{
|
||||||
|
byte* limit = end - 32;
|
||||||
|
|
||||||
|
ulong v1 = seed + XXH_PRIME64_1 + XXH_PRIME64_2;
|
||||||
|
ulong v2 = seed + XXH_PRIME64_2;
|
||||||
|
ulong v3 = seed + 0;
|
||||||
|
ulong v4 = seed - XXH_PRIME64_1;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// XXH64_round
|
||||||
|
v1 += *((ulong*)input) * XXH_PRIME64_2;
|
||||||
|
v1 = XXH_rotl64(v1, 31);
|
||||||
|
v1 *= XXH_PRIME64_1;
|
||||||
|
input += 8;
|
||||||
|
|
||||||
|
// XXH64_round
|
||||||
|
v2 += *((ulong*)input) * XXH_PRIME64_2;
|
||||||
|
v2 = XXH_rotl64(v2, 31);
|
||||||
|
v2 *= XXH_PRIME64_1;
|
||||||
|
input += 8;
|
||||||
|
|
||||||
|
// XXH64_round
|
||||||
|
v3 += *((ulong*)input) * XXH_PRIME64_2;
|
||||||
|
v3 = XXH_rotl64(v3, 31);
|
||||||
|
v3 *= XXH_PRIME64_1;
|
||||||
|
input += 8;
|
||||||
|
|
||||||
|
// XXH64_round
|
||||||
|
v4 += *((ulong*)input) * XXH_PRIME64_2;
|
||||||
|
v4 = XXH_rotl64(v4, 31);
|
||||||
|
v4 *= XXH_PRIME64_1;
|
||||||
|
input += 8;
|
||||||
|
|
||||||
|
} while (input <= limit);
|
||||||
|
|
||||||
|
h64 = XXH_rotl64(v1, 1) +
|
||||||
|
XXH_rotl64(v2, 7) +
|
||||||
|
XXH_rotl64(v3, 12) +
|
||||||
|
XXH_rotl64(v4, 18);
|
||||||
|
|
||||||
|
// XXH64_mergeRound
|
||||||
|
v1 *= XXH_PRIME64_2;
|
||||||
|
v1 = XXH_rotl64(v1, 31);
|
||||||
|
v1 *= XXH_PRIME64_1;
|
||||||
|
h64 ^= v1;
|
||||||
|
h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4;
|
||||||
|
|
||||||
|
// XXH64_mergeRound
|
||||||
|
v2 *= XXH_PRIME64_2;
|
||||||
|
v2 = XXH_rotl64(v2, 31);
|
||||||
|
v2 *= XXH_PRIME64_1;
|
||||||
|
h64 ^= v2;
|
||||||
|
h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4;
|
||||||
|
|
||||||
|
// XXH64_mergeRound
|
||||||
|
v3 *= XXH_PRIME64_2;
|
||||||
|
v3 = XXH_rotl64(v3, 31);
|
||||||
|
v3 *= XXH_PRIME64_1;
|
||||||
|
h64 ^= v3;
|
||||||
|
h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4;
|
||||||
|
|
||||||
|
// XXH64_mergeRound
|
||||||
|
v4 *= XXH_PRIME64_2;
|
||||||
|
v4 = XXH_rotl64(v4, 31);
|
||||||
|
v4 *= XXH_PRIME64_1;
|
||||||
|
h64 ^= v4;
|
||||||
|
h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
h64 = seed + XXH_PRIME64_5;
|
||||||
|
}
|
||||||
|
|
||||||
|
h64 += (ulong)len;
|
||||||
|
|
||||||
|
// XXH64_finalize
|
||||||
|
while (input <= end - 8)
|
||||||
|
{
|
||||||
|
ulong t1 = *((ulong*)input) * XXH_PRIME64_2;
|
||||||
|
t1 = XXH_rotl64(t1, 31);
|
||||||
|
t1 *= XXH_PRIME64_1;
|
||||||
|
h64 ^= t1;
|
||||||
|
h64 = XXH_rotl64(h64, 27) * XXH_PRIME64_1 + XXH_PRIME64_4;
|
||||||
|
input += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input <= end - 4)
|
||||||
|
{
|
||||||
|
h64 ^= *((uint*)input) * XXH_PRIME64_1;
|
||||||
|
h64 = XXH_rotl64(h64, 23) * XXH_PRIME64_2 + XXH_PRIME64_3;
|
||||||
|
input += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (input < end)
|
||||||
|
{
|
||||||
|
h64 ^= *((byte*)input) * XXH_PRIME64_5;
|
||||||
|
h64 = XXH_rotl64(h64, 11) * XXH_PRIME64_1;
|
||||||
|
input += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXH64_avalanche
|
||||||
|
h64 ^= h64 >> 33;
|
||||||
|
h64 *= XXH_PRIME64_2;
|
||||||
|
h64 ^= h64 >> 29;
|
||||||
|
h64 *= XXH_PRIME64_3;
|
||||||
|
h64 ^= h64 >> 32;
|
||||||
|
|
||||||
|
return h64;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static unsafe void __XXH64_stream_align(byte[] input, int len, ref ulong v1, ref ulong v2, ref ulong v3, ref ulong v4)
|
||||||
|
{
|
||||||
|
fixed (byte* pData = &input[0])
|
||||||
|
{
|
||||||
|
byte* ptr = pData;
|
||||||
|
byte* limit = ptr + len;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// XXH64_round
|
||||||
|
v1 += *((ulong*)ptr) * XXH_PRIME64_2;
|
||||||
|
v1 = XXH_rotl64(v1, 31);
|
||||||
|
v1 *= XXH_PRIME64_1;
|
||||||
|
ptr += 8;
|
||||||
|
|
||||||
|
// XXH64_round
|
||||||
|
v2 += *((ulong*)ptr) * XXH_PRIME64_2;
|
||||||
|
v2 = XXH_rotl64(v2, 31);
|
||||||
|
v2 *= XXH_PRIME64_1;
|
||||||
|
ptr += 8;
|
||||||
|
|
||||||
|
// XXH64_round
|
||||||
|
v3 += *((ulong*)ptr) * XXH_PRIME64_2;
|
||||||
|
v3 = XXH_rotl64(v3, 31);
|
||||||
|
v3 *= XXH_PRIME64_1;
|
||||||
|
ptr += 8;
|
||||||
|
|
||||||
|
// XXH64_round
|
||||||
|
v4 += *((ulong*)ptr) * XXH_PRIME64_2;
|
||||||
|
v4 = XXH_rotl64(v4, 31);
|
||||||
|
v4 *= XXH_PRIME64_1;
|
||||||
|
ptr += 8;
|
||||||
|
|
||||||
|
} while (ptr < limit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static unsafe ulong __XXH64_stream_finalize(byte[] input, int len, ref ulong v1, ref ulong v2, ref ulong v3, ref ulong v4, long length, ulong seed)
|
||||||
|
{
|
||||||
|
fixed (byte* pData = &input[0])
|
||||||
|
{
|
||||||
|
byte* ptr = pData;
|
||||||
|
byte* end = pData + len;
|
||||||
|
ulong h64;
|
||||||
|
|
||||||
|
if (length >= 32)
|
||||||
|
{
|
||||||
|
h64 = XXH_rotl64(v1, 1) +
|
||||||
|
XXH_rotl64(v2, 7) +
|
||||||
|
XXH_rotl64(v3, 12) +
|
||||||
|
XXH_rotl64(v4, 18);
|
||||||
|
|
||||||
|
// XXH64_mergeRound
|
||||||
|
v1 *= XXH_PRIME64_2;
|
||||||
|
v1 = XXH_rotl64(v1, 31);
|
||||||
|
v1 *= XXH_PRIME64_1;
|
||||||
|
h64 ^= v1;
|
||||||
|
h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4;
|
||||||
|
|
||||||
|
// XXH64_mergeRound
|
||||||
|
v2 *= XXH_PRIME64_2;
|
||||||
|
v2 = XXH_rotl64(v2, 31);
|
||||||
|
v2 *= XXH_PRIME64_1;
|
||||||
|
h64 ^= v2;
|
||||||
|
h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4;
|
||||||
|
|
||||||
|
// XXH64_mergeRound
|
||||||
|
v3 *= XXH_PRIME64_2;
|
||||||
|
v3 = XXH_rotl64(v3, 31);
|
||||||
|
v3 *= XXH_PRIME64_1;
|
||||||
|
h64 ^= v3;
|
||||||
|
h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4;
|
||||||
|
|
||||||
|
// XXH64_mergeRound
|
||||||
|
v4 *= XXH_PRIME64_2;
|
||||||
|
v4 = XXH_rotl64(v4, 31);
|
||||||
|
v4 *= XXH_PRIME64_1;
|
||||||
|
h64 ^= v4;
|
||||||
|
h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
h64 = seed + XXH_PRIME64_5;
|
||||||
|
}
|
||||||
|
|
||||||
|
h64 += (ulong)length;
|
||||||
|
|
||||||
|
// XXH64_finalize
|
||||||
|
while (ptr <= end - 8)
|
||||||
|
{
|
||||||
|
ulong t1 = *((ulong*)ptr) * XXH_PRIME64_2;
|
||||||
|
t1 = XXH_rotl64(t1, 31);
|
||||||
|
t1 *= XXH_PRIME64_1;
|
||||||
|
h64 ^= t1;
|
||||||
|
h64 = XXH_rotl64(h64, 27) * XXH_PRIME64_1 + XXH_PRIME64_4;
|
||||||
|
ptr += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ptr <= end - 4)
|
||||||
|
{
|
||||||
|
h64 ^= *((uint*)ptr) * XXH_PRIME64_1;
|
||||||
|
h64 = XXH_rotl64(h64, 23) * XXH_PRIME64_2 + XXH_PRIME64_3;
|
||||||
|
ptr += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (ptr < end)
|
||||||
|
{
|
||||||
|
h64 ^= *((byte*)ptr) * XXH_PRIME64_5;
|
||||||
|
h64 = XXH_rotl64(h64, 11) * XXH_PRIME64_1;
|
||||||
|
ptr += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXH64_avalanche
|
||||||
|
h64 ^= h64 >> 33;
|
||||||
|
h64 *= XXH_PRIME64_2;
|
||||||
|
h64 ^= h64 >> 29;
|
||||||
|
h64 *= XXH_PRIME64_3;
|
||||||
|
h64 ^= h64 >> 32;
|
||||||
|
|
||||||
|
return h64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
261
src/Standart.Hash.xxHash/xxHash64.cs
Normal file
261
src/Standart.Hash.xxHash/xxHash64.cs
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
// ReSharper disable InconsistentNaming
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Standart.Hash.xxHash;
|
||||||
|
|
||||||
|
public static partial class xxHash64
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Compute xxHash for the data byte array
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">The source of data</param>
|
||||||
|
/// <param name="length">The length of the data for hashing</param>
|
||||||
|
/// <param name="seed">The seed number</param>
|
||||||
|
/// <returns>hash</returns>
|
||||||
|
public static unsafe ulong ComputeHash(byte[] data, int length, ulong seed = 0)
|
||||||
|
{
|
||||||
|
Debug.Assert(data != null);
|
||||||
|
Debug.Assert(length >= 0);
|
||||||
|
Debug.Assert(length <= data.Length);
|
||||||
|
|
||||||
|
fixed (byte* pData = &data[0])
|
||||||
|
{
|
||||||
|
return UnsafeComputeHash(pData, length, seed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compute xxHash for the data byte array
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">The source of data</param>
|
||||||
|
/// <param name="length">The length of the data for hashing</param>
|
||||||
|
/// <param name="seed">The seed number</param>
|
||||||
|
/// <returns>hash</returns>
|
||||||
|
public static unsafe ulong ComputeHash(byte[] data, int offset, int length, ulong seed = 0)
|
||||||
|
{
|
||||||
|
Debug.Assert(data != null);
|
||||||
|
Debug.Assert(length >= 0);
|
||||||
|
Debug.Assert(offset < data.Length);
|
||||||
|
Debug.Assert(length <= data.Length - offset);
|
||||||
|
|
||||||
|
fixed (byte* pData = &data[0 + offset])
|
||||||
|
{
|
||||||
|
return UnsafeComputeHash(pData, length, seed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compute xxHash for the data byte array
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">The source of data</param>
|
||||||
|
/// <param name="seed">The seed number</param>
|
||||||
|
/// <returns>hash</returns>
|
||||||
|
public static unsafe ulong ComputeHash(System.ArraySegment<byte> data, ulong seed = 0)
|
||||||
|
{
|
||||||
|
Debug.Assert(data != null);
|
||||||
|
|
||||||
|
return ComputeHash(data.Array, data.Offset, data.Count, seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compute xxHash for the async stream
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The stream of data</param>
|
||||||
|
/// <param name="bufferSize">The buffer size</param>
|
||||||
|
/// <param name="seed">The seed number</param>
|
||||||
|
/// <returns>The hash</returns>
|
||||||
|
public static async ValueTask<ulong> ComputeHashAsync(Stream stream, int bufferSize = 8192, ulong seed = 0)
|
||||||
|
{
|
||||||
|
return await ComputeHashAsync(stream, bufferSize, seed, CancellationToken.None);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compute xxHash for the async stream
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The stream of data</param>
|
||||||
|
/// <param name="bufferSize">The buffer size</param>
|
||||||
|
/// <param name="seed">The seed number</param>
|
||||||
|
/// <param name="cancellationToken">The cancelation token</param>
|
||||||
|
/// <returns>The hash</returns>
|
||||||
|
public static async ValueTask<ulong> ComputeHashAsync(Stream stream, int bufferSize, ulong seed,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
Debug.Assert(stream != null);
|
||||||
|
Debug.Assert(bufferSize > 32);
|
||||||
|
|
||||||
|
// Optimizing memory allocation
|
||||||
|
byte[] buffer = ArrayPool<byte>.Shared.Rent(bufferSize + 32);
|
||||||
|
|
||||||
|
int readBytes;
|
||||||
|
int offset = 0;
|
||||||
|
long length = 0;
|
||||||
|
|
||||||
|
// Prepare the seed vector
|
||||||
|
ulong v1 = seed + XXH_PRIME64_1 + XXH_PRIME64_2;
|
||||||
|
ulong v2 = seed + XXH_PRIME64_2;
|
||||||
|
ulong v3 = seed + 0;
|
||||||
|
ulong v4 = seed - XXH_PRIME64_1;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Read flow of bytes
|
||||||
|
while ((readBytes =
|
||||||
|
await stream.ReadAsync(buffer, offset, bufferSize, cancellationToken).ConfigureAwait(false)) > 0)
|
||||||
|
{
|
||||||
|
length = length + readBytes;
|
||||||
|
offset = offset + readBytes;
|
||||||
|
|
||||||
|
if (offset < 32) continue;
|
||||||
|
|
||||||
|
int r = offset % 32; // remain
|
||||||
|
int l = offset - r; // length
|
||||||
|
|
||||||
|
// Process the next chunk
|
||||||
|
__XXH64_stream_align(buffer, l, ref v1, ref v2, ref v3, ref v4);
|
||||||
|
|
||||||
|
// Put remaining bytes to buffer
|
||||||
|
Utils.BlockCopy(buffer, l, buffer, 0, r);
|
||||||
|
offset = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the final chunk
|
||||||
|
ulong h64 = __XXH64_stream_finalize(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed);
|
||||||
|
|
||||||
|
return h64;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// Free memory
|
||||||
|
ArrayPool<byte>.Shared.Return(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compute xxHash for the data byte span
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">The source of data</param>
|
||||||
|
/// <param name="length">The length of the data for hashing</param>
|
||||||
|
/// <param name="seed">The seed number</param>
|
||||||
|
/// <returns>hash</returns>
|
||||||
|
public static unsafe ulong ComputeHash(Span<byte> data, int length, ulong seed = 0)
|
||||||
|
{
|
||||||
|
Debug.Assert(data != null);
|
||||||
|
Debug.Assert(length >= 0);
|
||||||
|
Debug.Assert(length <= data.Length);
|
||||||
|
|
||||||
|
fixed (byte* pData = &MemoryMarshal.GetReference(data))
|
||||||
|
{
|
||||||
|
return UnsafeComputeHash(pData, length, seed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compute xxHash for the data byte span
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">The source of data</param>
|
||||||
|
/// <param name="length">The length of the data for hashing</param>
|
||||||
|
/// <param name="seed">The seed number</param>
|
||||||
|
/// <returns>hash</returns>
|
||||||
|
public static unsafe ulong ComputeHash(ReadOnlySpan<byte> data, int length, ulong seed = 0)
|
||||||
|
{
|
||||||
|
Debug.Assert(data != null);
|
||||||
|
Debug.Assert(length >= 0);
|
||||||
|
Debug.Assert(length <= data.Length);
|
||||||
|
|
||||||
|
fixed (byte* pData = &MemoryMarshal.GetReference(data))
|
||||||
|
{
|
||||||
|
return UnsafeComputeHash(pData, length, seed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compute xxHash for the stream
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The stream of data</param>
|
||||||
|
/// <param name="bufferSize">The buffer size</param>
|
||||||
|
/// <param name="seed">The seed number</param>
|
||||||
|
/// <returns>The hash</returns>
|
||||||
|
public static ulong ComputeHash(Stream stream, int bufferSize = 8192, ulong seed = 0)
|
||||||
|
{
|
||||||
|
Debug.Assert(stream != null);
|
||||||
|
Debug.Assert(bufferSize > 32);
|
||||||
|
|
||||||
|
// Optimizing memory allocation
|
||||||
|
byte[] buffer = ArrayPool<byte>.Shared.Rent(bufferSize + 32);
|
||||||
|
|
||||||
|
int readBytes;
|
||||||
|
int offset = 0;
|
||||||
|
long length = 0;
|
||||||
|
|
||||||
|
// Prepare the seed vector
|
||||||
|
ulong v1 = seed + XXH_PRIME64_1 + XXH_PRIME64_2;
|
||||||
|
ulong v2 = seed + XXH_PRIME64_2;
|
||||||
|
ulong v3 = seed + 0;
|
||||||
|
ulong v4 = seed - XXH_PRIME64_1;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Read flow of bytes
|
||||||
|
while ((readBytes = stream.Read(buffer, offset, bufferSize)) > 0)
|
||||||
|
{
|
||||||
|
length = length + readBytes;
|
||||||
|
offset = offset + readBytes;
|
||||||
|
|
||||||
|
if (offset < 32) continue;
|
||||||
|
|
||||||
|
int r = offset % 32; // remain
|
||||||
|
int l = offset - r; // length
|
||||||
|
|
||||||
|
// Process the next chunk
|
||||||
|
__XXH64_stream_align(buffer, l, ref v1, ref v2, ref v3, ref v4);
|
||||||
|
|
||||||
|
// Put remaining bytes to buffer
|
||||||
|
Utils.BlockCopy(buffer, l, buffer, 0, r);
|
||||||
|
offset = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the final chunk
|
||||||
|
ulong h64 = __XXH64_stream_finalize(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed);
|
||||||
|
|
||||||
|
return h64;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// Free memory
|
||||||
|
ArrayPool<byte>.Shared.Return(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compute xxHash for the string
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="str">The source of data</param>
|
||||||
|
/// <param name="seed">The seed number</param>
|
||||||
|
/// <returns>hash</returns>
|
||||||
|
public static unsafe ulong ComputeHash(string str, uint seed = 0)
|
||||||
|
{
|
||||||
|
Debug.Assert(str != null);
|
||||||
|
|
||||||
|
fixed (char* c = str)
|
||||||
|
{
|
||||||
|
byte* ptr = (byte*) c;
|
||||||
|
int length = str.Length;
|
||||||
|
|
||||||
|
return UnsafeComputeHash(ptr, length, seed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static unsafe ulong UnsafeComputeHash(byte* ptr, int length, ulong seed)
|
||||||
|
{
|
||||||
|
return XXH64_internal(ptr, length, seed);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user