Add Streaming API
This commit is contained in:
parent
09f8040a80
commit
2aea731a75
11
deps.props
Normal file
11
deps.props
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<Project>
|
||||||
|
<PropertyGroup>
|
||||||
|
<SystemBuffers>4.4.0</SystemBuffers>
|
||||||
|
<SystemIO>4.3.0</SystemIO>
|
||||||
|
<BenchmarkDotNet>0.10.14</BenchmarkDotNet>
|
||||||
|
<MicrosoftSdk>15.6.0</MicrosoftSdk>
|
||||||
|
<xUnit>2.3.1</xUnit>
|
||||||
|
<xUnitRunner>2.3.1</xUnitRunner>
|
||||||
|
<xUnitTool>2.3.1</xUnitTool>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
14
nuget.props
Normal file
14
nuget.props
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<Project>
|
||||||
|
<Import Project="deps.props" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFrameworks>netstandard2.0</TargetFrameworks>
|
||||||
|
<PackageId>Standart.Hash.xxHash</PackageId>
|
||||||
|
<VersionPrefix>1.0.0</VersionPrefix>
|
||||||
|
<AssemblyName>Standart.Hash.xxHash</AssemblyName>
|
||||||
|
<AssemblyTitle>Standart.Hash.xxHash</AssemblyTitle>
|
||||||
|
<Authors>Alexander Melnik</Authors>
|
||||||
|
<PackageTags>hash;xxHash</PackageTags>
|
||||||
|
<Description>Standart.Hash.xxHash</Description>
|
||||||
|
<PackageProjectUrl>https://github.com/uranium62/xxHash</PackageProjectUrl>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
@ -1,4 +1,5 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<Import Project="..\..\deps.props" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
@ -12,7 +13,7 @@
|
|||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="BenchmarkDotNet" Version="0.10.14" />
|
<PackageReference Include="BenchmarkDotNet" Version="$(BenchmarkDotNet)" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Standart.Hash.xxHash\Standart.Hash.xxHash.csproj" />
|
<ProjectReference Include="..\Standart.Hash.xxHash\Standart.Hash.xxHash.csproj" />
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
namespace Standart.Hash.xxHash.Perf
|
namespace Standart.Hash.xxHash.Perf
|
||||||
{
|
{
|
||||||
using System;
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using BenchmarkDotNet.Attributes;
|
using BenchmarkDotNet.Attributes;
|
||||||
using BenchmarkDotNet.Attributes.Columns;
|
using BenchmarkDotNet.Attributes.Columns;
|
||||||
using BenchmarkDotNet.Attributes.Exporters;
|
using BenchmarkDotNet.Attributes.Exporters;
|
||||||
@ -16,6 +18,7 @@
|
|||||||
const int GB = 1024 * MB;
|
const int GB = 1024 * MB;
|
||||||
|
|
||||||
private byte[] data;
|
private byte[] data;
|
||||||
|
private MemoryStream stream;
|
||||||
|
|
||||||
[Params(KB, MB, GB)]
|
[Params(KB, MB, GB)]
|
||||||
public int N;
|
public int N;
|
||||||
@ -25,18 +28,43 @@
|
|||||||
{
|
{
|
||||||
data = new byte[N];
|
data = new byte[N];
|
||||||
new Random(42).NextBytes(data);
|
new Random(42).NextBytes(data);
|
||||||
|
stream = new MemoryStream(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public uint Hash32()
|
public uint Hash32()
|
||||||
{
|
{
|
||||||
return xxHash32.ComputeHash(data, data.Length);
|
return xxHash32.ComputeHash(data, data.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public uint Hash32_Stream()
|
||||||
|
{
|
||||||
|
return xxHash32.ComputeHash(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public async Task<uint> Hash32_StreamAsync()
|
||||||
|
{
|
||||||
|
return await xxHash32.ComputeHashAsync(stream);
|
||||||
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public ulong Hash64()
|
public ulong Hash64()
|
||||||
{
|
{
|
||||||
return xxHash64.ComputeHash(data, data.Length);
|
return xxHash64.ComputeHash(data, data.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public ulong Hash64_Stream()
|
||||||
|
{
|
||||||
|
return xxHash64.ComputeHash(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public async Task<ulong> Hash64_StreamAsync()
|
||||||
|
{
|
||||||
|
return await xxHash64.ComputeHashAsync(stream);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,4 +1,5 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<Import Project="..\..\deps.props" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
@ -12,10 +13,10 @@
|
|||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.6.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftSdk)" />
|
||||||
<PackageReference Include="xunit" Version="2.3.1" />
|
<PackageReference Include="xunit" Version="$(xUnit)" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
|
<PackageReference Include="xunit.runner.visualstudio" Version="$(xUnitRunner)" />
|
||||||
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
|
<DotNetCliToolReference Include="dotnet-xunit" Version="$(xUnitTool)" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Standart.Hash.xxHash\Standart.Hash.xxHash.csproj" />
|
<ProjectReference Include="..\Standart.Hash.xxHash\Standart.Hash.xxHash.csproj" />
|
||||||
|
|||||||
@ -1,12 +1,191 @@
|
|||||||
namespace Standart.Hash.xxHash.Test
|
namespace Standart.Hash.xxHash.Test
|
||||||
{
|
{
|
||||||
using System.Text;
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
public class xxHash32Test
|
public class xxHash32Test
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Compute_hash_for_the_byte_array()
|
public void Compute_hash32_for_the_length_1()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
byte[] data = {0xde};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
uint hash = xxHash32.ComputeHash(data, data.Length);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash, (uint) 0x2330eac0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Compute_hash32_for_the_length_5()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
byte[] data = {0xde, 0x55, 0x47, 0x7f, 0x14};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
uint hash = xxHash32.ComputeHash(data, data.Length);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash, (uint) 0x112348ba);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Compute_hash32_for_the_length_16()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
byte[] data = new byte[]
|
||||||
|
{
|
||||||
|
0xde, 0x55, 0x47, 0x7f, 0x14, 0x8f, 0xf1, 0x48,
|
||||||
|
0x22, 0x3a, 0x40, 0x96, 0x56, 0xc5, 0xdc, 0xbb
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
uint hash = xxHash32.ComputeHash(data, data.Length);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash, (uint) 0xcdf89609);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Compute_hash32_for_the_length_17()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
byte[] data = new byte[]
|
||||||
|
{
|
||||||
|
0xde, 0x55, 0x47, 0x7f, 0x14, 0x8f, 0xf1, 0x48,
|
||||||
|
0x22, 0x3a, 0x40, 0x96, 0x56, 0xc5, 0xdc, 0xbb,
|
||||||
|
0x0e
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
uint hash = xxHash32.ComputeHash(data, data.Length);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash, (uint) 0xbca8f924);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Compute_hash32_for_the_length_21()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
byte[] data = new byte[]
|
||||||
|
{
|
||||||
|
0xde, 0x55, 0x47, 0x7f, 0x14, 0x8f, 0xf1, 0x48,
|
||||||
|
0x22, 0x3a, 0x40, 0x96, 0x56, 0xc5, 0xdc, 0xbb,
|
||||||
|
0x0e, 0x59, 0x4d, 0x42, 0xc5
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
uint hash = xxHash32.ComputeHash(data, data.Length);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash, (uint) 0xf4518e14);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Compute_hash32_for_the_length_32()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
byte[] data = new byte[]
|
||||||
|
{
|
||||||
|
0xde, 0x55, 0x47, 0x7f, 0x14, 0x8f, 0xf1, 0x48,
|
||||||
|
0x22, 0x3a, 0x40, 0x96, 0x56, 0xc5, 0xdc, 0xbb,
|
||||||
|
0x0e, 0x59, 0x4d, 0x42, 0xc5, 0x07, 0x21, 0x08,
|
||||||
|
0x1c, 0x2c, 0xc9, 0x38, 0x7d, 0x43, 0x83, 0x11,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
uint hash = xxHash32.ComputeHash(data, data.Length);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash, (uint) 0xf8497daa);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Compute_hash32_for_the_stream_1()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
byte[] data = {0xde};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
uint hash = xxHash32.ComputeHash(new MemoryStream(data));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash, (uint) 0x2330eac0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Compute_hash32_for_the_stream_5()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
byte[] data = {0xde, 0x55, 0x47, 0x7f, 0x14};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
uint hash = xxHash32.ComputeHash(new MemoryStream(data));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash, (uint) 0x112348ba);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Compute_hash32_for_the_stream_16()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
byte[] data = new byte[]
|
||||||
|
{
|
||||||
|
0xde, 0x55, 0x47, 0x7f, 0x14, 0x8f, 0xf1, 0x48,
|
||||||
|
0x22, 0x3a, 0x40, 0x96, 0x56, 0xc5, 0xdc, 0xbb
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
uint hash = xxHash32.ComputeHash(new MemoryStream(data));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash, (uint) 0xcdf89609);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Compute_hash32_for_the_stream_17()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
byte[] data = new byte[]
|
||||||
|
{
|
||||||
|
0xde, 0x55, 0x47, 0x7f, 0x14, 0x8f, 0xf1, 0x48,
|
||||||
|
0x22, 0x3a, 0x40, 0x96, 0x56, 0xc5, 0xdc, 0xbb,
|
||||||
|
0x0e
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
uint hash = xxHash32.ComputeHash(new MemoryStream(data));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash, (uint) 0xbca8f924);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Compute_hash32_for_the_stream_21()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
byte[] data = new byte[]
|
||||||
|
{
|
||||||
|
0xde, 0x55, 0x47, 0x7f, 0x14, 0x8f, 0xf1, 0x48,
|
||||||
|
0x22, 0x3a, 0x40, 0x96, 0x56, 0xc5, 0xdc, 0xbb,
|
||||||
|
0x0e, 0x59, 0x4d, 0x42, 0xc5
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
uint hash = xxHash32.ComputeHash(new MemoryStream(data));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash, (uint) 0xf4518e14);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Compute_hash32_for_the_stream_32()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
byte[] data = new byte[]
|
byte[] data = new byte[]
|
||||||
@ -17,35 +196,169 @@
|
|||||||
0x1c, 0x2c, 0xc9, 0x38, 0x7d, 0x43, 0x83, 0x11,
|
0x1c, 0x2c, 0xc9, 0x38, 0x7d, 0x43, 0x83, 0x11,
|
||||||
};
|
};
|
||||||
|
|
||||||
uint[] actual = new uint[]
|
// Act
|
||||||
{
|
uint hash = xxHash32.ComputeHash(new MemoryStream(data));
|
||||||
0x2330eac0, 0x2c006f7e, 0xa1481114, 0x28d386f9, 0x112348ba, 0x65da8e31, 0x7555bcbd, 0x46cf19ed,
|
|
||||||
0x27802c05, 0x8d0a6fae, 0x6075daf0, 0x4c5aef64, 0x8c6b5a5e, 0x00c1810a, 0x863d91cf, 0xcdf89609,
|
|
||||||
0xbca8f924, 0xed028fb5, 0x81c19b77, 0x1a0550fa, 0xf4518e14, 0xae2eace8, 0xe7f85aa8, 0xcf8df264,
|
|
||||||
0xb4fd0c90, 0x511934b0, 0x796f989a, 0x26b664a6, 0x8c242079, 0x5842beef, 0xd1d0b350, 0xf8497daa,
|
|
||||||
};
|
|
||||||
|
|
||||||
for (int len = 1; len <= data.Length; len++)
|
// Assert
|
||||||
{
|
Assert.Equal(hash, (uint) 0xf8497daa);
|
||||||
// Act
|
|
||||||
uint hash = xxHash32.ComputeHash(data, len);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Equal(hash, actual[len - 1]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Compute_hash_for_the_string()
|
public void Compute_hash32_for_the_random_stream()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
byte[] data = Encoding.UTF8.GetBytes("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod");
|
int[] size =
|
||||||
|
{
|
||||||
|
256,
|
||||||
|
256 * 3,
|
||||||
|
256 * 3 + 1,
|
||||||
|
256 * 3 + 15,
|
||||||
|
256 * 3 + 16,
|
||||||
|
256 * 3 + 41
|
||||||
|
};
|
||||||
|
var random = new Random();
|
||||||
|
|
||||||
|
for (int i = 0; i < size.Length; i++)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var data = new byte[size[i]];
|
||||||
|
random.NextBytes(data);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
uint hash1 = xxHash32.ComputeHash(data, data.Length);
|
||||||
|
uint hash2 = xxHash32.ComputeHash(new MemoryStream(data), 32);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash1, hash2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Compute_hash32_for_the_async_stream_1()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
byte[] data = {0xde};
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
uint hash = xxHash32.ComputeHash(data, data.Length);
|
uint hash = await xxHash32.ComputeHashAsync(new MemoryStream(data));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(0xe3cd4dee, hash);
|
Assert.Equal(hash, (uint) 0x2330eac0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Compute_hash32_for_the_async_stream_5()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
byte[] data = {0xde, 0x55, 0x47, 0x7f, 0x14};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
uint hash = await xxHash32.ComputeHashAsync(new MemoryStream(data));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash, (uint) 0x112348ba);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Compute_hash32_for_the_async_stream_16()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
byte[] data = new byte[]
|
||||||
|
{
|
||||||
|
0xde, 0x55, 0x47, 0x7f, 0x14, 0x8f, 0xf1, 0x48,
|
||||||
|
0x22, 0x3a, 0x40, 0x96, 0x56, 0xc5, 0xdc, 0xbb
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
uint hash = await xxHash32.ComputeHashAsync(new MemoryStream(data));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash, (uint) 0xcdf89609);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Compute_hash32_for_the_async_stream_17()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
byte[] data = new byte[]
|
||||||
|
{
|
||||||
|
0xde, 0x55, 0x47, 0x7f, 0x14, 0x8f, 0xf1, 0x48,
|
||||||
|
0x22, 0x3a, 0x40, 0x96, 0x56, 0xc5, 0xdc, 0xbb,
|
||||||
|
0x0e
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
uint hash = await xxHash32.ComputeHashAsync(new MemoryStream(data));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash, (uint) 0xbca8f924);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Compute_hash32_for_the_async_stream_21()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
byte[] data = new byte[]
|
||||||
|
{
|
||||||
|
0xde, 0x55, 0x47, 0x7f, 0x14, 0x8f, 0xf1, 0x48,
|
||||||
|
0x22, 0x3a, 0x40, 0x96, 0x56, 0xc5, 0xdc, 0xbb,
|
||||||
|
0x0e, 0x59, 0x4d, 0x42, 0xc5
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
uint hash = await xxHash32.ComputeHashAsync(new MemoryStream(data));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash, (uint) 0xf4518e14);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Compute_hash32_for_the_async_stream_32()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
byte[] data = new byte[]
|
||||||
|
{
|
||||||
|
0xde, 0x55, 0x47, 0x7f, 0x14, 0x8f, 0xf1, 0x48,
|
||||||
|
0x22, 0x3a, 0x40, 0x96, 0x56, 0xc5, 0xdc, 0xbb,
|
||||||
|
0x0e, 0x59, 0x4d, 0x42, 0xc5, 0x07, 0x21, 0x08,
|
||||||
|
0x1c, 0x2c, 0xc9, 0x38, 0x7d, 0x43, 0x83, 0x11,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
uint hash = await xxHash32.ComputeHashAsync(new MemoryStream(data));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash, (uint) 0xf8497daa);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Compute_hash32_for_the_async_random_stream()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
int[] size =
|
||||||
|
{
|
||||||
|
256,
|
||||||
|
256 * 3,
|
||||||
|
256 * 3 + 1,
|
||||||
|
256 * 3 + 15,
|
||||||
|
256 * 3 + 16,
|
||||||
|
256 * 3 + 41
|
||||||
|
};
|
||||||
|
var random = new Random();
|
||||||
|
|
||||||
|
for (int i = 0; i < size.Length; i++)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var data = new byte[size[i]];
|
||||||
|
random.NextBytes(data);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
uint hash1 = xxHash32.ComputeHash(data, data.Length);
|
||||||
|
uint hash2 = await xxHash32.ComputeHashAsync(new MemoryStream(data), 32);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash1, hash2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,16 +1,79 @@
|
|||||||
namespace Standart.Hash.xxHash.Test
|
namespace Standart.Hash.xxHash.Test
|
||||||
{
|
{
|
||||||
using System.Text;
|
using System;
|
||||||
using Hash;
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
public class xxHash64Test
|
public class xxHash64Test
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Compute_hash_for_the_byte_array()
|
public void Compute_hash64_for_the_length_1()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
byte[] data = new byte[]
|
byte[] data = {0x60};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
ulong hash = xxHash64.ComputeHash(data, data.Length);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash, (ulong) 0xb3e7ca6ca5ba3445);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Compute_hash64_for_the_length_5()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
byte[] data = {0x60, 0x82, 0x40, 0x77, 0x8a};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
ulong hash = xxHash64.ComputeHash(data, data.Length);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash, (ulong) 0x917b11ed024938fc);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Compute_hash64_for_the_length_13()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
byte[] data =
|
||||||
|
{
|
||||||
|
0x60, 0x82, 0x40, 0x77, 0x8a, 0x0e, 0xe4, 0xd5,
|
||||||
|
0x85, 0x1f, 0xa6, 0x86, 0x34,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
ulong hash = xxHash64.ComputeHash(data, data.Length);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash, (ulong) 0x9d1cb0d181d58bee);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Compute_hash64_for_the_length_32()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
byte[] data =
|
||||||
|
{
|
||||||
|
0x60, 0x82, 0x40, 0x77, 0x8a, 0x0e, 0xe4, 0xd5,
|
||||||
|
0x85, 0x1f, 0xa6, 0x86, 0x34, 0x01, 0xd7, 0xf2,
|
||||||
|
0x30, 0x5d, 0x84, 0x54, 0x15, 0xf9, 0xbd, 0x03,
|
||||||
|
0x4b, 0x0f, 0x90, 0x4e, 0xf5, 0x57, 0x21, 0x21,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
ulong hash = xxHash64.ComputeHash(data, data.Length);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash, (ulong) 0x9233096b7804e12c);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Compute_hash64_for_the_length_64()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
byte[] data =
|
||||||
{
|
{
|
||||||
0x60, 0x82, 0x40, 0x77, 0x8a, 0x0e, 0xe4, 0xd5,
|
0x60, 0x82, 0x40, 0x77, 0x8a, 0x0e, 0xe4, 0xd5,
|
||||||
0x85, 0x1f, 0xa6, 0x86, 0x34, 0x01, 0xd7, 0xf2,
|
0x85, 0x1f, 0xa6, 0x86, 0x34, 0x01, 0xd7, 0xf2,
|
||||||
@ -21,40 +84,245 @@
|
|||||||
0x27, 0x6d, 0xb3, 0x5c, 0xc7, 0xc0, 0xd0, 0xa0,
|
0x27, 0x6d, 0xb3, 0x5c, 0xc7, 0xc0, 0xd0, 0xa0,
|
||||||
0x7e, 0x28, 0xce, 0x46, 0x85, 0xb7, 0x2b, 0x16,
|
0x7e, 0x28, 0xce, 0x46, 0x85, 0xb7, 0x2b, 0x16,
|
||||||
};
|
};
|
||||||
|
|
||||||
ulong[] actual = new ulong[]
|
|
||||||
{
|
|
||||||
0xb3e7ca6ca5ba3445, 0xc48d23e7117c5c9f, 0xbdde5e6c403b877f, 0xb1f2d0131359c662, 0x917b11ed024938fc, 0xf1f919ac6d7f76e4, 0xea769e99c9c9bbd8, 0x703ba74928ca5564,
|
|
||||||
0xe7c3e0490a3b1d95, 0x3029ac2ba355e675, 0x4c0457cbdeef0b12, 0xe62ef3a1d378c12e, 0x9d1cb0d181d58bee, 0x9a5fb7dcdf81ce31, 0x4b34ada6b021b0f0, 0x06a48a5ee2da8aa0,
|
|
||||||
0xc2c6ca165cef49be, 0xd65d8cf3e8303c45, 0x9c4fe072aa5ba2c3, 0x6fdcaa87f4c0027d, 0xdf36b78f6ed0d0c4, 0x4c2de293bd035f97, 0x80e9997ecb4b4dba, 0xedc569773e3c1aae,
|
|
||||||
0xce488e21bb53a4e2, 0x9eba278ca7d6167f, 0xafc41ab957fc123c, 0x221bc4f34b8afc02, 0x89448861c1506213, 0x1e790a0825d2edd5, 0xbac80f4da00a5ddb, 0x9233096b7804e12c,
|
|
||||||
0xa596aeb3e9e2a0fb, 0xe5e8a197b29353c0, 0x75adcf4cf52af71f, 0x98e480d02a353d0b, 0xba1959292dce8087, 0x244320e6b95005cf, 0xc7a8f723dedfcb7f, 0x5557772a50b43c1a,
|
|
||||||
0xdfe1c66f17b8caad, 0xcce29f0e017c531c, 0xc7582d7753b82d55, 0xfd7a0f9119288736, 0xd9d70c5d5d544166, 0x1e45f4055ed9dd64, 0xbdc0b3dedd7f9ba6, 0xfef1d3bf774540d4,
|
|
||||||
0xa9c399777e64b4fa, 0xa6a3a1e8bcfa2b2d, 0xb3e8ee1513ebb5cf, 0x1705345d27cd571e, 0x101c3fe5b4cbbc77, 0xc0990c64b0b3b7ab, 0x9e0a9991f51b4ff5, 0xd24f884f6c74e067,
|
|
||||||
0x5ae156ca6a9202c9, 0x60786b148def4de5, 0x36648dcc3f16c761, 0x3b5d877329197688, 0x22cb98d859720834, 0x77c5f375685b7942, 0x7a9f2086cdc70d02, 0x4c0a65b1ef9ea060,
|
|
||||||
};
|
|
||||||
|
|
||||||
for (int len = 1; len <= data.Length; len++)
|
|
||||||
{
|
|
||||||
// Act
|
|
||||||
ulong hash = xxHash64.ComputeHash(data, len);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Equal(hash, actual[len-1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Compute_hash_for_the_string()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
byte[] data = Encoding.UTF8.GetBytes("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod");
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
ulong hash = xxHash64.ComputeHash(data, data.Length);
|
ulong hash = xxHash64.ComputeHash(data, data.Length);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal((ulong) 0x5dee64ff7c935d7f, hash);
|
Assert.Equal(hash, (ulong) 0x4c0a65b1ef9ea060);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Compute_hash64_for_the_stream_1()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
byte[] data = {0x60};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
ulong hash = xxHash64.ComputeHash(new MemoryStream(data));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash, (ulong) 0xb3e7ca6ca5ba3445);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Compute_hash64_for_the_stream_5()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
byte[] data = {0x60, 0x82, 0x40, 0x77, 0x8a};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
ulong hash = xxHash64.ComputeHash(new MemoryStream(data));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash, (ulong) 0x917b11ed024938fc);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Compute_hash64_for_the_stream_13()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
byte[] data =
|
||||||
|
{
|
||||||
|
0x60, 0x82, 0x40, 0x77, 0x8a, 0x0e, 0xe4, 0xd5,
|
||||||
|
0x85, 0x1f, 0xa6, 0x86, 0x34,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
ulong hash = xxHash64.ComputeHash(new MemoryStream(data));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash, (ulong) 0x9d1cb0d181d58bee);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Compute_hash64_for_the_stream_32()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
byte[] data =
|
||||||
|
{
|
||||||
|
0x60, 0x82, 0x40, 0x77, 0x8a, 0x0e, 0xe4, 0xd5,
|
||||||
|
0x85, 0x1f, 0xa6, 0x86, 0x34, 0x01, 0xd7, 0xf2,
|
||||||
|
0x30, 0x5d, 0x84, 0x54, 0x15, 0xf9, 0xbd, 0x03,
|
||||||
|
0x4b, 0x0f, 0x90, 0x4e, 0xf5, 0x57, 0x21, 0x21,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
ulong hash = xxHash64.ComputeHash(new MemoryStream(data));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash, (ulong) 0x9233096b7804e12c);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Compute_hash64_for_the_stream_64()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
byte[] data =
|
||||||
|
{
|
||||||
|
0x60, 0x82, 0x40, 0x77, 0x8a, 0x0e, 0xe4, 0xd5,
|
||||||
|
0x85, 0x1f, 0xa6, 0x86, 0x34, 0x01, 0xd7, 0xf2,
|
||||||
|
0x30, 0x5d, 0x84, 0x54, 0x15, 0xf9, 0xbd, 0x03,
|
||||||
|
0x4b, 0x0f, 0x90, 0x4e, 0xf5, 0x57, 0x21, 0x21,
|
||||||
|
0xed, 0x8c, 0x19, 0x93, 0xbd, 0x01, 0x12, 0x0c,
|
||||||
|
0x20, 0xb0, 0x33, 0x98, 0x4b, 0xe7, 0xc1, 0x0a,
|
||||||
|
0x27, 0x6d, 0xb3, 0x5c, 0xc7, 0xc0, 0xd0, 0xa0,
|
||||||
|
0x7e, 0x28, 0xce, 0x46, 0x85, 0xb7, 0x2b, 0x16,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
ulong hash = xxHash64.ComputeHash(new MemoryStream(data));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash, (ulong) 0x4c0a65b1ef9ea060);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Compute_hash64_for_the_random_stream()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
int[] size =
|
||||||
|
{
|
||||||
|
1024,
|
||||||
|
1024 * 3,
|
||||||
|
1024 * 3 + 1,
|
||||||
|
1024 * 3 + 5,
|
||||||
|
1024 * 3 + 13,
|
||||||
|
1024 * 3 + 32,
|
||||||
|
1024 * 3 + 41
|
||||||
|
};
|
||||||
|
var random = new Random();
|
||||||
|
|
||||||
|
for (int i = 0; i < size.Length; i++)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var data = new byte[size[i]];
|
||||||
|
random.NextBytes(data);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
ulong hash1 = xxHash64.ComputeHash(data, data.Length);
|
||||||
|
ulong hash2 = xxHash64.ComputeHash(new MemoryStream(data), 64);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash1, hash2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Compute_hash64_for_the_async_stream_1()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
byte[] data = {0x60};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
ulong hash = await xxHash64.ComputeHashAsync(new MemoryStream(data));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash, (ulong) 0xb3e7ca6ca5ba3445);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Compute_hash64_for_the_async_stream_5()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
byte[] data = {0x60, 0x82, 0x40, 0x77, 0x8a};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
ulong hash = await xxHash64.ComputeHashAsync(new MemoryStream(data));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash, (ulong) 0x917b11ed024938fc);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Compute_hash64_for_the_async_stream_13()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
byte[] data =
|
||||||
|
{
|
||||||
|
0x60, 0x82, 0x40, 0x77, 0x8a, 0x0e, 0xe4, 0xd5,
|
||||||
|
0x85, 0x1f, 0xa6, 0x86, 0x34,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
ulong hash = await xxHash64.ComputeHashAsync(new MemoryStream(data));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash, (ulong) 0x9d1cb0d181d58bee);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Compute_hash64_for_the_async_stream_32()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
byte[] data =
|
||||||
|
{
|
||||||
|
0x60, 0x82, 0x40, 0x77, 0x8a, 0x0e, 0xe4, 0xd5,
|
||||||
|
0x85, 0x1f, 0xa6, 0x86, 0x34, 0x01, 0xd7, 0xf2,
|
||||||
|
0x30, 0x5d, 0x84, 0x54, 0x15, 0xf9, 0xbd, 0x03,
|
||||||
|
0x4b, 0x0f, 0x90, 0x4e, 0xf5, 0x57, 0x21, 0x21,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
ulong hash = await xxHash64.ComputeHashAsync(new MemoryStream(data));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash, (ulong) 0x9233096b7804e12c);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Compute_hash64_for_the_async_stream_64()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
byte[] data =
|
||||||
|
{
|
||||||
|
0x60, 0x82, 0x40, 0x77, 0x8a, 0x0e, 0xe4, 0xd5,
|
||||||
|
0x85, 0x1f, 0xa6, 0x86, 0x34, 0x01, 0xd7, 0xf2,
|
||||||
|
0x30, 0x5d, 0x84, 0x54, 0x15, 0xf9, 0xbd, 0x03,
|
||||||
|
0x4b, 0x0f, 0x90, 0x4e, 0xf5, 0x57, 0x21, 0x21,
|
||||||
|
0xed, 0x8c, 0x19, 0x93, 0xbd, 0x01, 0x12, 0x0c,
|
||||||
|
0x20, 0xb0, 0x33, 0x98, 0x4b, 0xe7, 0xc1, 0x0a,
|
||||||
|
0x27, 0x6d, 0xb3, 0x5c, 0xc7, 0xc0, 0xd0, 0xa0,
|
||||||
|
0x7e, 0x28, 0xce, 0x46, 0x85, 0xb7, 0x2b, 0x16,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
ulong hash = await xxHash64.ComputeHashAsync(new MemoryStream(data));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash, (ulong) 0x4c0a65b1ef9ea060);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Compute_hash64_for_the_async_random_stream()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
int[] size =
|
||||||
|
{
|
||||||
|
//1024,
|
||||||
|
1024 * 3,
|
||||||
|
1024 * 3 + 1,
|
||||||
|
1024 * 3 + 5,
|
||||||
|
1024 * 3 + 13,
|
||||||
|
1024 * 3 + 32,
|
||||||
|
1024 * 3 + 41
|
||||||
|
};
|
||||||
|
var random = new Random();
|
||||||
|
|
||||||
|
for (int i = 0; i < size.Length; i++)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var data = new byte[size[i]];
|
||||||
|
random.NextBytes(data);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
ulong hash1 = xxHash64.ComputeHash(data, data.Length);
|
||||||
|
ulong hash2 = await xxHash64.ComputeHashAsync(new MemoryStream(data), 64);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(hash1, hash2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,15 +1,5 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<Import Project="..\..\nuget.props" />
|
||||||
<TargetFrameworks>net45;netstandard2.0</TargetFrameworks>
|
|
||||||
<PackageId>Standart.Hash.xxHash</PackageId>
|
|
||||||
<VersionPrefix>1.0.0</VersionPrefix>
|
|
||||||
<AssemblyName>Standart.Hash.xxHash</AssemblyName>
|
|
||||||
<AssemblyTitle>Standart.Hash.xxHash</AssemblyTitle>
|
|
||||||
<Authors>Alexander Melnik</Authors>
|
|
||||||
<PackageTags>hash;xxHash</PackageTags>
|
|
||||||
<Description>Standart.Hash.xxHash</Description>
|
|
||||||
<PackageProjectUrl>https://github.com/uranium62/xxHash</PackageProjectUrl>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
<Optimize>true</Optimize>
|
<Optimize>true</Optimize>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
@ -20,4 +10,8 @@
|
|||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="System.Buffers" Version="$(SystemBuffers)" />
|
||||||
|
<PackageReference Include="System.IO" Version="$(SystemIO)" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
344
src/Standart.Hash.xxHash/xxHash32.Stream.cs
Normal file
344
src/Standart.Hash.xxHash/xxHash32.Stream.cs
Normal file
@ -0,0 +1,344 @@
|
|||||||
|
namespace Standart.Hash.xxHash
|
||||||
|
{
|
||||||
|
using System.Buffers;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
public static partial class xxHash32
|
||||||
|
{
|
||||||
|
private const int min32 = 256;
|
||||||
|
private const int div16 = 0x7FFFFFF0;
|
||||||
|
|
||||||
|
/// <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)
|
||||||
|
{
|
||||||
|
// Go to the beginning of the stream
|
||||||
|
stream.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
// Get length of the stream
|
||||||
|
long length = stream.Length;
|
||||||
|
|
||||||
|
// The buffer size can't be less than 256 bytes
|
||||||
|
if (bufferSize < min32) bufferSize = min32;
|
||||||
|
else bufferSize &= div16;
|
||||||
|
|
||||||
|
// Calculate the number of chunks and the remain
|
||||||
|
int chunks = (int) length / bufferSize;
|
||||||
|
int remain = (int) length % bufferSize;
|
||||||
|
int offset = bufferSize;
|
||||||
|
|
||||||
|
// Calculate the offset
|
||||||
|
if (remain != 0) chunks++;
|
||||||
|
if (remain != 0 && remain < 16) offset -= 16;
|
||||||
|
|
||||||
|
// Optimizing memory allocation
|
||||||
|
byte[] buffer = ArrayPool<byte>.Shared.Rent(bufferSize);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Prepare the seed vector
|
||||||
|
uint v1 = seed + p1 + p2;
|
||||||
|
uint v2 = seed + p2;
|
||||||
|
uint v3 = seed + 0;
|
||||||
|
uint v4 = seed - p1;
|
||||||
|
|
||||||
|
// Process chunks
|
||||||
|
// Skip the last chunk. It will processed a little bit later
|
||||||
|
for (int i = 2; i <= chunks; i++)
|
||||||
|
{
|
||||||
|
// Change bufferSize for the last read
|
||||||
|
if (i == chunks) bufferSize = offset;
|
||||||
|
|
||||||
|
// Read the next chunk
|
||||||
|
stream.Read(buffer, 0, bufferSize);
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
fixed (byte* pData = &buffer[0])
|
||||||
|
{
|
||||||
|
byte* ptr = pData;
|
||||||
|
byte* end = pData + bufferSize;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
v1 += *((uint*)ptr) * p2;
|
||||||
|
v1 = (v1 << 13) | (v1 >> (32 - 13)); // rotl 13
|
||||||
|
v1 *= p1;
|
||||||
|
ptr += 4;
|
||||||
|
|
||||||
|
v2 += *((uint*)ptr) * p2;
|
||||||
|
v2 = (v2 << 13) | (v2 >> (32 - 13)); // rotl 13
|
||||||
|
v2 *= p1;
|
||||||
|
ptr += 4;
|
||||||
|
|
||||||
|
v3 += *((uint*)ptr) * p2;
|
||||||
|
v3 = (v3 << 13) | (v3 >> (32 - 13)); // rotl 13
|
||||||
|
v3 *= p1;
|
||||||
|
ptr += 4;
|
||||||
|
|
||||||
|
v4 += *((uint*)ptr) * p2;
|
||||||
|
v4 = (v4 << 13) | (v4 >> (32 - 13)); // rotl 13
|
||||||
|
v4 *= p1;
|
||||||
|
ptr += 4;
|
||||||
|
|
||||||
|
} while (ptr < end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the last chunk
|
||||||
|
offset = stream.Read(buffer, 0, bufferSize);
|
||||||
|
|
||||||
|
// Process the last chunk
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
fixed (byte* pData = &buffer[0])
|
||||||
|
{
|
||||||
|
byte* ptr = pData;
|
||||||
|
byte* end = pData + offset;
|
||||||
|
uint h32;
|
||||||
|
|
||||||
|
if (length >= 16)
|
||||||
|
{
|
||||||
|
byte* limit = end - 16;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
v1 += *((uint*) ptr) * p2;
|
||||||
|
v1 = (v1 << 13) | (v1 >> (32 - 13)); // rotl 13
|
||||||
|
v1 *= p1;
|
||||||
|
ptr += 4;
|
||||||
|
|
||||||
|
v2 += *((uint*) ptr) * p2;
|
||||||
|
v2 = (v2 << 13) | (v2 >> (32 - 13)); // rotl 13
|
||||||
|
v2 *= p1;
|
||||||
|
ptr += 4;
|
||||||
|
|
||||||
|
v3 += *((uint*) ptr) * p2;
|
||||||
|
v3 = (v3 << 13) | (v3 >> (32 - 13)); // rotl 13
|
||||||
|
v3 *= p1;
|
||||||
|
ptr += 4;
|
||||||
|
|
||||||
|
v4 += *((uint*) ptr) * p2;
|
||||||
|
v4 = (v4 << 13) | (v4 >> (32 - 13)); // rotl 13
|
||||||
|
v4 *= p1;
|
||||||
|
ptr += 4;
|
||||||
|
|
||||||
|
} while (ptr <= limit);
|
||||||
|
|
||||||
|
h32 = ((v1 << 1) | (v1 >> (32 - 1))) + // rotl 1
|
||||||
|
((v2 << 7) | (v2 >> (32 - 7))) + // rotl 7
|
||||||
|
((v3 << 12) | (v3 >> (32 - 12))) + // rotl 12
|
||||||
|
((v4 << 18) | (v4 >> (32 - 18))); // rotl 18
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
h32 = seed + p5;
|
||||||
|
}
|
||||||
|
|
||||||
|
h32 += (uint) length;
|
||||||
|
|
||||||
|
while (ptr <= end - 4)
|
||||||
|
{
|
||||||
|
h32 += *((uint*) ptr) * p3;
|
||||||
|
h32 = ((h32 << 17) | (h32 >> (32 - 17))) * p4; // (rotl 17) * p4
|
||||||
|
ptr += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (ptr < end)
|
||||||
|
{
|
||||||
|
h32 += *((byte*) ptr) * p5;
|
||||||
|
h32 = ((h32 << 11) | (h32 >> (32 - 11))) * p1; // (rotl 11) * p1
|
||||||
|
ptr += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
h32 ^= h32 >> 15;
|
||||||
|
h32 *= p2;
|
||||||
|
h32 ^= h32 >> 13;
|
||||||
|
h32 *= p3;
|
||||||
|
h32 ^= h32 >> 16;
|
||||||
|
|
||||||
|
return h32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// Free memory
|
||||||
|
ArrayPool<byte>.Shared.Return(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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 Task<uint> ComputeHashAsync(Stream stream, int bufferSize = 4096, uint seed = 0)
|
||||||
|
{
|
||||||
|
// Go to the beginning of the stream
|
||||||
|
stream.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
// Get length of the stream
|
||||||
|
long length = stream.Length;
|
||||||
|
|
||||||
|
// The buffer size can't be less than 256 bytes
|
||||||
|
if (bufferSize < min32) bufferSize = min32;
|
||||||
|
else bufferSize &= div16;
|
||||||
|
|
||||||
|
// Calculate the number of chunks and the remain
|
||||||
|
int chunks = (int) length / bufferSize;
|
||||||
|
int remain = (int) length % bufferSize;
|
||||||
|
int offset = bufferSize;
|
||||||
|
|
||||||
|
// Calculate the offset
|
||||||
|
if (remain != 0) chunks++;
|
||||||
|
if (remain != 0 && remain < 16) offset -= 16;
|
||||||
|
|
||||||
|
// Optimizing memory allocation
|
||||||
|
byte[] buffer = ArrayPool<byte>.Shared.Rent(bufferSize);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Prepare the seed vector
|
||||||
|
uint v1 = seed + p1 + p2;
|
||||||
|
uint v2 = seed + p2;
|
||||||
|
uint v3 = seed + 0;
|
||||||
|
uint v4 = seed - p1;
|
||||||
|
|
||||||
|
// Process chunks
|
||||||
|
// Skip the last chunk. It will processed a little bit later
|
||||||
|
for (int i = 2; i <= chunks; i++)
|
||||||
|
{
|
||||||
|
// Change bufferSize for the last read
|
||||||
|
if (i == chunks) bufferSize = offset;
|
||||||
|
|
||||||
|
// Read the next chunk
|
||||||
|
await stream.ReadAsync(buffer, 0, bufferSize).ConfigureAwait(false);;
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
fixed (byte* pData = &buffer[0])
|
||||||
|
{
|
||||||
|
byte* ptr = pData;
|
||||||
|
byte* end = pData + bufferSize;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
v1 += *((uint*)ptr) * p2;
|
||||||
|
v1 = (v1 << 13) | (v1 >> (32 - 13)); // rotl 13
|
||||||
|
v1 *= p1;
|
||||||
|
ptr += 4;
|
||||||
|
|
||||||
|
v2 += *((uint*)ptr) * p2;
|
||||||
|
v2 = (v2 << 13) | (v2 >> (32 - 13)); // rotl 13
|
||||||
|
v2 *= p1;
|
||||||
|
ptr += 4;
|
||||||
|
|
||||||
|
v3 += *((uint*)ptr) * p2;
|
||||||
|
v3 = (v3 << 13) | (v3 >> (32 - 13)); // rotl 13
|
||||||
|
v3 *= p1;
|
||||||
|
ptr += 4;
|
||||||
|
|
||||||
|
v4 += *((uint*)ptr) * p2;
|
||||||
|
v4 = (v4 << 13) | (v4 >> (32 - 13)); // rotl 13
|
||||||
|
v4 *= p1;
|
||||||
|
ptr += 4;
|
||||||
|
|
||||||
|
} while (ptr < end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the last chunk
|
||||||
|
offset = await stream.ReadAsync(buffer, 0, bufferSize).ConfigureAwait(false);
|
||||||
|
|
||||||
|
// Process the last chunk
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
fixed (byte* pData = &buffer[0])
|
||||||
|
{
|
||||||
|
byte* ptr = pData;
|
||||||
|
byte* end = pData + offset;
|
||||||
|
uint h32;
|
||||||
|
|
||||||
|
if (length >= 16)
|
||||||
|
{
|
||||||
|
byte* limit = end - 16;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
v1 += *((uint*) ptr) * p2;
|
||||||
|
v1 = (v1 << 13) | (v1 >> (32 - 13)); // rotl 13
|
||||||
|
v1 *= p1;
|
||||||
|
ptr += 4;
|
||||||
|
|
||||||
|
v2 += *((uint*) ptr) * p2;
|
||||||
|
v2 = (v2 << 13) | (v2 >> (32 - 13)); // rotl 13
|
||||||
|
v2 *= p1;
|
||||||
|
ptr += 4;
|
||||||
|
|
||||||
|
v3 += *((uint*) ptr) * p2;
|
||||||
|
v3 = (v3 << 13) | (v3 >> (32 - 13)); // rotl 13
|
||||||
|
v3 *= p1;
|
||||||
|
ptr += 4;
|
||||||
|
|
||||||
|
v4 += *((uint*) ptr) * p2;
|
||||||
|
v4 = (v4 << 13) | (v4 >> (32 - 13)); // rotl 13
|
||||||
|
v4 *= p1;
|
||||||
|
ptr += 4;
|
||||||
|
|
||||||
|
} while (ptr <= limit);
|
||||||
|
|
||||||
|
h32 = ((v1 << 1) | (v1 >> (32 - 1))) + // rotl 1
|
||||||
|
((v2 << 7) | (v2 >> (32 - 7))) + // rotl 7
|
||||||
|
((v3 << 12) | (v3 >> (32 - 12))) + // rotl 12
|
||||||
|
((v4 << 18) | (v4 >> (32 - 18))); // rotl 18
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
h32 = seed + p5;
|
||||||
|
}
|
||||||
|
|
||||||
|
h32 += (uint) length;
|
||||||
|
|
||||||
|
while (ptr <= end - 4)
|
||||||
|
{
|
||||||
|
h32 += *((uint*) ptr) * p3;
|
||||||
|
h32 = ((h32 << 17) | (h32 >> (32 - 17))) * p4; // (rotl 17) * p4
|
||||||
|
ptr += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (ptr < end)
|
||||||
|
{
|
||||||
|
h32 += *((byte*) ptr) * p5;
|
||||||
|
h32 = ((h32 << 11) | (h32 >> (32 - 11))) * p1; // (rotl 11) * p1
|
||||||
|
ptr += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
h32 ^= h32 >> 15;
|
||||||
|
h32 *= p2;
|
||||||
|
h32 ^= h32 >> 13;
|
||||||
|
h32 *= p3;
|
||||||
|
h32 ^= h32 >> 16;
|
||||||
|
|
||||||
|
return h32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// Free memory
|
||||||
|
ArrayPool<byte>.Shared.Return(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
namespace Standart.Hash.xxHash
|
namespace Standart.Hash.xxHash
|
||||||
{
|
{
|
||||||
public static class xxHash32
|
public static partial class xxHash32
|
||||||
{
|
{
|
||||||
private const uint p1 = 2654435761U;
|
private const uint p1 = 2654435761U;
|
||||||
private const uint p2 = 2246822519U;
|
private const uint p2 = 2246822519U;
|
||||||
@ -12,18 +12,18 @@
|
|||||||
/// Compute xxHash for the data byte array
|
/// Compute xxHash for the data byte array
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="data">The source of data</param>
|
/// <param name="data">The source of data</param>
|
||||||
/// <param name="len">The length of the data for hashing</param>
|
/// <param name="length">The length of the data for hashing</param>
|
||||||
/// <param name="seed">The seed number</param>
|
/// <param name="seed">The seed number</param>
|
||||||
/// <returns>hash</returns>
|
/// <returns>hash</returns>
|
||||||
public static unsafe uint ComputeHash(byte[] data, int len, uint seed = 0)
|
public static unsafe uint ComputeHash(byte[] data, int length, uint seed = 0)
|
||||||
{
|
{
|
||||||
fixed (byte* pData = &data[0])
|
fixed (byte* pData = &data[0])
|
||||||
{
|
{
|
||||||
byte* ptr = pData;
|
byte* ptr = pData;
|
||||||
byte* end = pData + len;
|
byte* end = pData + length;
|
||||||
uint h32;
|
uint h32;
|
||||||
|
|
||||||
if (len >= 16)
|
if (length >= 16)
|
||||||
{
|
{
|
||||||
byte* limit = end - 16;
|
byte* limit = end - 16;
|
||||||
|
|
||||||
@ -66,7 +66,7 @@
|
|||||||
h32 = seed + p5;
|
h32 = seed + p5;
|
||||||
}
|
}
|
||||||
|
|
||||||
h32 += (uint) len;
|
h32 += (uint) length;
|
||||||
|
|
||||||
// finalize
|
// finalize
|
||||||
while (ptr <= end - 4)
|
while (ptr <= end - 4)
|
||||||
|
|||||||
424
src/Standart.Hash.xxHash/xxHash64.Stream.cs
Normal file
424
src/Standart.Hash.xxHash/xxHash64.Stream.cs
Normal file
@ -0,0 +1,424 @@
|
|||||||
|
namespace Standart.Hash.xxHash
|
||||||
|
{
|
||||||
|
using System.Buffers;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
public static partial class xxHash64
|
||||||
|
{
|
||||||
|
private const int min64 = 1024;
|
||||||
|
private const int div32 = 0x7FFFFFE0;
|
||||||
|
|
||||||
|
/// <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)
|
||||||
|
{
|
||||||
|
// Go to the beginning of the stream
|
||||||
|
stream.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
// Get length of the stream
|
||||||
|
long length = stream.Length;
|
||||||
|
|
||||||
|
// The buffer can't be less than 1024 bytes
|
||||||
|
if (bufferSize < min64) bufferSize = min64;
|
||||||
|
else bufferSize &= div32;
|
||||||
|
|
||||||
|
// Calculate the number of chunks and the remain
|
||||||
|
int chunks = (int) length / bufferSize;
|
||||||
|
int remain = (int) length % bufferSize;
|
||||||
|
int offset = bufferSize;
|
||||||
|
|
||||||
|
// Calculate the offset
|
||||||
|
if (remain != 0) chunks++;
|
||||||
|
if (remain != 0 && remain < 32) offset -= 32;
|
||||||
|
|
||||||
|
// Optimizing memory allocation
|
||||||
|
byte[] buffer = ArrayPool<byte>.Shared.Rent(bufferSize);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Prepare the seed vector
|
||||||
|
ulong v1 = seed + p1 + p2;
|
||||||
|
ulong v2 = seed + p2;
|
||||||
|
ulong v3 = seed + 0;
|
||||||
|
ulong v4 = seed - p1;
|
||||||
|
|
||||||
|
// Process chunks
|
||||||
|
// Skip the last chunk. It will processed a little bit later
|
||||||
|
for (int i = 2; i <= chunks; i++)
|
||||||
|
{
|
||||||
|
// Change bufferSize for the last read
|
||||||
|
if (i == chunks) bufferSize = offset;
|
||||||
|
|
||||||
|
// Read the next chunk
|
||||||
|
stream.Read(buffer, 0, bufferSize);
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
fixed (byte* pData = &buffer[0])
|
||||||
|
{
|
||||||
|
byte* ptr = pData;
|
||||||
|
byte* end = pData + bufferSize;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
v1 += *((ulong*) ptr) * p2;
|
||||||
|
v1 = (v1 << 31) | (v1 >> (64 - 31)); // rotl 31
|
||||||
|
v1 *= p1;
|
||||||
|
ptr += 8;
|
||||||
|
|
||||||
|
v2 += *((ulong*) ptr) * p2;
|
||||||
|
v2 = (v2 << 31) | (v2 >> (64 - 31)); // rotl 31
|
||||||
|
v2 *= p1;
|
||||||
|
ptr += 8;
|
||||||
|
|
||||||
|
v3 += *((ulong*) ptr) * p2;
|
||||||
|
v3 = (v3 << 31) | (v3 >> (64 - 31)); // rotl 31
|
||||||
|
v3 *= p1;
|
||||||
|
ptr += 8;
|
||||||
|
|
||||||
|
v4 += *((ulong*) ptr) * p2;
|
||||||
|
v4 = (v4 << 31) | (v4 >> (64 - 31)); // rotl 31
|
||||||
|
v4 *= p1;
|
||||||
|
ptr += 8;
|
||||||
|
|
||||||
|
} while (ptr < end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the last chunk
|
||||||
|
offset = stream.Read(buffer, 0, bufferSize);
|
||||||
|
|
||||||
|
// Process the last chunk
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
fixed (byte* pData = &buffer[0])
|
||||||
|
{
|
||||||
|
byte* ptr = pData;
|
||||||
|
byte* end = pData + offset;
|
||||||
|
ulong h64;
|
||||||
|
|
||||||
|
if (length >= 32)
|
||||||
|
{
|
||||||
|
byte* limit = end - 32;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
v1 += *((ulong*)ptr) * p2;
|
||||||
|
v1 = (v1 << 31) | (v1 >> (64 - 31)); // rotl 31
|
||||||
|
v1 *= p1;
|
||||||
|
ptr += 8;
|
||||||
|
|
||||||
|
v2 += *((ulong*)ptr) * p2;
|
||||||
|
v2 = (v2 << 31) | (v2 >> (64 - 31)); // rotl 31
|
||||||
|
v2 *= p1;
|
||||||
|
ptr += 8;
|
||||||
|
|
||||||
|
v3 += *((ulong*)ptr) * p2;
|
||||||
|
v3 = (v3 << 31) | (v3 >> (64 - 31)); // rotl 31
|
||||||
|
v3 *= p1;
|
||||||
|
ptr += 8;
|
||||||
|
|
||||||
|
v4 += *((ulong*)ptr) * p2;
|
||||||
|
v4 = (v4 << 31) | (v4 >> (64 - 31)); // rotl 31
|
||||||
|
v4 *= p1;
|
||||||
|
ptr += 8;
|
||||||
|
|
||||||
|
} while (ptr <= limit);
|
||||||
|
|
||||||
|
h64 = ((v1 << 1) | (v1 >> (64 - 1))) + // rotl 1
|
||||||
|
((v2 << 7) | (v2 >> (64 - 7))) + // rotl 7
|
||||||
|
((v3 << 12) | (v3 >> (64 - 12))) + // rotl 12
|
||||||
|
((v4 << 18) | (v4 >> (64 - 18))); // rotl 18
|
||||||
|
|
||||||
|
// merge round
|
||||||
|
v1 *= p2;
|
||||||
|
v1 = (v1 << 31) | (v1 >> (64 - 31)); // rotl 31
|
||||||
|
v1 *= p1;
|
||||||
|
h64 ^= v1;
|
||||||
|
h64 = h64 * p1 + p4;
|
||||||
|
|
||||||
|
// merge round
|
||||||
|
v2 *= p2;
|
||||||
|
v2 = (v2 << 31) | (v2 >> (64 - 31)); // rotl 31
|
||||||
|
v2 *= p1;
|
||||||
|
h64 ^= v2;
|
||||||
|
h64 = h64 * p1 + p4;
|
||||||
|
|
||||||
|
// merge round
|
||||||
|
v3 *= p2;
|
||||||
|
v3 = (v3 << 31) | (v3 >> (64 - 31)); // rotl 31
|
||||||
|
v3 *= p1;
|
||||||
|
h64 ^= v3;
|
||||||
|
h64 = h64 * p1 + p4;
|
||||||
|
|
||||||
|
// merge round
|
||||||
|
v4 *= p2;
|
||||||
|
v4 = (v4 << 31) | (v4 >> (64 - 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 = (t1 << 31) | (t1 >> (64 - 31)); // rotl 31
|
||||||
|
t1 *= p1;
|
||||||
|
h64 ^= t1;
|
||||||
|
h64 = ((h64 << 27) | (h64 >> (64 - 27))) * p1 + p4; // (rotl 27) * p1 + p4
|
||||||
|
ptr += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ptr <= end - 4)
|
||||||
|
{
|
||||||
|
h64 ^= *((uint*)ptr) * p1;
|
||||||
|
h64 = ((h64 << 23) | (h64 >> (64 - 23))) * p2 + p3; // (rotl 27) * p2 + p3
|
||||||
|
ptr += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (ptr < end)
|
||||||
|
{
|
||||||
|
h64 ^= *((byte*)ptr) * p5;
|
||||||
|
h64 = ((h64 << 11) | (h64 >> (64 - 11))) * p1; // (rotl 11) * p1
|
||||||
|
ptr += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// avalanche
|
||||||
|
h64 ^= h64 >> 33;
|
||||||
|
h64 *= p2;
|
||||||
|
h64 ^= h64 >> 29;
|
||||||
|
h64 *= p3;
|
||||||
|
h64 ^= h64 >> 32;
|
||||||
|
|
||||||
|
return h64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// Free memory
|
||||||
|
ArrayPool<byte>.Shared.Return(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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 Task<ulong> ComputeHashAsync(Stream stream, int bufferSize = 8192, ulong seed = 0)
|
||||||
|
{
|
||||||
|
// Go to the beginning of the stream
|
||||||
|
stream.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
// Get length of the stream
|
||||||
|
long length = stream.Length;
|
||||||
|
|
||||||
|
// The buffer can't be less than 1024 bytes
|
||||||
|
if (bufferSize < min64) bufferSize = min64;
|
||||||
|
else bufferSize &= div32;
|
||||||
|
|
||||||
|
// Calculate the number of chunks and the remain
|
||||||
|
int chunks = (int) length / bufferSize;
|
||||||
|
int remain = (int) length % bufferSize;
|
||||||
|
int offset = bufferSize;
|
||||||
|
|
||||||
|
// Calculate the offset
|
||||||
|
if (remain != 0) chunks++;
|
||||||
|
if (remain != 0 && remain < 32) offset -= 32;
|
||||||
|
|
||||||
|
// Optimizing memory allocation
|
||||||
|
byte[] buffer = ArrayPool<byte>.Shared.Rent(bufferSize);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Prepare the seed vector
|
||||||
|
ulong v1 = seed + p1 + p2;
|
||||||
|
ulong v2 = seed + p2;
|
||||||
|
ulong v3 = seed + 0;
|
||||||
|
ulong v4 = seed - p1;
|
||||||
|
|
||||||
|
// Process chunks
|
||||||
|
// Skip the last chunk. It will processed a little bit later
|
||||||
|
for (int i = 2; i <= chunks; i++)
|
||||||
|
{
|
||||||
|
// Change bufferSize for the last read
|
||||||
|
if (i == chunks) bufferSize = offset;
|
||||||
|
|
||||||
|
// Read the next chunk
|
||||||
|
await stream.ReadAsync(buffer, 0, bufferSize).ConfigureAwait(false);;
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
fixed (byte* pData = &buffer[0])
|
||||||
|
{
|
||||||
|
byte* ptr = pData;
|
||||||
|
byte* end = pData + bufferSize;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
v1 += *((ulong*) ptr) * p2;
|
||||||
|
v1 = (v1 << 31) | (v1 >> (64 - 31)); // rotl 31
|
||||||
|
v1 *= p1;
|
||||||
|
ptr += 8;
|
||||||
|
|
||||||
|
v2 += *((ulong*) ptr) * p2;
|
||||||
|
v2 = (v2 << 31) | (v2 >> (64 - 31)); // rotl 31
|
||||||
|
v2 *= p1;
|
||||||
|
ptr += 8;
|
||||||
|
|
||||||
|
v3 += *((ulong*) ptr) * p2;
|
||||||
|
v3 = (v3 << 31) | (v3 >> (64 - 31)); // rotl 31
|
||||||
|
v3 *= p1;
|
||||||
|
ptr += 8;
|
||||||
|
|
||||||
|
v4 += *((ulong*) ptr) * p2;
|
||||||
|
v4 = (v4 << 31) | (v4 >> (64 - 31)); // rotl 31
|
||||||
|
v4 *= p1;
|
||||||
|
ptr += 8;
|
||||||
|
|
||||||
|
} while (ptr < end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the last chunk
|
||||||
|
offset = await stream.ReadAsync(buffer, 0, bufferSize).ConfigureAwait(false);;
|
||||||
|
|
||||||
|
// Process the last chunk
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
fixed (byte* pData = &buffer[0])
|
||||||
|
{
|
||||||
|
byte* ptr = pData;
|
||||||
|
byte* end = pData + offset;
|
||||||
|
ulong h64;
|
||||||
|
|
||||||
|
if (length >= 32)
|
||||||
|
{
|
||||||
|
byte* limit = end - 32;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
v1 += *((ulong*) ptr) * p2;
|
||||||
|
v1 = (v1 << 31) | (v1 >> (64 - 31)); // rotl 31
|
||||||
|
v1 *= p1;
|
||||||
|
ptr += 8;
|
||||||
|
|
||||||
|
v2 += *((ulong*) ptr) * p2;
|
||||||
|
v2 = (v2 << 31) | (v2 >> (64 - 31)); // rotl 31
|
||||||
|
v2 *= p1;
|
||||||
|
ptr += 8;
|
||||||
|
|
||||||
|
v3 += *((ulong*) ptr) * p2;
|
||||||
|
v3 = (v3 << 31) | (v3 >> (64 - 31)); // rotl 31
|
||||||
|
v3 *= p1;
|
||||||
|
ptr += 8;
|
||||||
|
|
||||||
|
v4 += *((ulong*) ptr) * p2;
|
||||||
|
v4 = (v4 << 31) | (v4 >> (64 - 31)); // rotl 31
|
||||||
|
v4 *= p1;
|
||||||
|
ptr += 8;
|
||||||
|
|
||||||
|
} while (ptr <= limit);
|
||||||
|
|
||||||
|
h64 = ((v1 << 1) | (v1 >> (64 - 1))) + // rotl 1
|
||||||
|
((v2 << 7) | (v2 >> (64 - 7))) + // rotl 7
|
||||||
|
((v3 << 12) | (v3 >> (64 - 12))) + // rotl 12
|
||||||
|
((v4 << 18) | (v4 >> (64 - 18))); // rotl 18
|
||||||
|
|
||||||
|
// merge round
|
||||||
|
v1 *= p2;
|
||||||
|
v1 = (v1 << 31) | (v1 >> (64 - 31)); // rotl 31
|
||||||
|
v1 *= p1;
|
||||||
|
h64 ^= v1;
|
||||||
|
h64 = h64 * p1 + p4;
|
||||||
|
|
||||||
|
// merge round
|
||||||
|
v2 *= p2;
|
||||||
|
v2 = (v2 << 31) | (v2 >> (64 - 31)); // rotl 31
|
||||||
|
v2 *= p1;
|
||||||
|
h64 ^= v2;
|
||||||
|
h64 = h64 * p1 + p4;
|
||||||
|
|
||||||
|
// merge round
|
||||||
|
v3 *= p2;
|
||||||
|
v3 = (v3 << 31) | (v3 >> (64 - 31)); // rotl 31
|
||||||
|
v3 *= p1;
|
||||||
|
h64 ^= v3;
|
||||||
|
h64 = h64 * p1 + p4;
|
||||||
|
|
||||||
|
// merge round
|
||||||
|
v4 *= p2;
|
||||||
|
v4 = (v4 << 31) | (v4 >> (64 - 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 = (t1 << 31) | (t1 >> (64 - 31)); // rotl 31
|
||||||
|
t1 *= p1;
|
||||||
|
h64 ^= t1;
|
||||||
|
h64 = ((h64 << 27) | (h64 >> (64 - 27))) * p1 + p4; // (rotl 27) * p1 + p4
|
||||||
|
ptr += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ptr <= end - 4)
|
||||||
|
{
|
||||||
|
h64 ^= *((uint*) ptr) * p1;
|
||||||
|
h64 = ((h64 << 23) | (h64 >> (64 - 23))) * p2 + p3; // (rotl 27) * p2 + p3
|
||||||
|
ptr += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (ptr < end)
|
||||||
|
{
|
||||||
|
h64 ^= *((byte*) ptr) * p5;
|
||||||
|
h64 = ((h64 << 11) | (h64 >> (64 - 11))) * p1; // (rotl 11) * p1
|
||||||
|
ptr += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// avalanche
|
||||||
|
h64 ^= h64 >> 33;
|
||||||
|
h64 *= p2;
|
||||||
|
h64 ^= h64 >> 29;
|
||||||
|
h64 *= p3;
|
||||||
|
h64 ^= h64 >> 32;
|
||||||
|
|
||||||
|
return h64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// Free memory
|
||||||
|
ArrayPool<byte>.Shared.Return(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
namespace Standart.Hash.xxHash
|
namespace Standart.Hash.xxHash
|
||||||
{
|
{
|
||||||
public static class xxHash64
|
public static partial class xxHash64
|
||||||
{
|
{
|
||||||
private const ulong p1 = 11400714785074694791UL;
|
private const ulong p1 = 11400714785074694791UL;
|
||||||
private const ulong p2 = 14029467366897019727UL;
|
private const ulong p2 = 14029467366897019727UL;
|
||||||
@ -12,18 +12,18 @@
|
|||||||
/// Compute xxHash for the data byte array
|
/// Compute xxHash for the data byte array
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="data">The source of data</param>
|
/// <param name="data">The source of data</param>
|
||||||
/// <param name="len">The length of the data for hashing</param>
|
/// <param name="length">The length of the data for hashing</param>
|
||||||
/// <param name="seed">The seed number</param>
|
/// <param name="seed">The seed number</param>
|
||||||
/// <returns>hash</returns>
|
/// <returns>hash</returns>
|
||||||
public static unsafe ulong ComputeHash(byte[] data, int len, ulong seed = 0)
|
public static unsafe ulong ComputeHash(byte[] data, int length, ulong seed = 0)
|
||||||
{
|
{
|
||||||
fixed (byte* pData = &data[0])
|
fixed (byte* pData = &data[0])
|
||||||
{
|
{
|
||||||
byte* ptr = pData;
|
byte* ptr = pData;
|
||||||
byte* end = pData + len;
|
byte* end = pData + length;
|
||||||
ulong h64;
|
ulong h64;
|
||||||
|
|
||||||
if (len >= 32)
|
if (length >= 32)
|
||||||
{
|
{
|
||||||
byte* limit = end - 32;
|
byte* limit = end - 32;
|
||||||
|
|
||||||
@ -94,7 +94,7 @@
|
|||||||
h64 = seed + p5;
|
h64 = seed + p5;
|
||||||
}
|
}
|
||||||
|
|
||||||
h64 += (ulong) len;
|
h64 += (ulong) length;
|
||||||
|
|
||||||
// finalize
|
// finalize
|
||||||
while (ptr <= end - 8)
|
while (ptr <= end - 8)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user