commit
6b20e7f7b3
@ -1,5 +1,7 @@
|
|||||||
<Project>
|
<Project>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
<TargetFrameworks>net5.0;net6.0</TargetFrameworks>
|
||||||
|
<LangVersion>9.0</LangVersion>
|
||||||
<BenchmarkDotNet>0.13.1</BenchmarkDotNet>
|
<BenchmarkDotNet>0.13.1</BenchmarkDotNet>
|
||||||
<MicrosoftSdk>17.2.0</MicrosoftSdk>
|
<MicrosoftSdk>17.2.0</MicrosoftSdk>
|
||||||
<xUnit>2.4.1</xUnit>
|
<xUnit>2.4.1</xUnit>
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
<Project>
|
<Project>
|
||||||
<Import Project="deps.props" />
|
<Import Project="deps.props" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
|
||||||
<PackageId>Standart.Hash.xxHash</PackageId>
|
<PackageId>Standart.Hash.xxHash</PackageId>
|
||||||
<VersionPrefix>4.0.4</VersionPrefix>
|
<VersionPrefix>4.0.5</VersionPrefix>
|
||||||
<AssemblyName>Standart.Hash.xxHash</AssemblyName>
|
<AssemblyName>Standart.Hash.xxHash</AssemblyName>
|
||||||
<AssemblyTitle>Standart.Hash.xxHash</AssemblyTitle>
|
<AssemblyTitle>Standart.Hash.xxHash</AssemblyTitle>
|
||||||
<Authors>Oleksandr Melnyk</Authors>
|
<Authors>Oleksandr Melnyk</Authors>
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
<Import Project="..\..\deps.props" />
|
<Import Project="..\..\deps.props" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
<Optimize>true</Optimize>
|
<Optimize>true</Optimize>
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
<Import Project="..\..\deps.props" />
|
<Import Project="..\..\deps.props" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
|
||||||
<DebugType>full</DebugType>
|
<DebugType>full</DebugType>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
|||||||
@ -2,112 +2,113 @@ using System;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Standart.Hash.xxHash.Test;
|
namespace Standart.Hash.xxHash.Test
|
||||||
|
|
||||||
public class xxHash128Test
|
|
||||||
{
|
{
|
||||||
[Fact]
|
public class xxHash128Test
|
||||||
public void Compute_hash128_for_bytes()
|
|
||||||
{
|
{
|
||||||
// Arrange
|
[Fact]
|
||||||
var bytes = new byte[]
|
public void Compute_hash128_for_bytes()
|
||||||
{
|
{
|
||||||
0xd2, 0x94, 0x29, 0xc9, 0x4c, 0xc5, 0x0f, 0xbb,
|
// Arrange
|
||||||
0xaa, 0xf4, 0x7c, 0xd5, 0x69, 0x5a, 0xa9, 0xbd,
|
var bytes = new byte[]
|
||||||
0xaf, 0xd8, 0x3f, 0xfb, 0xca, 0x6a, 0xd4, 0x2c,
|
{
|
||||||
0x6c, 0x69, 0x7a, 0x5b, 0x0d, 0xe8, 0xd2, 0xb1,
|
0xd2, 0x94, 0x29, 0xc9, 0x4c, 0xc5, 0x0f, 0xbb,
|
||||||
0x41, 0xb3, 0x1b, 0x23, 0xdb, 0x8c, 0x25, 0xb4,
|
0xaa, 0xf4, 0x7c, 0xd5, 0x69, 0x5a, 0xa9, 0xbd,
|
||||||
0x6c, 0xfb
|
0xaf, 0xd8, 0x3f, 0xfb, 0xca, 0x6a, 0xd4, 0x2c,
|
||||||
};
|
0x6c, 0x69, 0x7a, 0x5b, 0x0d, 0xe8, 0xd2, 0xb1,
|
||||||
|
0x41, 0xb3, 0x1b, 0x23, 0xdb, 0x8c, 0x25, 0xb4,
|
||||||
|
0x6c, 0xfb
|
||||||
|
};
|
||||||
|
|
||||||
ulong expectedH = 3466251221427321594;
|
ulong expectedH = 3466251221427321594;
|
||||||
ulong expectedL = 2862260537881727713;
|
ulong expectedL = 2862260537881727713;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var hash = xxHash128.ComputeHash(bytes, bytes.Length);
|
var hash = xxHash128.ComputeHash(bytes, bytes.Length);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expectedH, hash.high64);
|
Assert.Equal(expectedH, hash.high64);
|
||||||
Assert.Equal(expectedL, hash.low64);
|
Assert.Equal(expectedL, hash.low64);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Compute_hash128_for_span()
|
public void Compute_hash128_for_span()
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var bytes = new byte[]
|
|
||||||
{
|
{
|
||||||
0xd2, 0x94, 0x29, 0xc9, 0x4c, 0xc5, 0x0f, 0xbb,
|
// Arrange
|
||||||
0xaa, 0xf4, 0x7c, 0xd5, 0x69, 0x5a, 0xa9, 0xbd,
|
var bytes = new byte[]
|
||||||
0xaf, 0xd8, 0x3f, 0xfb, 0xca, 0x6a, 0xd4, 0x2c,
|
{
|
||||||
0x6c, 0x69, 0x7a, 0x5b, 0x0d, 0xe8, 0xd2, 0xb1,
|
0xd2, 0x94, 0x29, 0xc9, 0x4c, 0xc5, 0x0f, 0xbb,
|
||||||
0x41, 0xb3, 0x1b, 0x23, 0xdb, 0x8c, 0x25, 0xb4,
|
0xaa, 0xf4, 0x7c, 0xd5, 0x69, 0x5a, 0xa9, 0xbd,
|
||||||
0x6c, 0xfb
|
0xaf, 0xd8, 0x3f, 0xfb, 0xca, 0x6a, 0xd4, 0x2c,
|
||||||
};
|
0x6c, 0x69, 0x7a, 0x5b, 0x0d, 0xe8, 0xd2, 0xb1,
|
||||||
var span = bytes.AsSpan();
|
0x41, 0xb3, 0x1b, 0x23, 0xdb, 0x8c, 0x25, 0xb4,
|
||||||
|
0x6c, 0xfb
|
||||||
|
};
|
||||||
|
var span = bytes.AsSpan();
|
||||||
|
|
||||||
ulong expectedH = 3466251221427321594;
|
ulong expectedH = 3466251221427321594;
|
||||||
ulong expectedL = 2862260537881727713;
|
ulong expectedL = 2862260537881727713;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var hash = xxHash128.ComputeHash(span, span.Length);
|
var hash = xxHash128.ComputeHash(span, span.Length);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expectedH, hash.high64);
|
Assert.Equal(expectedH, hash.high64);
|
||||||
Assert.Equal(expectedL, hash.low64);
|
Assert.Equal(expectedL, hash.low64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Compute_hash128_for_string()
|
public void Compute_hash128_for_string()
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var str = "veni vidi vici";
|
|
||||||
var bytes = Encoding.Unicode.GetBytes(str);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var hash1 = xxHash128.ComputeHash(str);
|
|
||||||
var hash2 = xxHash128.ComputeHash(bytes, bytes.Length);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Equal(hash1.high64, hash2.high64);
|
|
||||||
Assert.Equal(hash1.low64, hash2.low64);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Compute_hash128_bytes_for_bytes()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var bytes = new byte[]
|
|
||||||
{
|
{
|
||||||
0xd2, 0x94, 0x29, 0xc9, 0x4c, 0xc5, 0x0f, 0xbb,
|
// Arrange
|
||||||
0xaa, 0xf4, 0x7c, 0xd5, 0x69, 0x5a, 0xa9, 0xbd,
|
var str = "veni vidi vici";
|
||||||
0xaf, 0xd8, 0x3f, 0xfb, 0xca, 0x6a, 0xd4, 0x2c,
|
var bytes = Encoding.Unicode.GetBytes(str);
|
||||||
0x6c, 0x69, 0x7a, 0x5b, 0x0d, 0xe8, 0xd2, 0xb1,
|
|
||||||
0x41, 0xb3, 0x1b, 0x23, 0xdb, 0x8c, 0x25, 0xb4,
|
|
||||||
0x6c, 0xfb
|
|
||||||
};
|
|
||||||
|
|
||||||
// ulong expectedH = 3466251221427321594;
|
// Act
|
||||||
// ulong expectedL = 2862260537881727713;
|
var hash1 = xxHash128.ComputeHash(str);
|
||||||
|
var hash2 = xxHash128.ComputeHash(bytes, bytes.Length);
|
||||||
|
|
||||||
// (hBits * 18446744073709551616) + lBits
|
// Assert
|
||||||
// (3466251221427321594 * 18446744073709551616) + 2862260537881727713
|
Assert.Equal(hash1.high64, hash2.high64);
|
||||||
|
Assert.Equal(hash1.low64, hash2.low64);
|
||||||
|
}
|
||||||
|
|
||||||
// dec: 63941049176852939372872402763456123617
|
[Fact]
|
||||||
// hex: 301A991EF3707AFA27B8CACB570F12E1
|
public void Compute_hash128_bytes_for_bytes()
|
||||||
var expected = new byte[]
|
|
||||||
{
|
{
|
||||||
0xe1, 0x12, 0x0F, 0x57, 0xcb, 0xca, 0xb8, 0x27,
|
// Arrange
|
||||||
0xfa, 0x7a, 0x70, 0xf3, 0x1e, 0x99, 0x1a, 0x30
|
var bytes = new byte[]
|
||||||
};
|
{
|
||||||
|
0xd2, 0x94, 0x29, 0xc9, 0x4c, 0xc5, 0x0f, 0xbb,
|
||||||
|
0xaa, 0xf4, 0x7c, 0xd5, 0x69, 0x5a, 0xa9, 0xbd,
|
||||||
|
0xaf, 0xd8, 0x3f, 0xfb, 0xca, 0x6a, 0xd4, 0x2c,
|
||||||
|
0x6c, 0x69, 0x7a, 0x5b, 0x0d, 0xe8, 0xd2, 0xb1,
|
||||||
|
0x41, 0xb3, 0x1b, 0x23, 0xdb, 0x8c, 0x25, 0xb4,
|
||||||
|
0x6c, 0xfb
|
||||||
|
};
|
||||||
|
|
||||||
// Act
|
// ulong expectedH = 3466251221427321594;
|
||||||
var hash = xxHash128.ComputeHashBytes(bytes, bytes.Length);
|
// ulong expectedL = 2862260537881727713;
|
||||||
|
|
||||||
|
// (hBits * 18446744073709551616) + lBits
|
||||||
|
// (3466251221427321594 * 18446744073709551616) + 2862260537881727713
|
||||||
|
|
||||||
|
// dec: 63941049176852939372872402763456123617
|
||||||
|
// hex: 301A991EF3707AFA27B8CACB570F12E1
|
||||||
|
var expected = new byte[]
|
||||||
|
{
|
||||||
|
0xe1, 0x12, 0x0F, 0x57, 0xcb, 0xca, 0xb8, 0x27,
|
||||||
|
0xfa, 0x7a, 0x70, 0xf3, 0x1e, 0x99, 0x1a, 0x30
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var hash = xxHash128.ComputeHashBytes(bytes, bytes.Length);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
Assert.Equal(expected[i], hash[i]);
|
||||||
|
}
|
||||||
|
|
||||||
// Assert
|
|
||||||
for (int i = 0; i < 16; i++)
|
|
||||||
Assert.Equal(expected[i], hash[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -3,7 +3,6 @@
|
|||||||
<Import Project="..\..\nuget.props" />
|
<Import Project="..\..\nuget.props" />
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|||||||
@ -6,146 +6,55 @@
|
|||||||
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Standart.Hash.xxHash;
|
namespace Standart.Hash.xxHash
|
||||||
|
|
||||||
public partial class xxHash32
|
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
public partial class xxHash32
|
||||||
private static unsafe uint __inline__XXH32(byte* input, int len, uint seed)
|
|
||||||
{
|
{
|
||||||
uint h32;
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static unsafe uint __inline__XXH32(byte* input, int len, uint seed)
|
||||||
if (len >= 16)
|
|
||||||
{
|
{
|
||||||
byte* end = input + len;
|
|
||||||
byte* limit = end - 15;
|
|
||||||
|
|
||||||
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
|
|
||||||
{
|
|
||||||
var reg1 = *((uint*)(input + 0));
|
|
||||||
var reg2 = *((uint*)(input + 4));
|
|
||||||
var reg3 = *((uint*)(input + 8));
|
|
||||||
var reg4 = *((uint*)(input + 12));
|
|
||||||
|
|
||||||
// XXH32_round
|
|
||||||
v1 += reg1 * XXH_PRIME32_2;
|
|
||||||
v1 = (v1 << 13) | (v1 >> (32 - 13));
|
|
||||||
v1 *= XXH_PRIME32_1;
|
|
||||||
|
|
||||||
// XXH32_round
|
|
||||||
v2 += reg2 * XXH_PRIME32_2;
|
|
||||||
v2 = (v2 << 13) | (v2 >> (32 - 13));
|
|
||||||
v2 *= XXH_PRIME32_1;
|
|
||||||
|
|
||||||
// XXH32_round
|
|
||||||
v3 += reg3 * XXH_PRIME32_2;
|
|
||||||
v3 = (v3 << 13) | (v3 >> (32 - 13));
|
|
||||||
v3 *= XXH_PRIME32_1;
|
|
||||||
|
|
||||||
// XXH32_round
|
|
||||||
v4 += reg4 * XXH_PRIME32_2;
|
|
||||||
v4 = (v4 << 13) | (v4 >> (32 - 13));
|
|
||||||
v4 *= XXH_PRIME32_1;
|
|
||||||
|
|
||||||
input += 16;
|
|
||||||
} while (input < limit);
|
|
||||||
|
|
||||||
h32 = ((v1 << 1) | (v1 >> (32 - 1))) +
|
|
||||||
((v2 << 7) | (v2 >> (32 - 7))) +
|
|
||||||
((v3 << 12) | (v3 >> (32 - 12))) +
|
|
||||||
((v4 << 18) | (v4 >> (32 - 18)));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
h32 = seed + XXH_PRIME32_5;
|
|
||||||
}
|
|
||||||
|
|
||||||
h32 += (uint) len;
|
|
||||||
|
|
||||||
// XXH32_finalize
|
|
||||||
len &= 15;
|
|
||||||
while (len >= 4)
|
|
||||||
{
|
|
||||||
h32 += *((uint*) input) * XXH_PRIME32_3;
|
|
||||||
input += 4;
|
|
||||||
h32 = ((h32 << 17) | (h32 >> (32 - 17))) * XXH_PRIME32_4;
|
|
||||||
len -= 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (len > 0)
|
|
||||||
{
|
|
||||||
h32 += *((byte*) input) * XXH_PRIME32_5;
|
|
||||||
++input;
|
|
||||||
h32 = ((h32 << 11) | (h32 >> (32 - 11))) * XXH_PRIME32_1;
|
|
||||||
--len;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 __inline__XXH32_stream_process(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
|
|
||||||
{
|
|
||||||
var reg1 = *((uint*)(ptr + 0));
|
|
||||||
var reg2 = *((uint*)(ptr + 4));
|
|
||||||
var reg3 = *((uint*)(ptr + 8));
|
|
||||||
var reg4 = *((uint*)(ptr + 12));
|
|
||||||
|
|
||||||
// XXH32_round
|
|
||||||
v1 += reg1 * XXH_PRIME32_2;
|
|
||||||
v1 = (v1 << 13) | (v1 >> (32 - 13));
|
|
||||||
v1 *= XXH_PRIME32_1;
|
|
||||||
|
|
||||||
// XXH32_round
|
|
||||||
v2 += reg2 * XXH_PRIME32_2;
|
|
||||||
v2 = (v2 << 13) | (v2 >> (32 - 13));
|
|
||||||
v2 *= XXH_PRIME32_1;
|
|
||||||
|
|
||||||
// XXH32_round
|
|
||||||
v3 += reg3 * XXH_PRIME32_2;
|
|
||||||
v3 = (v3 << 13) | (v3 >> (32 - 13));
|
|
||||||
v3 *= XXH_PRIME32_1;
|
|
||||||
|
|
||||||
// XXH32_round
|
|
||||||
v4 += reg4 * XXH_PRIME32_2;
|
|
||||||
v4 = (v4 << 13) | (v4 >> (32 - 13));
|
|
||||||
v4 *= XXH_PRIME32_1;
|
|
||||||
|
|
||||||
ptr += 16;
|
|
||||||
|
|
||||||
} while (ptr < limit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private static unsafe uint __inline__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;
|
|
||||||
uint h32;
|
uint h32;
|
||||||
|
|
||||||
if (length >= 16)
|
if (len >= 16)
|
||||||
{
|
{
|
||||||
|
byte* end = input + len;
|
||||||
|
byte* limit = end - 15;
|
||||||
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
var reg1 = *((uint*)(input + 0));
|
||||||
|
var reg2 = *((uint*)(input + 4));
|
||||||
|
var reg3 = *((uint*)(input + 8));
|
||||||
|
var reg4 = *((uint*)(input + 12));
|
||||||
|
|
||||||
|
// XXH32_round
|
||||||
|
v1 += reg1 * XXH_PRIME32_2;
|
||||||
|
v1 = (v1 << 13) | (v1 >> (32 - 13));
|
||||||
|
v1 *= XXH_PRIME32_1;
|
||||||
|
|
||||||
|
// XXH32_round
|
||||||
|
v2 += reg2 * XXH_PRIME32_2;
|
||||||
|
v2 = (v2 << 13) | (v2 >> (32 - 13));
|
||||||
|
v2 *= XXH_PRIME32_1;
|
||||||
|
|
||||||
|
// XXH32_round
|
||||||
|
v3 += reg3 * XXH_PRIME32_2;
|
||||||
|
v3 = (v3 << 13) | (v3 >> (32 - 13));
|
||||||
|
v3 *= XXH_PRIME32_1;
|
||||||
|
|
||||||
|
// XXH32_round
|
||||||
|
v4 += reg4 * XXH_PRIME32_2;
|
||||||
|
v4 = (v4 << 13) | (v4 >> (32 - 13));
|
||||||
|
v4 *= XXH_PRIME32_1;
|
||||||
|
|
||||||
|
input += 16;
|
||||||
|
} while (input < limit);
|
||||||
|
|
||||||
h32 = ((v1 << 1) | (v1 >> (32 - 1))) +
|
h32 = ((v1 << 1) | (v1 >> (32 - 1))) +
|
||||||
((v2 << 7) | (v2 >> (32 - 7))) +
|
((v2 << 7) | (v2 >> (32 - 7))) +
|
||||||
((v3 << 12) | (v3 >> (32 - 12))) +
|
((v3 << 12) | (v3 >> (32 - 12))) +
|
||||||
@ -156,24 +65,24 @@ public partial class xxHash32
|
|||||||
h32 = seed + XXH_PRIME32_5;
|
h32 = seed + XXH_PRIME32_5;
|
||||||
}
|
}
|
||||||
|
|
||||||
h32 += (uint)length;
|
h32 += (uint) len;
|
||||||
|
|
||||||
// XXH32_finalize
|
// XXH32_finalize
|
||||||
len &= 15;
|
len &= 15;
|
||||||
while (len >= 4)
|
while (len >= 4)
|
||||||
{
|
{
|
||||||
h32 += *((uint*)ptr) * XXH_PRIME32_3;
|
h32 += *((uint*) input) * XXH_PRIME32_3;
|
||||||
ptr += 4;
|
input += 4;
|
||||||
h32 = ((h32 << 17) | (h32 >> (32 - 17))) * XXH_PRIME32_4;
|
h32 = ((h32 << 17) | (h32 >> (32 - 17))) * XXH_PRIME32_4;
|
||||||
len -= 4;
|
len -= 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (len > 0)
|
while (len > 0)
|
||||||
{
|
{
|
||||||
h32 += *((byte*)ptr) * XXH_PRIME32_5;
|
h32 += *((byte*) input) * XXH_PRIME32_5;
|
||||||
ptr++;
|
++input;
|
||||||
h32 = ((h32 << 11) | (h32 >> (32 - 11))) * XXH_PRIME32_1;
|
h32 = ((h32 << 11) | (h32 >> (32 - 11))) * XXH_PRIME32_1;
|
||||||
len--;
|
--len;
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXH32_avalanche
|
// XXH32_avalanche
|
||||||
@ -185,5 +94,98 @@ public partial class xxHash32
|
|||||||
|
|
||||||
return h32;
|
return h32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static unsafe void __inline__XXH32_stream_process(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
|
||||||
|
{
|
||||||
|
var reg1 = *((uint*)(ptr + 0));
|
||||||
|
var reg2 = *((uint*)(ptr + 4));
|
||||||
|
var reg3 = *((uint*)(ptr + 8));
|
||||||
|
var reg4 = *((uint*)(ptr + 12));
|
||||||
|
|
||||||
|
// XXH32_round
|
||||||
|
v1 += reg1 * XXH_PRIME32_2;
|
||||||
|
v1 = (v1 << 13) | (v1 >> (32 - 13));
|
||||||
|
v1 *= XXH_PRIME32_1;
|
||||||
|
|
||||||
|
// XXH32_round
|
||||||
|
v2 += reg2 * XXH_PRIME32_2;
|
||||||
|
v2 = (v2 << 13) | (v2 >> (32 - 13));
|
||||||
|
v2 *= XXH_PRIME32_1;
|
||||||
|
|
||||||
|
// XXH32_round
|
||||||
|
v3 += reg3 * XXH_PRIME32_2;
|
||||||
|
v3 = (v3 << 13) | (v3 >> (32 - 13));
|
||||||
|
v3 *= XXH_PRIME32_1;
|
||||||
|
|
||||||
|
// XXH32_round
|
||||||
|
v4 += reg4 * XXH_PRIME32_2;
|
||||||
|
v4 = (v4 << 13) | (v4 >> (32 - 13));
|
||||||
|
v4 *= XXH_PRIME32_1;
|
||||||
|
|
||||||
|
ptr += 16;
|
||||||
|
|
||||||
|
} while (ptr < limit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static unsafe uint __inline__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;
|
||||||
|
uint h32;
|
||||||
|
|
||||||
|
if (length >= 16)
|
||||||
|
{
|
||||||
|
h32 = ((v1 << 1) | (v1 >> (32 - 1))) +
|
||||||
|
((v2 << 7) | (v2 >> (32 - 7))) +
|
||||||
|
((v3 << 12) | (v3 >> (32 - 12))) +
|
||||||
|
((v4 << 18) | (v4 >> (32 - 18)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
h32 = seed + XXH_PRIME32_5;
|
||||||
|
}
|
||||||
|
|
||||||
|
h32 += (uint)length;
|
||||||
|
|
||||||
|
// XXH32_finalize
|
||||||
|
len &= 15;
|
||||||
|
while (len >= 4)
|
||||||
|
{
|
||||||
|
h32 += *((uint*)ptr) * XXH_PRIME32_3;
|
||||||
|
ptr += 4;
|
||||||
|
h32 = ((h32 << 17) | (h32 >> (32 - 17))) * XXH_PRIME32_4;
|
||||||
|
len -= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (len > 0)
|
||||||
|
{
|
||||||
|
h32 += *((byte*)ptr) * XXH_PRIME32_5;
|
||||||
|
ptr++;
|
||||||
|
h32 = ((h32 << 11) | (h32 >> (32 - 11))) * XXH_PRIME32_1;
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXH32_avalanche
|
||||||
|
h32 ^= h32 >> 15;
|
||||||
|
h32 *= XXH_PRIME32_2;
|
||||||
|
h32 ^= h32 >> 13;
|
||||||
|
h32 *= XXH_PRIME32_3;
|
||||||
|
h32 ^= h32 >> 16;
|
||||||
|
|
||||||
|
return h32;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,177 +6,54 @@
|
|||||||
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Standart.Hash.xxHash;
|
namespace Standart.Hash.xxHash
|
||||||
|
|
||||||
public partial class xxHash64
|
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
public partial class xxHash64
|
||||||
private static unsafe ulong __inline__XXH64(byte* input, int len, ulong seed)
|
|
||||||
{
|
{
|
||||||
ulong h64;
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static unsafe ulong __inline__XXH64(byte* input, int len, ulong seed)
|
||||||
if (len >= 32)
|
|
||||||
{
|
{
|
||||||
byte* end = input + len;
|
|
||||||
byte* limit = end - 31;
|
|
||||||
|
|
||||||
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
|
|
||||||
{
|
|
||||||
var reg1 = *((ulong*)(input + 0));
|
|
||||||
var reg2 = *((ulong*)(input + 8));
|
|
||||||
var reg3 = *((ulong*)(input + 16));
|
|
||||||
var reg4 = *((ulong*)(input + 24));
|
|
||||||
|
|
||||||
// XXH64_round
|
|
||||||
v1 += reg1 * XXH_PRIME64_2;
|
|
||||||
v1 = (v1 << 31) | (v1 >> (64 - 31));
|
|
||||||
v1 *= XXH_PRIME64_1;
|
|
||||||
|
|
||||||
// XXH64_round
|
|
||||||
v2 += reg2 * XXH_PRIME64_2;
|
|
||||||
v2 = (v2 << 31) | (v2 >> (64 - 31));
|
|
||||||
v2 *= XXH_PRIME64_1;
|
|
||||||
|
|
||||||
// XXH64_round
|
|
||||||
v3 += reg3 * XXH_PRIME64_2;
|
|
||||||
v3 = (v3 << 31) | (v3 >> (64 - 31));
|
|
||||||
v3 *= XXH_PRIME64_1;
|
|
||||||
|
|
||||||
// XXH64_round
|
|
||||||
v4 += reg4 * XXH_PRIME64_2;
|
|
||||||
v4 = (v4 << 31) | (v4 >> (64 - 31));
|
|
||||||
v4 *= XXH_PRIME64_1;
|
|
||||||
input += 32;
|
|
||||||
} while (input < limit);
|
|
||||||
|
|
||||||
h64 = ((v1 << 1) | (v1 >> (64 - 1))) +
|
|
||||||
((v2 << 7) | (v2 >> (64 - 7))) +
|
|
||||||
((v3 << 12) | (v3 >> (64 - 12))) +
|
|
||||||
((v4 << 18) | (v4 >> (64 - 18)));
|
|
||||||
|
|
||||||
// XXH64_mergeRound
|
|
||||||
v1 *= XXH_PRIME64_2;
|
|
||||||
v1 = (v1 << 31) | (v1 >> (64 - 31));
|
|
||||||
v1 *= XXH_PRIME64_1;
|
|
||||||
h64 ^= v1;
|
|
||||||
h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4;
|
|
||||||
|
|
||||||
// XXH64_mergeRound
|
|
||||||
v2 *= XXH_PRIME64_2;
|
|
||||||
v2 = (v2 << 31) | (v2 >> (64 - 31));
|
|
||||||
v2 *= XXH_PRIME64_1;
|
|
||||||
h64 ^= v2;
|
|
||||||
h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4;
|
|
||||||
|
|
||||||
// XXH64_mergeRound
|
|
||||||
v3 *= XXH_PRIME64_2;
|
|
||||||
v3 = (v3 << 31) | (v3 >> (64 - 31));
|
|
||||||
v3 *= XXH_PRIME64_1;
|
|
||||||
h64 ^= v3;
|
|
||||||
h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4;
|
|
||||||
|
|
||||||
// XXH64_mergeRound
|
|
||||||
v4 *= XXH_PRIME64_2;
|
|
||||||
v4 = (v4 << 31) | (v4 >> (64 - 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
|
|
||||||
len &= 31;
|
|
||||||
while (len >= 8) {
|
|
||||||
ulong k1 = XXH64_round(0, *(ulong*)input);
|
|
||||||
input += 8;
|
|
||||||
h64 ^= k1;
|
|
||||||
h64 = XXH_rotl64(h64,27) * XXH_PRIME64_1 + XXH_PRIME64_4;
|
|
||||||
len -= 8;
|
|
||||||
}
|
|
||||||
if (len >= 4) {
|
|
||||||
h64 ^= *(uint*)input * XXH_PRIME64_1;
|
|
||||||
input += 4;
|
|
||||||
h64 = XXH_rotl64(h64, 23) * XXH_PRIME64_2 + XXH_PRIME64_3;
|
|
||||||
len -= 4;
|
|
||||||
}
|
|
||||||
while (len > 0) {
|
|
||||||
h64 ^= (*input++) * XXH_PRIME64_5;
|
|
||||||
h64 = XXH_rotl64(h64, 11) * XXH_PRIME64_1;
|
|
||||||
--len;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 __inline__XXH64_stream_process(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
|
|
||||||
{
|
|
||||||
var reg1 = *((ulong*)(ptr + 0));
|
|
||||||
var reg2 = *((ulong*)(ptr + 8));
|
|
||||||
var reg3 = *((ulong*)(ptr + 16));
|
|
||||||
var reg4 = *((ulong*)(ptr + 24));
|
|
||||||
|
|
||||||
// XXH64_round
|
|
||||||
v1 += reg1 * XXH_PRIME64_2;
|
|
||||||
v1 = (v1 << 31) | (v1 >> (64 - 31));
|
|
||||||
v1 *= XXH_PRIME64_1;
|
|
||||||
|
|
||||||
// XXH64_round
|
|
||||||
v2 += reg2 * XXH_PRIME64_2;
|
|
||||||
v2 = (v2 << 31) | (v2 >> (64 - 31));
|
|
||||||
v2 *= XXH_PRIME64_1;
|
|
||||||
|
|
||||||
// XXH64_round
|
|
||||||
v3 += reg3 * XXH_PRIME64_2;
|
|
||||||
v3 = (v3 << 31) | (v3 >> (64 - 31));
|
|
||||||
v3 *= XXH_PRIME64_1;
|
|
||||||
|
|
||||||
// XXH64_round
|
|
||||||
v4 += reg4 * XXH_PRIME64_2;
|
|
||||||
v4 = (v4 << 31) | (v4 >> (64 - 31));
|
|
||||||
v4 *= XXH_PRIME64_1;
|
|
||||||
ptr += 32;
|
|
||||||
} while (ptr < limit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private static unsafe ulong __inline__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;
|
ulong h64;
|
||||||
|
|
||||||
if (length >= 32)
|
if (len >= 32)
|
||||||
{
|
{
|
||||||
|
byte* end = input + len;
|
||||||
|
byte* limit = end - 31;
|
||||||
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
var reg1 = *((ulong*)(input + 0));
|
||||||
|
var reg2 = *((ulong*)(input + 8));
|
||||||
|
var reg3 = *((ulong*)(input + 16));
|
||||||
|
var reg4 = *((ulong*)(input + 24));
|
||||||
|
|
||||||
|
// XXH64_round
|
||||||
|
v1 += reg1 * XXH_PRIME64_2;
|
||||||
|
v1 = (v1 << 31) | (v1 >> (64 - 31));
|
||||||
|
v1 *= XXH_PRIME64_1;
|
||||||
|
|
||||||
|
// XXH64_round
|
||||||
|
v2 += reg2 * XXH_PRIME64_2;
|
||||||
|
v2 = (v2 << 31) | (v2 >> (64 - 31));
|
||||||
|
v2 *= XXH_PRIME64_1;
|
||||||
|
|
||||||
|
// XXH64_round
|
||||||
|
v3 += reg3 * XXH_PRIME64_2;
|
||||||
|
v3 = (v3 << 31) | (v3 >> (64 - 31));
|
||||||
|
v3 *= XXH_PRIME64_1;
|
||||||
|
|
||||||
|
// XXH64_round
|
||||||
|
v4 += reg4 * XXH_PRIME64_2;
|
||||||
|
v4 = (v4 << 31) | (v4 >> (64 - 31));
|
||||||
|
v4 *= XXH_PRIME64_1;
|
||||||
|
input += 32;
|
||||||
|
} while (input < limit);
|
||||||
|
|
||||||
h64 = ((v1 << 1) | (v1 >> (64 - 1))) +
|
h64 = ((v1 << 1) | (v1 >> (64 - 1))) +
|
||||||
((v2 << 7) | (v2 >> (64 - 7))) +
|
((v2 << 7) | (v2 >> (64 - 7))) +
|
||||||
((v3 << 12) | (v3 >> (64 - 12))) +
|
((v3 << 12) | (v3 >> (64 - 12))) +
|
||||||
@ -215,25 +92,25 @@ public partial class xxHash64
|
|||||||
h64 = seed + XXH_PRIME64_5;
|
h64 = seed + XXH_PRIME64_5;
|
||||||
}
|
}
|
||||||
|
|
||||||
h64 += (ulong) length;
|
h64 += (ulong) len;
|
||||||
|
|
||||||
// XXH64_finalize
|
// XXH64_finalize
|
||||||
len &= 31;
|
len &= 31;
|
||||||
while (len >= 8) {
|
while (len >= 8) {
|
||||||
ulong k1 = XXH64_round(0, *(ulong*)ptr);
|
ulong k1 = XXH64_round(0, *(ulong*)input);
|
||||||
ptr += 8;
|
input += 8;
|
||||||
h64 ^= k1;
|
h64 ^= k1;
|
||||||
h64 = XXH_rotl64(h64,27) * XXH_PRIME64_1 + XXH_PRIME64_4;
|
h64 = XXH_rotl64(h64,27) * XXH_PRIME64_1 + XXH_PRIME64_4;
|
||||||
len -= 8;
|
len -= 8;
|
||||||
}
|
}
|
||||||
if (len >= 4) {
|
if (len >= 4) {
|
||||||
h64 ^= *(uint*)ptr * XXH_PRIME64_1;
|
h64 ^= *(uint*)input * XXH_PRIME64_1;
|
||||||
ptr += 4;
|
input += 4;
|
||||||
h64 = XXH_rotl64(h64, 23) * XXH_PRIME64_2 + XXH_PRIME64_3;
|
h64 = XXH_rotl64(h64, 23) * XXH_PRIME64_2 + XXH_PRIME64_3;
|
||||||
len -= 4;
|
len -= 4;
|
||||||
}
|
}
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
h64 ^= (*ptr++) * XXH_PRIME64_5;
|
h64 ^= (*input++) * XXH_PRIME64_5;
|
||||||
h64 = XXH_rotl64(h64, 11) * XXH_PRIME64_1;
|
h64 = XXH_rotl64(h64, 11) * XXH_PRIME64_1;
|
||||||
--len;
|
--len;
|
||||||
}
|
}
|
||||||
@ -247,5 +124,129 @@ public partial class xxHash64
|
|||||||
|
|
||||||
return h64;
|
return h64;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static unsafe void __inline__XXH64_stream_process(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
|
||||||
|
{
|
||||||
|
var reg1 = *((ulong*)(ptr + 0));
|
||||||
|
var reg2 = *((ulong*)(ptr + 8));
|
||||||
|
var reg3 = *((ulong*)(ptr + 16));
|
||||||
|
var reg4 = *((ulong*)(ptr + 24));
|
||||||
|
|
||||||
|
// XXH64_round
|
||||||
|
v1 += reg1 * XXH_PRIME64_2;
|
||||||
|
v1 = (v1 << 31) | (v1 >> (64 - 31));
|
||||||
|
v1 *= XXH_PRIME64_1;
|
||||||
|
|
||||||
|
// XXH64_round
|
||||||
|
v2 += reg2 * XXH_PRIME64_2;
|
||||||
|
v2 = (v2 << 31) | (v2 >> (64 - 31));
|
||||||
|
v2 *= XXH_PRIME64_1;
|
||||||
|
|
||||||
|
// XXH64_round
|
||||||
|
v3 += reg3 * XXH_PRIME64_2;
|
||||||
|
v3 = (v3 << 31) | (v3 >> (64 - 31));
|
||||||
|
v3 *= XXH_PRIME64_1;
|
||||||
|
|
||||||
|
// XXH64_round
|
||||||
|
v4 += reg4 * XXH_PRIME64_2;
|
||||||
|
v4 = (v4 << 31) | (v4 >> (64 - 31));
|
||||||
|
v4 *= XXH_PRIME64_1;
|
||||||
|
ptr += 32;
|
||||||
|
} while (ptr < limit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static unsafe ulong __inline__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 = ((v1 << 1) | (v1 >> (64 - 1))) +
|
||||||
|
((v2 << 7) | (v2 >> (64 - 7))) +
|
||||||
|
((v3 << 12) | (v3 >> (64 - 12))) +
|
||||||
|
((v4 << 18) | (v4 >> (64 - 18)));
|
||||||
|
|
||||||
|
// XXH64_mergeRound
|
||||||
|
v1 *= XXH_PRIME64_2;
|
||||||
|
v1 = (v1 << 31) | (v1 >> (64 - 31));
|
||||||
|
v1 *= XXH_PRIME64_1;
|
||||||
|
h64 ^= v1;
|
||||||
|
h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4;
|
||||||
|
|
||||||
|
// XXH64_mergeRound
|
||||||
|
v2 *= XXH_PRIME64_2;
|
||||||
|
v2 = (v2 << 31) | (v2 >> (64 - 31));
|
||||||
|
v2 *= XXH_PRIME64_1;
|
||||||
|
h64 ^= v2;
|
||||||
|
h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4;
|
||||||
|
|
||||||
|
// XXH64_mergeRound
|
||||||
|
v3 *= XXH_PRIME64_2;
|
||||||
|
v3 = (v3 << 31) | (v3 >> (64 - 31));
|
||||||
|
v3 *= XXH_PRIME64_1;
|
||||||
|
h64 ^= v3;
|
||||||
|
h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4;
|
||||||
|
|
||||||
|
// XXH64_mergeRound
|
||||||
|
v4 *= XXH_PRIME64_2;
|
||||||
|
v4 = (v4 << 31) | (v4 >> (64 - 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
|
||||||
|
len &= 31;
|
||||||
|
while (len >= 8) {
|
||||||
|
ulong k1 = XXH64_round(0, *(ulong*)ptr);
|
||||||
|
ptr += 8;
|
||||||
|
h64 ^= k1;
|
||||||
|
h64 = XXH_rotl64(h64,27) * XXH_PRIME64_1 + XXH_PRIME64_4;
|
||||||
|
len -= 8;
|
||||||
|
}
|
||||||
|
if (len >= 4) {
|
||||||
|
h64 ^= *(uint*)ptr * XXH_PRIME64_1;
|
||||||
|
ptr += 4;
|
||||||
|
h64 = XXH_rotl64(h64, 23) * XXH_PRIME64_2 + XXH_PRIME64_3;
|
||||||
|
len -= 4;
|
||||||
|
}
|
||||||
|
while (len > 0) {
|
||||||
|
h64 ^= (*ptr++) * XXH_PRIME64_5;
|
||||||
|
h64 = XXH_rotl64(h64, 11) * XXH_PRIME64_1;
|
||||||
|
--len;
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXH64_avalanche
|
||||||
|
h64 ^= h64 >> 33;
|
||||||
|
h64 *= XXH_PRIME64_2;
|
||||||
|
h64 ^= h64 >> 29;
|
||||||
|
h64 *= XXH_PRIME64_3;
|
||||||
|
h64 ^= h64 >> 32;
|
||||||
|
|
||||||
|
return h64;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2,19 +2,20 @@
|
|||||||
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Standart.Hash.xxHash;
|
namespace Standart.Hash.xxHash
|
||||||
|
|
||||||
public static partial class xxHash32
|
|
||||||
{
|
{
|
||||||
private static readonly uint XXH_PRIME32_1 = 2654435761U;
|
public static partial class xxHash32
|
||||||
private static readonly uint XXH_PRIME32_2 = 2246822519U;
|
|
||||||
private static readonly uint XXH_PRIME32_3 = 3266489917U;
|
|
||||||
private static readonly uint XXH_PRIME32_4 = 668265263U;
|
|
||||||
private static readonly uint XXH_PRIME32_5 = 374761393U;
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private static uint XXH_rotl32(uint x, int r)
|
|
||||||
{
|
{
|
||||||
return (x << r) | (x >> (32 - r));
|
private static readonly uint XXH_PRIME32_1 = 2654435761U;
|
||||||
|
private static readonly uint XXH_PRIME32_2 = 2246822519U;
|
||||||
|
private static readonly uint XXH_PRIME32_3 = 3266489917U;
|
||||||
|
private static readonly uint XXH_PRIME32_4 = 668265263U;
|
||||||
|
private static readonly uint XXH_PRIME32_5 = 374761393U;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static uint XXH_rotl32(uint x, int r)
|
||||||
|
{
|
||||||
|
return (x << r) | (x >> (32 - r));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -9,256 +9,257 @@ using System.Runtime.InteropServices;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Standart.Hash.xxHash;
|
namespace Standart.Hash.xxHash
|
||||||
|
|
||||||
public static partial class xxHash32
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
public static partial class xxHash32
|
||||||
/// 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);
|
/// <summary>
|
||||||
Debug.Assert(length >= 0);
|
/// Compute xxHash for the data byte array
|
||||||
Debug.Assert(length <= data.Length);
|
/// </summary>
|
||||||
|
/// <param name="data">The source of data</param>
|
||||||
fixed (byte* pData = &data[0])
|
/// <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)
|
||||||
{
|
{
|
||||||
return UnsafeComputeHash(pData, length, seed);
|
Debug.Assert(data != null);
|
||||||
}
|
Debug.Assert(length >= 0);
|
||||||
}
|
Debug.Assert(length <= data.Length);
|
||||||
|
|
||||||
/// <summary>
|
fixed (byte* pData = &data[0])
|
||||||
/// 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;
|
return UnsafeComputeHash(pData, length, seed);
|
||||||
offset = offset + readBytes;
|
|
||||||
|
|
||||||
if (offset < 16) continue;
|
|
||||||
|
|
||||||
int r = offset % 16; // remain
|
|
||||||
int l = offset - r; // length
|
|
||||||
|
|
||||||
// Process the next chunk
|
|
||||||
__inline__XXH32_stream_process(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 = __inline__XXH32_stream_finalize(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed);
|
|
||||||
|
|
||||||
return h32;
|
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
|
/// <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)
|
||||||
{
|
{
|
||||||
// Free memory
|
Debug.Assert(data != null);
|
||||||
ArrayPool<byte>.Shared.Return(buffer);
|
Debug.Assert(length >= 0);
|
||||||
}
|
Debug.Assert(offset < data.Length);
|
||||||
}
|
Debug.Assert(length <= data.Length - offset);
|
||||||
|
|
||||||
/// <summary>
|
fixed (byte* pData = &data[0 + offset])
|
||||||
/// 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;
|
return UnsafeComputeHash(pData, length, seed);
|
||||||
offset = offset + readBytes;
|
|
||||||
|
|
||||||
if (offset < 16) continue;
|
|
||||||
|
|
||||||
int r = offset % 16; // remain
|
|
||||||
int l = offset - r; // length
|
|
||||||
|
|
||||||
// Process the next chunk
|
|
||||||
__inline__XXH32_stream_process(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 = __inline__XXH32_stream_finalize(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed);
|
|
||||||
|
|
||||||
return h32;
|
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
|
/// <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)
|
||||||
{
|
{
|
||||||
// Free memory
|
Debug.Assert(data != null);
|
||||||
ArrayPool<byte>.Shared.Return(buffer);
|
|
||||||
|
return ComputeHash(data.Array, data.Offset, data.Count, seed);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Compute xxHash for the string
|
/// Compute xxHash for the async stream
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="str">The source of data</param>
|
/// <param name="stream">The stream of data</param>
|
||||||
/// <param name="seed">The seed number</param>
|
/// <param name="bufferSize">The buffer size</param>
|
||||||
/// <returns>hash</returns>
|
/// <param name="seed">The seed number</param>
|
||||||
public static unsafe uint ComputeHash(string str, uint seed = 0)
|
/// <returns>The hash</returns>
|
||||||
{
|
public static async ValueTask<uint> ComputeHashAsync(Stream stream, int bufferSize = 4096, uint seed = 0)
|
||||||
Debug.Assert(str != null);
|
|
||||||
|
|
||||||
fixed (char* c = str)
|
|
||||||
{
|
{
|
||||||
byte* ptr = (byte*) c;
|
return await ComputeHashAsync(stream, bufferSize, seed, CancellationToken.None);
|
||||||
int length = str.Length * 2;
|
|
||||||
|
|
||||||
return UnsafeComputeHash(ptr, length, seed);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
/// <summary>
|
||||||
private static unsafe uint UnsafeComputeHash(byte* ptr, int length, uint seed)
|
/// Compute xxHash for the async stream
|
||||||
{
|
/// </summary>
|
||||||
// Use inlined version
|
/// <param name="stream">The stream of data</param>
|
||||||
// return XXH32(ptr, length, seed);
|
/// <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);
|
||||||
|
|
||||||
return __inline__XXH32(ptr, length, seed);
|
// 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
|
||||||
|
__inline__XXH32_stream_process(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 = __inline__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
|
||||||
|
__inline__XXH32_stream_process(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 = __inline__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 * 2;
|
||||||
|
|
||||||
|
return UnsafeComputeHash(ptr, length, seed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static unsafe uint UnsafeComputeHash(byte* ptr, int length, uint seed)
|
||||||
|
{
|
||||||
|
// Use inlined version
|
||||||
|
// return XXH32(ptr, length, seed);
|
||||||
|
|
||||||
|
return __inline__XXH32(ptr, length, seed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2,19 +2,20 @@
|
|||||||
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Standart.Hash.xxHash;
|
namespace Standart.Hash.xxHash
|
||||||
|
|
||||||
public static partial class xxHash64
|
|
||||||
{
|
{
|
||||||
private static readonly ulong XXH_PRIME64_1 = 11400714785074694791UL;
|
public static partial class xxHash64
|
||||||
private static readonly ulong XXH_PRIME64_2 = 14029467366897019727UL;
|
|
||||||
private static readonly ulong XXH_PRIME64_3 = 1609587929392839161UL;
|
|
||||||
private static readonly ulong XXH_PRIME64_4 = 9650029242287828579UL;
|
|
||||||
private static readonly ulong XXH_PRIME64_5 = 2870177450012600261UL;
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private static ulong XXH_rotl64(ulong x, int r)
|
|
||||||
{
|
{
|
||||||
return (x << r) | (x >> (64 - r));
|
private static readonly ulong XXH_PRIME64_1 = 11400714785074694791UL;
|
||||||
|
private static readonly ulong XXH_PRIME64_2 = 14029467366897019727UL;
|
||||||
|
private static readonly ulong XXH_PRIME64_3 = 1609587929392839161UL;
|
||||||
|
private static readonly ulong XXH_PRIME64_4 = 9650029242287828579UL;
|
||||||
|
private static readonly ulong XXH_PRIME64_5 = 2870177450012600261UL;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static ulong XXH_rotl64(ulong x, int r)
|
||||||
|
{
|
||||||
|
return (x << r) | (x >> (64 - r));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -9,256 +9,258 @@ using System.Runtime.InteropServices;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Standart.Hash.xxHash;
|
namespace Standart.Hash.xxHash
|
||||||
|
|
||||||
public static partial class xxHash64
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
public static partial class xxHash64
|
||||||
/// 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);
|
/// <summary>
|
||||||
Debug.Assert(length >= 0);
|
/// Compute xxHash for the data byte array
|
||||||
Debug.Assert(length <= data.Length);
|
/// </summary>
|
||||||
|
/// <param name="data">The source of data</param>
|
||||||
fixed (byte* pData = &data[0])
|
/// <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)
|
||||||
{
|
{
|
||||||
return UnsafeComputeHash(pData, length, seed);
|
Debug.Assert(data != null);
|
||||||
}
|
Debug.Assert(length >= 0);
|
||||||
}
|
Debug.Assert(length <= data.Length);
|
||||||
|
|
||||||
/// <summary>
|
fixed (byte* pData = &data[0])
|
||||||
/// 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;
|
return UnsafeComputeHash(pData, length, seed);
|
||||||
offset = offset + readBytes;
|
|
||||||
|
|
||||||
if (offset < 32) continue;
|
|
||||||
|
|
||||||
int r = offset % 32; // remain
|
|
||||||
int l = offset - r; // length
|
|
||||||
|
|
||||||
// Process the next chunk
|
|
||||||
__inline__XXH64_stream_process(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 = __inline__XXH64_stream_finalize(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed);
|
|
||||||
|
|
||||||
return h64;
|
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
|
/// <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)
|
||||||
{
|
{
|
||||||
// Free memory
|
Debug.Assert(data != null);
|
||||||
ArrayPool<byte>.Shared.Return(buffer);
|
Debug.Assert(length >= 0);
|
||||||
}
|
Debug.Assert(offset < data.Length);
|
||||||
}
|
Debug.Assert(length <= data.Length - offset);
|
||||||
|
|
||||||
/// <summary>
|
fixed (byte* pData = &data[0 + offset])
|
||||||
/// 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;
|
return UnsafeComputeHash(pData, length, seed);
|
||||||
offset = offset + readBytes;
|
|
||||||
|
|
||||||
if (offset < 32) continue;
|
|
||||||
|
|
||||||
int r = offset % 32; // remain
|
|
||||||
int l = offset - r; // length
|
|
||||||
|
|
||||||
// Process the next chunk
|
|
||||||
__inline__XXH64_stream_process(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 = __inline__XXH64_stream_finalize(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed);
|
|
||||||
|
|
||||||
return h64;
|
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
|
/// <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)
|
||||||
{
|
{
|
||||||
// Free memory
|
Debug.Assert(data != null);
|
||||||
ArrayPool<byte>.Shared.Return(buffer);
|
|
||||||
|
return ComputeHash(data.Array, data.Offset, data.Count, seed);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Compute xxHash for the string
|
/// Compute xxHash for the async stream
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="str">The source of data</param>
|
/// <param name="stream">The stream of data</param>
|
||||||
/// <param name="seed">The seed number</param>
|
/// <param name="bufferSize">The buffer size</param>
|
||||||
/// <returns>hash</returns>
|
/// <param name="seed">The seed number</param>
|
||||||
public static unsafe ulong ComputeHash(string str, uint seed = 0)
|
/// <returns>The hash</returns>
|
||||||
{
|
public static async ValueTask<ulong> ComputeHashAsync(Stream stream, int bufferSize = 8192, ulong seed = 0)
|
||||||
Debug.Assert(str != null);
|
|
||||||
|
|
||||||
fixed (char* c = str)
|
|
||||||
{
|
{
|
||||||
byte* ptr = (byte*) c;
|
return await ComputeHashAsync(stream, bufferSize, seed, CancellationToken.None);
|
||||||
int length = str.Length * 2;
|
|
||||||
|
|
||||||
return UnsafeComputeHash(ptr, length, seed);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
/// <summary>
|
||||||
private static unsafe ulong UnsafeComputeHash(byte* ptr, int length, ulong seed)
|
/// Compute xxHash for the async stream
|
||||||
{
|
/// </summary>
|
||||||
// Use inlined version
|
/// <param name="stream">The stream of data</param>
|
||||||
// return XXH64(ptr, length, seed);
|
/// <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);
|
||||||
|
|
||||||
return __inline__XXH64(ptr, length, seed);
|
// 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
|
||||||
|
__inline__XXH64_stream_process(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 = __inline__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
|
||||||
|
__inline__XXH64_stream_process(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 = __inline__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 * 2;
|
||||||
|
|
||||||
|
return UnsafeComputeHash(ptr, length, seed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static unsafe ulong UnsafeComputeHash(byte* ptr, int length, ulong seed)
|
||||||
|
{
|
||||||
|
// Use inlined version
|
||||||
|
// return XXH64(ptr, length, seed);
|
||||||
|
|
||||||
|
return __inline__XXH64(ptr, length, seed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user