diff --git a/deps.props b/deps.props
new file mode 100644
index 0000000..f74040c
--- /dev/null
+++ b/deps.props
@@ -0,0 +1,11 @@
+
+
+ 4.4.0
+ 4.3.0
+ 0.10.14
+ 15.6.0
+ 2.3.1
+ 2.3.1
+ 2.3.1
+
+
\ No newline at end of file
diff --git a/nuget.props b/nuget.props
new file mode 100644
index 0000000..cd339e6
--- /dev/null
+++ b/nuget.props
@@ -0,0 +1,14 @@
+
+
+
+ netstandard2.0
+ Standart.Hash.xxHash
+ 1.0.0
+ Standart.Hash.xxHash
+ Standart.Hash.xxHash
+ Alexander Melnik
+ hash;xxHash
+ Standart.Hash.xxHash
+ https://github.com/uranium62/xxHash
+
+
\ No newline at end of file
diff --git a/src/Standart.Hash.xxHash.Perf/Standart.Hash.xxHash.Perf.csproj b/src/Standart.Hash.xxHash.Perf/Standart.Hash.xxHash.Perf.csproj
index 2a5ae4b..6c9c03f 100644
--- a/src/Standart.Hash.xxHash.Perf/Standart.Hash.xxHash.Perf.csproj
+++ b/src/Standart.Hash.xxHash.Perf/Standart.Hash.xxHash.Perf.csproj
@@ -1,4 +1,5 @@
+
Exe
netcoreapp2.0
@@ -12,7 +13,7 @@
AnyCPU
-
+
diff --git a/src/Standart.Hash.xxHash.Perf/xxHashBenchmark.cs b/src/Standart.Hash.xxHash.Perf/xxHashBenchmark.cs
index 4bba1ef..b06f32b 100644
--- a/src/Standart.Hash.xxHash.Perf/xxHashBenchmark.cs
+++ b/src/Standart.Hash.xxHash.Perf/xxHashBenchmark.cs
@@ -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,18 +28,43 @@
{
data = new byte[N];
new Random(42).NextBytes(data);
+ stream = new MemoryStream(data);
}
-
+
[Benchmark]
public uint Hash32()
{
return xxHash32.ComputeHash(data, data.Length);
}
+ [Benchmark]
+ public uint Hash32_Stream()
+ {
+ return xxHash32.ComputeHash(stream);
+ }
+
+ [Benchmark]
+ public async Task 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 Hash64_StreamAsync()
+ {
+ return await xxHash64.ComputeHashAsync(stream);
+ }
}
}
\ No newline at end of file
diff --git a/src/Standart.Hash.xxHash.Test/Standart.Hash.xxHash.Test.csproj b/src/Standart.Hash.xxHash.Test/Standart.Hash.xxHash.Test.csproj
index 64be2ed..cfa3709 100644
--- a/src/Standart.Hash.xxHash.Test/Standart.Hash.xxHash.Test.csproj
+++ b/src/Standart.Hash.xxHash.Test/Standart.Hash.xxHash.Test.csproj
@@ -1,4 +1,5 @@
+
false
netcoreapp2.0
@@ -12,10 +13,10 @@
AnyCPU
-
-
-
-
+
+
+
+
diff --git a/src/Standart.Hash.xxHash.Test/xxHash32Test.cs b/src/Standart.Hash.xxHash.Test/xxHash32Test.cs
index aa0cbbf..4a0bb9e 100644
--- a/src/Standart.Hash.xxHash.Test/xxHash32Test.cs
+++ b/src/Standart.Hash.xxHash.Test/xxHash32Test.cs
@@ -1,12 +1,191 @@
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[]
+ {
+ 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
byte[] data = new byte[]
@@ -17,35 +196,169 @@
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,
- };
+ // Act
+ uint hash = xxHash32.ComputeHash(new MemoryStream(data));
- for (int len = 1; len <= data.Length; len++)
- {
- // Act
- uint hash = xxHash32.ComputeHash(data, len);
-
- // Assert
- Assert.Equal(hash, actual[len - 1]);
- }
+ // Assert
+ Assert.Equal(hash, (uint) 0xf8497daa);
}
[Fact]
- public void Compute_hash_for_the_string()
+ public void Compute_hash32_for_the_random_stream()
{
// 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
- uint hash = xxHash32.ComputeHash(data, data.Length);
+ uint hash = await xxHash32.ComputeHashAsync(new MemoryStream(data));
// 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);
+ }
}
}
}
\ No newline at end of file
diff --git a/src/Standart.Hash.xxHash.Test/xxHash64Test.cs b/src/Standart.Hash.xxHash.Test/xxHash64Test.cs
index 5693ad6..be65204 100644
--- a/src/Standart.Hash.xxHash.Test/xxHash64Test.cs
+++ b/src/Standart.Hash.xxHash.Test/xxHash64Test.cs
@@ -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,
@@ -21,40 +84,245 @@
0x27, 0x6d, 0xb3, 0x5c, 0xc7, 0xc0, 0xd0, 0xa0,
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);
+ }
+ }
+
}
}
\ No newline at end of file
diff --git a/src/Standart.Hash.xxHash/Standart.Hash.xxHash.csproj b/src/Standart.Hash.xxHash/Standart.Hash.xxHash.csproj
index 3bc47ba..5b8cf44 100644
--- a/src/Standart.Hash.xxHash/Standart.Hash.xxHash.csproj
+++ b/src/Standart.Hash.xxHash/Standart.Hash.xxHash.csproj
@@ -1,15 +1,5 @@
-
- net45;netstandard2.0
- Standart.Hash.xxHash
- 1.0.0
- Standart.Hash.xxHash
- Standart.Hash.xxHash
- Alexander Melnik
- hash;xxHash
- Standart.Hash.xxHash
- https://github.com/uranium62/xxHash
-
+
true
true
@@ -20,4 +10,8 @@
true
AnyCPU
+
+
+
+
\ No newline at end of file
diff --git a/src/Standart.Hash.xxHash/xxHash32.Stream.cs b/src/Standart.Hash.xxHash/xxHash32.Stream.cs
new file mode 100644
index 0000000..3f26550
--- /dev/null
+++ b/src/Standart.Hash.xxHash/xxHash32.Stream.cs
@@ -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;
+
+ ///
+ /// Compute xxHash for the stream
+ ///
+ /// The stream of data
+ /// The buffer size
+ /// The seed number
+ /// The hash
+ 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.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.Shared.Return(buffer);
+ }
+ }
+
+ ///
+ /// Compute xxHash for the async stream
+ ///
+ /// The stream of data
+ /// The buffer size
+ /// The seed number
+ /// The hash
+ public static async Task 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.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.Shared.Return(buffer);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Standart.Hash.xxHash/xxHash32.cs b/src/Standart.Hash.xxHash/xxHash32.cs
index ef51e2c..9eac1b8 100644
--- a/src/Standart.Hash.xxHash/xxHash32.cs
+++ b/src/Standart.Hash.xxHash/xxHash32.cs
@@ -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
///
/// The source of data
- /// The length of the data for hashing
+ /// The length of the data for hashing
/// The seed number
/// hash
- 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)
diff --git a/src/Standart.Hash.xxHash/xxHash64.Stream.cs b/src/Standart.Hash.xxHash/xxHash64.Stream.cs
new file mode 100644
index 0000000..2020dda
--- /dev/null
+++ b/src/Standart.Hash.xxHash/xxHash64.Stream.cs
@@ -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;
+
+ ///
+ /// Compute xxHash for the stream
+ ///
+ /// The stream of data
+ /// The buffer size
+ /// The seed number
+ /// The hash
+ 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.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.Shared.Return(buffer);
+ }
+ }
+
+ ///
+ /// Compute xxHash for the async stream
+ ///
+ /// The stream of data
+ /// The buffer size
+ /// The seed number
+ /// The hash
+ public static async Task 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.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.Shared.Return(buffer);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Standart.Hash.xxHash/xxHash64.cs b/src/Standart.Hash.xxHash/xxHash64.cs
index 9b1eac9..8e643ba 100644
--- a/src/Standart.Hash.xxHash/xxHash64.cs
+++ b/src/Standart.Hash.xxHash/xxHash64.cs
@@ -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
///
/// The source of data
- /// The length of the data for hashing
+ /// The length of the data for hashing
/// The seed number
/// hash
- 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)