Add Streaming API

This commit is contained in:
Oleksandr Melnyk 2018-05-13 13:48:53 +03:00
parent 09f8040a80
commit 2aea731a75
12 changed files with 1483 additions and 85 deletions

11
deps.props Normal file
View 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
View 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>

View File

@ -1,4 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\deps.props" />
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
@ -12,7 +13,7 @@
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.10.14" />
<PackageReference Include="BenchmarkDotNet" Version="$(BenchmarkDotNet)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Standart.Hash.xxHash\Standart.Hash.xxHash.csproj" />

View File

@ -1,6 +1,8 @@
namespace Standart.Hash.xxHash.Perf
{
using System;
using System.IO;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes.Columns;
using BenchmarkDotNet.Attributes.Exporters;
@ -16,6 +18,7 @@
const int GB = 1024 * MB;
private byte[] data;
private MemoryStream stream;
[Params(KB, MB, GB)]
public int N;
@ -25,6 +28,7 @@
{
data = new byte[N];
new Random(42).NextBytes(data);
stream = new MemoryStream(data);
}
[Benchmark]
@ -33,10 +37,34 @@
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]
public ulong Hash64()
{
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);
}
}
}

View File

@ -1,4 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\deps.props" />
<PropertyGroup>
<IsPackable>false</IsPackable>
<TargetFramework>netcoreapp2.0</TargetFramework>
@ -12,10 +13,10 @@
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.6.0" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftSdk)" />
<PackageReference Include="xunit" Version="$(xUnit)" />
<PackageReference Include="xunit.runner.visualstudio" Version="$(xUnitRunner)" />
<DotNetCliToolReference Include="dotnet-xunit" Version="$(xUnitTool)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Standart.Hash.xxHash\Standart.Hash.xxHash.csproj" />

View File

@ -1,12 +1,93 @@
namespace Standart.Hash.xxHash.Test
{
using System.Text;
using System;
using System.IO;
using System.Threading.Tasks;
using Xunit;
public class xxHash32Test
{
[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[]
@ -17,35 +98,267 @@
0x1c, 0x2c, 0xc9, 0x38, 0x7d, 0x43, 0x83, 0x11,
};
uint[] actual = new uint[]
{
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++)
{
// Act
uint hash = xxHash32.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
uint hash = xxHash32.ComputeHash(data, data.Length);
// Assert
Assert.Equal(0xe3cd4dee, hash);
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
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(new MemoryStream(data));
// Assert
Assert.Equal(hash, (uint) 0xf8497daa);
}
[Fact]
public void Compute_hash32_for_the_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 = 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
uint hash = await xxHash32.ComputeHashAsync(new MemoryStream(data));
// Assert
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);
}
}
}
}

View File

@ -1,16 +1,79 @@
namespace Standart.Hash.xxHash.Test
{
using System.Text;
using Hash;
using System;
using System.IO;
using System.Threading.Tasks;
using Xunit;
public class xxHash64Test
{
[Fact]
public void Compute_hash_for_the_byte_array()
public void Compute_hash64_for_the_length_1()
{
// 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,
0x85, 0x1f, 0xa6, 0x86, 0x34, 0x01, 0xd7, 0xf2,
@ -22,39 +85,244 @@
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
ulong hash = xxHash64.ComputeHash(data, data.Length);
// 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);
}
}
}
}

View File

@ -1,15 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<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>
<Import Project="..\..\nuget.props" />
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<Optimize>true</Optimize>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
@ -20,4 +10,8 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Buffers" Version="$(SystemBuffers)" />
<PackageReference Include="System.IO" Version="$(SystemIO)" />
</ItemGroup>
</Project>

View 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);
}
}
}
}

View File

@ -1,6 +1,6 @@
namespace Standart.Hash.xxHash
{
public static class xxHash32
public static partial class xxHash32
{
private const uint p1 = 2654435761U;
private const uint p2 = 2246822519U;
@ -12,18 +12,18 @@
/// Compute xxHash for the data byte array
/// </summary>
/// <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>
/// <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])
{
byte* ptr = pData;
byte* end = pData + len;
byte* end = pData + length;
uint h32;
if (len >= 16)
if (length >= 16)
{
byte* limit = end - 16;
@ -66,7 +66,7 @@
h32 = seed + p5;
}
h32 += (uint) len;
h32 += (uint) length;
// finalize
while (ptr <= end - 4)

View 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);
}
}
}
}

View File

@ -1,6 +1,6 @@
namespace Standart.Hash.xxHash
{
public static class xxHash64
public static partial class xxHash64
{
private const ulong p1 = 11400714785074694791UL;
private const ulong p2 = 14029467366897019727UL;
@ -12,18 +12,18 @@
/// Compute xxHash for the data byte array
/// </summary>
/// <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>
/// <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])
{
byte* ptr = pData;
byte* end = pData + len;
byte* end = pData + length;
ulong h64;
if (len >= 32)
if (length >= 32)
{
byte* limit = end - 32;
@ -94,7 +94,7 @@
h64 = seed + p5;
}
h64 += (ulong) len;
h64 += (ulong) length;
// finalize
while (ptr <= end - 8)