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)