From 62d648b6c3829c0eb0f4ec161476c875a47955ed Mon Sep 17 00:00:00 2001 From: Igor Tamashchuk Date: Wed, 5 Oct 2022 20:29:24 +0300 Subject: [PATCH] Add net5.0 support --- deps.props | 2 + nuget.props | 3 +- .../Standart.Hash.xxHash.Perf.csproj | 1 - .../Standart.Hash.xxHash.Test.csproj | 1 - .../xxHash128Test.cs | 187 +++---- .../Standart.Hash.xxHash.csproj | 1 - .../__inline__xxHash32.cs | 288 +++++------ .../__inline__xxHash64.cs | 343 ++++++------- src/Standart.Hash.xxHash/xxHash32.XXH.cs | 29 +- src/Standart.Hash.xxHash/xxHash32.cs | 467 ++++++++--------- src/Standart.Hash.xxHash/xxHash64.XXH.cs | 29 +- src/Standart.Hash.xxHash/xxHash64.cs | 474 +++++++++--------- 12 files changed, 916 insertions(+), 909 deletions(-) diff --git a/deps.props b/deps.props index 0d10c00..c5ff158 100644 --- a/deps.props +++ b/deps.props @@ -1,5 +1,7 @@ + net5.0;net6.0 + 9.0 0.13.1 17.2.0 2.4.1 diff --git a/nuget.props b/nuget.props index 816d197..2edde0c 100644 --- a/nuget.props +++ b/nuget.props @@ -1,9 +1,8 @@ - net6.0 Standart.Hash.xxHash - 4.0.4 + 4.0.5 Standart.Hash.xxHash Standart.Hash.xxHash Oleksandr Melnyk 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 36f9cef..e0e03f3 100644 --- a/src/Standart.Hash.xxHash.Perf/Standart.Hash.xxHash.Perf.csproj +++ b/src/Standart.Hash.xxHash.Perf/Standart.Hash.xxHash.Perf.csproj @@ -2,7 +2,6 @@ Exe - net6.0 true 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 d6e0d5b..928cfbc 100644 --- a/src/Standart.Hash.xxHash.Test/Standart.Hash.xxHash.Test.csproj +++ b/src/Standart.Hash.xxHash.Test/Standart.Hash.xxHash.Test.csproj @@ -2,7 +2,6 @@ false - net6.0 full diff --git a/src/Standart.Hash.xxHash.Test/xxHash128Test.cs b/src/Standart.Hash.xxHash.Test/xxHash128Test.cs index 51d4435..015b2c4 100644 --- a/src/Standart.Hash.xxHash.Test/xxHash128Test.cs +++ b/src/Standart.Hash.xxHash.Test/xxHash128Test.cs @@ -2,112 +2,113 @@ using System; using System.Text; using Xunit; -namespace Standart.Hash.xxHash.Test; - -public class xxHash128Test +namespace Standart.Hash.xxHash.Test { - [Fact] - public void Compute_hash128_for_bytes() + public class xxHash128Test { - // Arrange - var bytes = new byte[] + [Fact] + public void Compute_hash128_for_bytes() { - 0xd2, 0x94, 0x29, 0xc9, 0x4c, 0xc5, 0x0f, 0xbb, - 0xaa, 0xf4, 0x7c, 0xd5, 0x69, 0x5a, 0xa9, 0xbd, - 0xaf, 0xd8, 0x3f, 0xfb, 0xca, 0x6a, 0xd4, 0x2c, - 0x6c, 0x69, 0x7a, 0x5b, 0x0d, 0xe8, 0xd2, 0xb1, - 0x41, 0xb3, 0x1b, 0x23, 0xdb, 0x8c, 0x25, 0xb4, - 0x6c, 0xfb - }; + // Arrange + var bytes = new byte[] + { + 0xd2, 0x94, 0x29, 0xc9, 0x4c, 0xc5, 0x0f, 0xbb, + 0xaa, 0xf4, 0x7c, 0xd5, 0x69, 0x5a, 0xa9, 0xbd, + 0xaf, 0xd8, 0x3f, 0xfb, 0xca, 0x6a, 0xd4, 0x2c, + 0x6c, 0x69, 0x7a, 0x5b, 0x0d, 0xe8, 0xd2, 0xb1, + 0x41, 0xb3, 0x1b, 0x23, 0xdb, 0x8c, 0x25, 0xb4, + 0x6c, 0xfb + }; - ulong expectedH = 3466251221427321594; - ulong expectedL = 2862260537881727713; + ulong expectedH = 3466251221427321594; + ulong expectedL = 2862260537881727713; - // Act - var hash = xxHash128.ComputeHash(bytes, bytes.Length); - - // Assert - Assert.Equal(expectedH, hash.high64); - Assert.Equal(expectedL, hash.low64); - } - - [Fact] - public void Compute_hash128_for_span() - { - // Arrange - var bytes = new byte[] + // Act + var hash = xxHash128.ComputeHash(bytes, bytes.Length); + + // Assert + Assert.Equal(expectedH, hash.high64); + Assert.Equal(expectedL, hash.low64); + } + + [Fact] + public void Compute_hash128_for_span() { - 0xd2, 0x94, 0x29, 0xc9, 0x4c, 0xc5, 0x0f, 0xbb, - 0xaa, 0xf4, 0x7c, 0xd5, 0x69, 0x5a, 0xa9, 0xbd, - 0xaf, 0xd8, 0x3f, 0xfb, 0xca, 0x6a, 0xd4, 0x2c, - 0x6c, 0x69, 0x7a, 0x5b, 0x0d, 0xe8, 0xd2, 0xb1, - 0x41, 0xb3, 0x1b, 0x23, 0xdb, 0x8c, 0x25, 0xb4, - 0x6c, 0xfb - }; - var span = bytes.AsSpan(); + // Arrange + var bytes = new byte[] + { + 0xd2, 0x94, 0x29, 0xc9, 0x4c, 0xc5, 0x0f, 0xbb, + 0xaa, 0xf4, 0x7c, 0xd5, 0x69, 0x5a, 0xa9, 0xbd, + 0xaf, 0xd8, 0x3f, 0xfb, 0xca, 0x6a, 0xd4, 0x2c, + 0x6c, 0x69, 0x7a, 0x5b, 0x0d, 0xe8, 0xd2, 0xb1, + 0x41, 0xb3, 0x1b, 0x23, 0xdb, 0x8c, 0x25, 0xb4, + 0x6c, 0xfb + }; + var span = bytes.AsSpan(); - ulong expectedH = 3466251221427321594; - ulong expectedL = 2862260537881727713; + ulong expectedH = 3466251221427321594; + ulong expectedL = 2862260537881727713; - // Act - var hash = xxHash128.ComputeHash(span, span.Length); - - // Assert - Assert.Equal(expectedH, hash.high64); - Assert.Equal(expectedL, hash.low64); - } - - - [Fact] - public void Compute_hash128_for_string() - { - // Arrange - var str = "veni vidi vici"; - var bytes = Encoding.Unicode.GetBytes(str); + // Act + var hash = xxHash128.ComputeHash(span, span.Length); - // Act - var hash1 = xxHash128.ComputeHash(str); - var hash2 = xxHash128.ComputeHash(bytes, bytes.Length); - - // Assert - Assert.Equal(hash1.high64, hash2.high64); - Assert.Equal(hash1.low64, hash2.low64); - } - - [Fact] - public void Compute_hash128_bytes_for_bytes() - { - // Arrange - var bytes = new byte[] + // Assert + Assert.Equal(expectedH, hash.high64); + Assert.Equal(expectedL, hash.low64); + } + + + [Fact] + public void Compute_hash128_for_string() { - 0xd2, 0x94, 0x29, 0xc9, 0x4c, 0xc5, 0x0f, 0xbb, - 0xaa, 0xf4, 0x7c, 0xd5, 0x69, 0x5a, 0xa9, 0xbd, - 0xaf, 0xd8, 0x3f, 0xfb, 0xca, 0x6a, 0xd4, 0x2c, - 0x6c, 0x69, 0x7a, 0x5b, 0x0d, 0xe8, 0xd2, 0xb1, - 0x41, 0xb3, 0x1b, 0x23, 0xdb, 0x8c, 0x25, 0xb4, - 0x6c, 0xfb - }; - - // ulong expectedH = 3466251221427321594; - // ulong expectedL = 2862260537881727713; + // Arrange + var str = "veni vidi vici"; + var bytes = Encoding.Unicode.GetBytes(str); - // (hBits * 18446744073709551616) + lBits - // (3466251221427321594 * 18446744073709551616) + 2862260537881727713 - - // dec: 63941049176852939372872402763456123617 - // hex: 301A991EF3707AFA27B8CACB570F12E1 - var expected = new byte[] + // Act + var hash1 = xxHash128.ComputeHash(str); + var hash2 = xxHash128.ComputeHash(bytes, bytes.Length); + + // Assert + Assert.Equal(hash1.high64, hash2.high64); + Assert.Equal(hash1.low64, hash2.low64); + } + + [Fact] + public void Compute_hash128_bytes_for_bytes() { - 0xe1, 0x12, 0x0F, 0x57, 0xcb, 0xca, 0xb8, 0x27, - 0xfa, 0x7a, 0x70, 0xf3, 0x1e, 0x99, 0x1a, 0x30 - }; + // Arrange + var bytes = new byte[] + { + 0xd2, 0x94, 0x29, 0xc9, 0x4c, 0xc5, 0x0f, 0xbb, + 0xaa, 0xf4, 0x7c, 0xd5, 0x69, 0x5a, 0xa9, 0xbd, + 0xaf, 0xd8, 0x3f, 0xfb, 0xca, 0x6a, 0xd4, 0x2c, + 0x6c, 0x69, 0x7a, 0x5b, 0x0d, 0xe8, 0xd2, 0xb1, + 0x41, 0xb3, 0x1b, 0x23, 0xdb, 0x8c, 0x25, 0xb4, + 0x6c, 0xfb + }; - // Act - var hash = xxHash128.ComputeHashBytes(bytes, bytes.Length); + // ulong expectedH = 3466251221427321594; + // ulong expectedL = 2862260537881727713; + + // (hBits * 18446744073709551616) + lBits + // (3466251221427321594 * 18446744073709551616) + 2862260537881727713 + + // dec: 63941049176852939372872402763456123617 + // hex: 301A991EF3707AFA27B8CACB570F12E1 + var expected = new byte[] + { + 0xe1, 0x12, 0x0F, 0x57, 0xcb, 0xca, 0xb8, 0x27, + 0xfa, 0x7a, 0x70, 0xf3, 0x1e, 0x99, 0x1a, 0x30 + }; + + // Act + var hash = xxHash128.ComputeHashBytes(bytes, bytes.Length); + + // Assert + for (int i = 0; i < 16; i++) + Assert.Equal(expected[i], hash[i]); + } - // Assert - for (int i = 0; i < 16; i++) - Assert.Equal(expected[i], hash[i]); } - } \ 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 41208ef..00d92f3 100644 --- a/src/Standart.Hash.xxHash/Standart.Hash.xxHash.csproj +++ b/src/Standart.Hash.xxHash/Standart.Hash.xxHash.csproj @@ -3,7 +3,6 @@ - net6.0 true diff --git a/src/Standart.Hash.xxHash/__inline__xxHash32.cs b/src/Standart.Hash.xxHash/__inline__xxHash32.cs index 8e71787..078f8c0 100644 --- a/src/Standart.Hash.xxHash/__inline__xxHash32.cs +++ b/src/Standart.Hash.xxHash/__inline__xxHash32.cs @@ -6,147 +6,56 @@ using System.Runtime.CompilerServices; -namespace Standart.Hash.xxHash; - -public partial class xxHash32 +namespace Standart.Hash.xxHash { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe uint __inline__XXH32(byte* input, int len, uint seed) + public partial class xxHash32 { - uint h32; - - if (len >= 16) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static unsafe uint __inline__XXH32(byte* input, int len, uint seed) { - byte* end = input + len; - byte* limit = end - 15; - - uint v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2; - uint v2 = seed + XXH_PRIME32_2; - uint v3 = seed + 0; - uint v4 = seed - XXH_PRIME32_1; - - do - { - var reg1 = *((uint*)(input + 0)); - var reg2 = *((uint*)(input + 4)); - var reg3 = *((uint*)(input + 8)); - var reg4 = *((uint*)(input + 12)); - - // XXH32_round - v1 += reg1 * XXH_PRIME32_2; - v1 = (v1 << 13) | (v1 >> (32 - 13)); - v1 *= XXH_PRIME32_1; - - // XXH32_round - v2 += reg2 * XXH_PRIME32_2; - v2 = (v2 << 13) | (v2 >> (32 - 13)); - v2 *= XXH_PRIME32_1; - - // XXH32_round - v3 += reg3 * XXH_PRIME32_2; - v3 = (v3 << 13) | (v3 >> (32 - 13)); - v3 *= XXH_PRIME32_1; - - // XXH32_round - v4 += reg4 * XXH_PRIME32_2; - v4 = (v4 << 13) | (v4 >> (32 - 13)); - v4 *= XXH_PRIME32_1; - - input += 16; - } while (input < limit); - - h32 = ((v1 << 1) | (v1 >> (32 - 1))) + - ((v2 << 7) | (v2 >> (32 - 7))) + - ((v3 << 12) | (v3 >> (32 - 12))) + - ((v4 << 18) | (v4 >> (32 - 18))); - } - else - { - h32 = seed + XXH_PRIME32_5; - } - - h32 += (uint) len; - - // XXH32_finalize - len &= 15; - while (len >= 4) - { - h32 += *((uint*) input) * XXH_PRIME32_3; - input += 4; - h32 = ((h32 << 17) | (h32 >> (32 - 17))) * XXH_PRIME32_4; - len -= 4; - } - - while (len > 0) - { - h32 += *((byte*) input) * XXH_PRIME32_5; - ++input; - h32 = ((h32 << 11) | (h32 >> (32 - 11))) * XXH_PRIME32_1; - --len; - } - - // XXH32_avalanche - h32 ^= h32 >> 15; - h32 *= XXH_PRIME32_2; - h32 ^= h32 >> 13; - h32 *= XXH_PRIME32_3; - h32 ^= h32 >> 16; - - return h32; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe void __inline__XXH32_stream_process(byte[] input, int len, ref uint v1, ref uint v2, ref uint v3, ref uint v4) - { - fixed (byte* pData = &input[0]) - { - byte* ptr = pData; - byte* limit = ptr + len; - - do - { - var reg1 = *((uint*)(ptr + 0)); - var reg2 = *((uint*)(ptr + 4)); - var reg3 = *((uint*)(ptr + 8)); - var reg4 = *((uint*)(ptr + 12)); - - // XXH32_round - v1 += reg1 * XXH_PRIME32_2; - v1 = (v1 << 13) | (v1 >> (32 - 13)); - v1 *= XXH_PRIME32_1; - - // XXH32_round - v2 += reg2 * XXH_PRIME32_2; - v2 = (v2 << 13) | (v2 >> (32 - 13)); - v2 *= XXH_PRIME32_1; - - // XXH32_round - v3 += reg3 * XXH_PRIME32_2; - v3 = (v3 << 13) | (v3 >> (32 - 13)); - v3 *= XXH_PRIME32_1; - - // XXH32_round - v4 += reg4 * XXH_PRIME32_2; - v4 = (v4 << 13) | (v4 >> (32 - 13)); - v4 *= XXH_PRIME32_1; - - ptr += 16; - - } while (ptr < limit); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe uint __inline__XXH32_stream_finalize(byte[] input, int len, ref uint v1, ref uint v2, ref uint v3, ref uint v4, long length, uint seed) - { - fixed (byte* pData = &input[0]) - { - byte* ptr = pData; uint h32; - if (length >= 16) + if (len >= 16) { - h32 = ((v1 << 1) | (v1 >> (32 - 1))) + + byte* end = input + len; + byte* limit = end - 15; + + uint v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2; + uint v2 = seed + XXH_PRIME32_2; + uint v3 = seed + 0; + uint v4 = seed - XXH_PRIME32_1; + + do + { + var reg1 = *((uint*)(input + 0)); + var reg2 = *((uint*)(input + 4)); + var reg3 = *((uint*)(input + 8)); + var reg4 = *((uint*)(input + 12)); + + // XXH32_round + v1 += reg1 * XXH_PRIME32_2; + v1 = (v1 << 13) | (v1 >> (32 - 13)); + v1 *= XXH_PRIME32_1; + + // XXH32_round + v2 += reg2 * XXH_PRIME32_2; + v2 = (v2 << 13) | (v2 >> (32 - 13)); + v2 *= XXH_PRIME32_1; + + // XXH32_round + v3 += reg3 * XXH_PRIME32_2; + v3 = (v3 << 13) | (v3 >> (32 - 13)); + v3 *= XXH_PRIME32_1; + + // XXH32_round + v4 += reg4 * XXH_PRIME32_2; + v4 = (v4 << 13) | (v4 >> (32 - 13)); + v4 *= XXH_PRIME32_1; + + input += 16; + } while (input < limit); + + h32 = ((v1 << 1) | (v1 >> (32 - 1))) + ((v2 << 7) | (v2 >> (32 - 7))) + ((v3 << 12) | (v3 >> (32 - 12))) + ((v4 << 18) | (v4 >> (32 - 18))); @@ -156,24 +65,24 @@ public partial class xxHash32 h32 = seed + XXH_PRIME32_5; } - h32 += (uint)length; + h32 += (uint) len; // XXH32_finalize len &= 15; while (len >= 4) { - h32 += *((uint*)ptr) * XXH_PRIME32_3; - ptr += 4; + h32 += *((uint*) input) * XXH_PRIME32_3; + input += 4; h32 = ((h32 << 17) | (h32 >> (32 - 17))) * XXH_PRIME32_4; len -= 4; } while (len > 0) { - h32 += *((byte*)ptr) * XXH_PRIME32_5; - ptr++; + h32 += *((byte*) input) * XXH_PRIME32_5; + ++input; h32 = ((h32 << 11) | (h32 >> (32 - 11))) * XXH_PRIME32_1; - len--; + --len; } // XXH32_avalanche @@ -185,5 +94,98 @@ public partial class xxHash32 return h32; } - } -} \ No newline at end of file + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static unsafe void __inline__XXH32_stream_process(byte[] input, int len, ref uint v1, ref uint v2, ref uint v3, ref uint v4) + { + fixed (byte* pData = &input[0]) + { + byte* ptr = pData; + byte* limit = ptr + len; + + do + { + var reg1 = *((uint*)(ptr + 0)); + var reg2 = *((uint*)(ptr + 4)); + var reg3 = *((uint*)(ptr + 8)); + var reg4 = *((uint*)(ptr + 12)); + + // XXH32_round + v1 += reg1 * XXH_PRIME32_2; + v1 = (v1 << 13) | (v1 >> (32 - 13)); + v1 *= XXH_PRIME32_1; + + // XXH32_round + v2 += reg2 * XXH_PRIME32_2; + v2 = (v2 << 13) | (v2 >> (32 - 13)); + v2 *= XXH_PRIME32_1; + + // XXH32_round + v3 += reg3 * XXH_PRIME32_2; + v3 = (v3 << 13) | (v3 >> (32 - 13)); + v3 *= XXH_PRIME32_1; + + // XXH32_round + v4 += reg4 * XXH_PRIME32_2; + v4 = (v4 << 13) | (v4 >> (32 - 13)); + v4 *= XXH_PRIME32_1; + + ptr += 16; + + } while (ptr < limit); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static unsafe uint __inline__XXH32_stream_finalize(byte[] input, int len, ref uint v1, ref uint v2, ref uint v3, ref uint v4, long length, uint seed) + { + fixed (byte* pData = &input[0]) + { + byte* ptr = pData; + uint h32; + + if (length >= 16) + { + h32 = ((v1 << 1) | (v1 >> (32 - 1))) + + ((v2 << 7) | (v2 >> (32 - 7))) + + ((v3 << 12) | (v3 >> (32 - 12))) + + ((v4 << 18) | (v4 >> (32 - 18))); + } + else + { + h32 = seed + XXH_PRIME32_5; + } + + h32 += (uint)length; + + // XXH32_finalize + len &= 15; + while (len >= 4) + { + h32 += *((uint*)ptr) * XXH_PRIME32_3; + ptr += 4; + h32 = ((h32 << 17) | (h32 >> (32 - 17))) * XXH_PRIME32_4; + len -= 4; + } + + while (len > 0) + { + h32 += *((byte*)ptr) * XXH_PRIME32_5; + ptr++; + h32 = ((h32 << 11) | (h32 >> (32 - 11))) * XXH_PRIME32_1; + len--; + } + + // XXH32_avalanche + h32 ^= h32 >> 15; + h32 *= XXH_PRIME32_2; + h32 ^= h32 >> 13; + h32 *= XXH_PRIME32_3; + h32 ^= h32 >> 16; + + return h32; + } + } + } +} + diff --git a/src/Standart.Hash.xxHash/__inline__xxHash64.cs b/src/Standart.Hash.xxHash/__inline__xxHash64.cs index 04f9ec6..451dbf4 100644 --- a/src/Standart.Hash.xxHash/__inline__xxHash64.cs +++ b/src/Standart.Hash.xxHash/__inline__xxHash64.cs @@ -6,177 +6,54 @@ using System.Runtime.CompilerServices; -namespace Standart.Hash.xxHash; - -public partial class xxHash64 +namespace Standart.Hash.xxHash { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe ulong __inline__XXH64(byte* input, int len, ulong seed) + public partial class xxHash64 { - ulong h64; - - if (len >= 32) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static unsafe ulong __inline__XXH64(byte* input, int len, ulong seed) { - byte* end = input + len; - byte* limit = end - 31; - - ulong v1 = seed + XXH_PRIME64_1 + XXH_PRIME64_2; - ulong v2 = seed + XXH_PRIME64_2; - ulong v3 = seed + 0; - ulong v4 = seed - XXH_PRIME64_1; - - do - { - var reg1 = *((ulong*)(input + 0)); - var reg2 = *((ulong*)(input + 8)); - var reg3 = *((ulong*)(input + 16)); - var reg4 = *((ulong*)(input + 24)); - - // XXH64_round - v1 += reg1 * XXH_PRIME64_2; - v1 = (v1 << 31) | (v1 >> (64 - 31)); - v1 *= XXH_PRIME64_1; - - // XXH64_round - v2 += reg2 * XXH_PRIME64_2; - v2 = (v2 << 31) | (v2 >> (64 - 31)); - v2 *= XXH_PRIME64_1; - - // XXH64_round - v3 += reg3 * XXH_PRIME64_2; - v3 = (v3 << 31) | (v3 >> (64 - 31)); - v3 *= XXH_PRIME64_1; - - // XXH64_round - v4 += reg4 * XXH_PRIME64_2; - v4 = (v4 << 31) | (v4 >> (64 - 31)); - v4 *= XXH_PRIME64_1; - input += 32; - } while (input < limit); - - h64 = ((v1 << 1) | (v1 >> (64 - 1))) + - ((v2 << 7) | (v2 >> (64 - 7))) + - ((v3 << 12) | (v3 >> (64 - 12))) + - ((v4 << 18) | (v4 >> (64 - 18))); - - // XXH64_mergeRound - v1 *= XXH_PRIME64_2; - v1 = (v1 << 31) | (v1 >> (64 - 31)); - v1 *= XXH_PRIME64_1; - h64 ^= v1; - h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4; - - // XXH64_mergeRound - v2 *= XXH_PRIME64_2; - v2 = (v2 << 31) | (v2 >> (64 - 31)); - v2 *= XXH_PRIME64_1; - h64 ^= v2; - h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4; - - // XXH64_mergeRound - v3 *= XXH_PRIME64_2; - v3 = (v3 << 31) | (v3 >> (64 - 31)); - v3 *= XXH_PRIME64_1; - h64 ^= v3; - h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4; - - // XXH64_mergeRound - v4 *= XXH_PRIME64_2; - v4 = (v4 << 31) | (v4 >> (64 - 31)); - v4 *= XXH_PRIME64_1; - h64 ^= v4; - h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4; - } - else - { - h64 = seed + XXH_PRIME64_5; - } - - h64 += (ulong) len; - - // XXH64_finalize - len &= 31; - while (len >= 8) { - ulong k1 = XXH64_round(0, *(ulong*)input); - input += 8; - h64 ^= k1; - h64 = XXH_rotl64(h64,27) * XXH_PRIME64_1 + XXH_PRIME64_4; - len -= 8; - } - if (len >= 4) { - h64 ^= *(uint*)input * XXH_PRIME64_1; - input += 4; - h64 = XXH_rotl64(h64, 23) * XXH_PRIME64_2 + XXH_PRIME64_3; - len -= 4; - } - while (len > 0) { - h64 ^= (*input++) * XXH_PRIME64_5; - h64 = XXH_rotl64(h64, 11) * XXH_PRIME64_1; - --len; - } - - // XXH64_avalanche - h64 ^= h64 >> 33; - h64 *= XXH_PRIME64_2; - h64 ^= h64 >> 29; - h64 *= XXH_PRIME64_3; - h64 ^= h64 >> 32; - - return h64; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe void __inline__XXH64_stream_process(byte[] input, int len, ref ulong v1, ref ulong v2, ref ulong v3, - ref ulong v4) - { - fixed (byte* pData = &input[0]) - { - byte* ptr = pData; - byte* limit = ptr + len; - - do - { - var reg1 = *((ulong*)(ptr + 0)); - var reg2 = *((ulong*)(ptr + 8)); - var reg3 = *((ulong*)(ptr + 16)); - var reg4 = *((ulong*)(ptr + 24)); - - // XXH64_round - v1 += reg1 * XXH_PRIME64_2; - v1 = (v1 << 31) | (v1 >> (64 - 31)); - v1 *= XXH_PRIME64_1; - - // XXH64_round - v2 += reg2 * XXH_PRIME64_2; - v2 = (v2 << 31) | (v2 >> (64 - 31)); - v2 *= XXH_PRIME64_1; - - // XXH64_round - v3 += reg3 * XXH_PRIME64_2; - v3 = (v3 << 31) | (v3 >> (64 - 31)); - v3 *= XXH_PRIME64_1; - - // XXH64_round - v4 += reg4 * XXH_PRIME64_2; - v4 = (v4 << 31) | (v4 >> (64 - 31)); - v4 *= XXH_PRIME64_1; - ptr += 32; - } while (ptr < limit); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe ulong __inline__XXH64_stream_finalize(byte[] input, int len, ref ulong v1, ref ulong v2, ref ulong v3, - ref ulong v4, long length, ulong seed) - { - fixed (byte* pData = &input[0]) - { - byte* ptr = pData; - byte* end = pData + len; ulong h64; - if (length >= 32) + if (len >= 32) { + byte* end = input + len; + byte* limit = end - 31; + + ulong v1 = seed + XXH_PRIME64_1 + XXH_PRIME64_2; + ulong v2 = seed + XXH_PRIME64_2; + ulong v3 = seed + 0; + ulong v4 = seed - XXH_PRIME64_1; + + do + { + var reg1 = *((ulong*)(input + 0)); + var reg2 = *((ulong*)(input + 8)); + var reg3 = *((ulong*)(input + 16)); + var reg4 = *((ulong*)(input + 24)); + + // XXH64_round + v1 += reg1 * XXH_PRIME64_2; + v1 = (v1 << 31) | (v1 >> (64 - 31)); + v1 *= XXH_PRIME64_1; + + // XXH64_round + v2 += reg2 * XXH_PRIME64_2; + v2 = (v2 << 31) | (v2 >> (64 - 31)); + v2 *= XXH_PRIME64_1; + + // XXH64_round + v3 += reg3 * XXH_PRIME64_2; + v3 = (v3 << 31) | (v3 >> (64 - 31)); + v3 *= XXH_PRIME64_1; + + // XXH64_round + v4 += reg4 * XXH_PRIME64_2; + v4 = (v4 << 31) | (v4 >> (64 - 31)); + v4 *= XXH_PRIME64_1; + input += 32; + } while (input < limit); + h64 = ((v1 << 1) | (v1 >> (64 - 1))) + ((v2 << 7) | (v2 >> (64 - 7))) + ((v3 << 12) | (v3 >> (64 - 12))) + @@ -215,25 +92,25 @@ public partial class xxHash64 h64 = seed + XXH_PRIME64_5; } - h64 += (ulong) length; + h64 += (ulong) len; // XXH64_finalize len &= 31; while (len >= 8) { - ulong k1 = XXH64_round(0, *(ulong*)ptr); - ptr += 8; + ulong k1 = XXH64_round(0, *(ulong*)input); + input += 8; h64 ^= k1; h64 = XXH_rotl64(h64,27) * XXH_PRIME64_1 + XXH_PRIME64_4; len -= 8; } if (len >= 4) { - h64 ^= *(uint*)ptr * XXH_PRIME64_1; - ptr += 4; + h64 ^= *(uint*)input * XXH_PRIME64_1; + input += 4; h64 = XXH_rotl64(h64, 23) * XXH_PRIME64_2 + XXH_PRIME64_3; len -= 4; } while (len > 0) { - h64 ^= (*ptr++) * XXH_PRIME64_5; + h64 ^= (*input++) * XXH_PRIME64_5; h64 = XXH_rotl64(h64, 11) * XXH_PRIME64_1; --len; } @@ -247,5 +124,129 @@ public partial class xxHash64 return h64; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static unsafe void __inline__XXH64_stream_process(byte[] input, int len, ref ulong v1, ref ulong v2, ref ulong v3, + ref ulong v4) + { + fixed (byte* pData = &input[0]) + { + byte* ptr = pData; + byte* limit = ptr + len; + + do + { + var reg1 = *((ulong*)(ptr + 0)); + var reg2 = *((ulong*)(ptr + 8)); + var reg3 = *((ulong*)(ptr + 16)); + var reg4 = *((ulong*)(ptr + 24)); + + // XXH64_round + v1 += reg1 * XXH_PRIME64_2; + v1 = (v1 << 31) | (v1 >> (64 - 31)); + v1 *= XXH_PRIME64_1; + + // XXH64_round + v2 += reg2 * XXH_PRIME64_2; + v2 = (v2 << 31) | (v2 >> (64 - 31)); + v2 *= XXH_PRIME64_1; + + // XXH64_round + v3 += reg3 * XXH_PRIME64_2; + v3 = (v3 << 31) | (v3 >> (64 - 31)); + v3 *= XXH_PRIME64_1; + + // XXH64_round + v4 += reg4 * XXH_PRIME64_2; + v4 = (v4 << 31) | (v4 >> (64 - 31)); + v4 *= XXH_PRIME64_1; + ptr += 32; + } while (ptr < limit); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static unsafe ulong __inline__XXH64_stream_finalize(byte[] input, int len, ref ulong v1, ref ulong v2, ref ulong v3, + ref ulong v4, long length, ulong seed) + { + fixed (byte* pData = &input[0]) + { + byte* ptr = pData; + byte* end = pData + len; + ulong h64; + + if (length >= 32) + { + h64 = ((v1 << 1) | (v1 >> (64 - 1))) + + ((v2 << 7) | (v2 >> (64 - 7))) + + ((v3 << 12) | (v3 >> (64 - 12))) + + ((v4 << 18) | (v4 >> (64 - 18))); + + // XXH64_mergeRound + v1 *= XXH_PRIME64_2; + v1 = (v1 << 31) | (v1 >> (64 - 31)); + v1 *= XXH_PRIME64_1; + h64 ^= v1; + h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4; + + // XXH64_mergeRound + v2 *= XXH_PRIME64_2; + v2 = (v2 << 31) | (v2 >> (64 - 31)); + v2 *= XXH_PRIME64_1; + h64 ^= v2; + h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4; + + // XXH64_mergeRound + v3 *= XXH_PRIME64_2; + v3 = (v3 << 31) | (v3 >> (64 - 31)); + v3 *= XXH_PRIME64_1; + h64 ^= v3; + h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4; + + // XXH64_mergeRound + v4 *= XXH_PRIME64_2; + v4 = (v4 << 31) | (v4 >> (64 - 31)); + v4 *= XXH_PRIME64_1; + h64 ^= v4; + h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4; + } + else + { + h64 = seed + XXH_PRIME64_5; + } + + h64 += (ulong) length; + + // XXH64_finalize + len &= 31; + while (len >= 8) { + ulong k1 = XXH64_round(0, *(ulong*)ptr); + ptr += 8; + h64 ^= k1; + h64 = XXH_rotl64(h64,27) * XXH_PRIME64_1 + XXH_PRIME64_4; + len -= 8; + } + if (len >= 4) { + h64 ^= *(uint*)ptr * XXH_PRIME64_1; + ptr += 4; + h64 = XXH_rotl64(h64, 23) * XXH_PRIME64_2 + XXH_PRIME64_3; + len -= 4; + } + while (len > 0) { + h64 ^= (*ptr++) * XXH_PRIME64_5; + h64 = XXH_rotl64(h64, 11) * XXH_PRIME64_1; + --len; + } + + // XXH64_avalanche + h64 ^= h64 >> 33; + h64 *= XXH_PRIME64_2; + h64 ^= h64 >> 29; + h64 *= XXH_PRIME64_3; + h64 ^= h64 >> 32; + + return h64; + } + } } } \ No newline at end of file diff --git a/src/Standart.Hash.xxHash/xxHash32.XXH.cs b/src/Standart.Hash.xxHash/xxHash32.XXH.cs index 34319dd..631fd74 100644 --- a/src/Standart.Hash.xxHash/xxHash32.XXH.cs +++ b/src/Standart.Hash.xxHash/xxHash32.XXH.cs @@ -2,19 +2,20 @@ using System.Runtime.CompilerServices; -namespace Standart.Hash.xxHash; - -public static partial class xxHash32 +namespace Standart.Hash.xxHash { - private static readonly uint XXH_PRIME32_1 = 2654435761U; - private static readonly uint XXH_PRIME32_2 = 2246822519U; - private static readonly uint XXH_PRIME32_3 = 3266489917U; - private static readonly uint XXH_PRIME32_4 = 668265263U; - private static readonly uint XXH_PRIME32_5 = 374761393U; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint XXH_rotl32(uint x, int r) + public static partial class xxHash32 { - return (x << r) | (x >> (32 - r)); - } -} \ No newline at end of file + private static readonly uint XXH_PRIME32_1 = 2654435761U; + private static readonly uint XXH_PRIME32_2 = 2246822519U; + private static readonly uint XXH_PRIME32_3 = 3266489917U; + private static readonly uint XXH_PRIME32_4 = 668265263U; + private static readonly uint XXH_PRIME32_5 = 374761393U; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint XXH_rotl32(uint x, int r) + { + return (x << r) | (x >> (32 - r)); + } + } +} diff --git a/src/Standart.Hash.xxHash/xxHash32.cs b/src/Standart.Hash.xxHash/xxHash32.cs index 3fcb6f1..e0c4653 100644 --- a/src/Standart.Hash.xxHash/xxHash32.cs +++ b/src/Standart.Hash.xxHash/xxHash32.cs @@ -9,256 +9,257 @@ using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; -namespace Standart.Hash.xxHash; - -public static partial class xxHash32 +namespace Standart.Hash.xxHash { - /// - /// Compute xxHash for the data byte array - /// - /// The source of data - /// The length of the data for hashing - /// The seed number - /// hash - public static unsafe uint ComputeHash(byte[] data, int length, uint seed = 0) + public static partial class xxHash32 { - Debug.Assert(data != null); - Debug.Assert(length >= 0); - Debug.Assert(length <= data.Length); - - fixed (byte* pData = &data[0]) + /// + /// Compute xxHash for the data byte array + /// + /// The source of data + /// The length of the data for hashing + /// The seed number + /// hash + public static unsafe uint ComputeHash(byte[] data, int length, uint seed = 0) { - return UnsafeComputeHash(pData, length, seed); - } - } + Debug.Assert(data != null); + Debug.Assert(length >= 0); + Debug.Assert(length <= data.Length); - /// - /// Compute xxHash for the data byte array - /// - /// The source of data - /// The offset of the data for hashing - /// The length of the data for hashing - /// The seed number - /// hash - public static unsafe uint ComputeHash(byte[] data, int offset, int length, uint seed = 0) - { - Debug.Assert(data != null); - Debug.Assert(length >= 0); - Debug.Assert(offset < data.Length); - Debug.Assert(length <= data.Length - offset); - - fixed (byte* pData = &data[0 + offset]) - { - return UnsafeComputeHash(pData, length, seed); - } - } - - /// - /// Compute xxHash for the data byte array - /// - /// The source of data - /// The seed number - /// hash - public static ulong ComputeHash(ArraySegment data, uint seed = 0) - { - Debug.Assert(data != null); - - return ComputeHash(data.Array, data.Offset, data.Count, seed); - } - - /// - /// Compute xxHash for the async stream - /// - /// The stream of data - /// The buffer size - /// The seed number - /// The hash - public static async ValueTask ComputeHashAsync(Stream stream, int bufferSize = 4096, uint seed = 0) - { - return await ComputeHashAsync(stream, bufferSize, seed, CancellationToken.None); - } - - /// - /// Compute xxHash for the async stream - /// - /// The stream of data - /// The buffer size - /// The seed number - /// The cancellation token - /// The hash - public static async ValueTask ComputeHashAsync(Stream stream, int bufferSize, uint seed, CancellationToken cancellationToken) - { - Debug.Assert(stream != null); - Debug.Assert(bufferSize > 16); - - // Optimizing memory allocation - byte[] buffer = ArrayPool.Shared.Rent(bufferSize + 16); - - int readBytes; - int offset = 0; - long length = 0; - - // Prepare the seed vector - uint v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2; - uint v2 = seed + XXH_PRIME32_2; - uint v3 = seed + 0; - uint v4 = seed - XXH_PRIME32_1; - - try - { - // Read flow of bytes - while ((readBytes = - await stream.ReadAsync(buffer, offset, bufferSize, cancellationToken).ConfigureAwait(false)) > 0) + fixed (byte* pData = &data[0]) { - length = length + readBytes; - offset = offset + readBytes; - - if (offset < 16) continue; - - int r = offset % 16; // remain - int l = offset - r; // length - - // Process the next chunk - __inline__XXH32_stream_process(buffer, l, ref v1, ref v2, ref v3, ref v4); - - // Put remaining bytes to buffer - Utils.BlockCopy(buffer, l, buffer, 0, r); - offset = r; + return UnsafeComputeHash(pData, length, seed); } - - // Process the final chunk - uint h32 = __inline__XXH32_stream_finalize(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed); - - return h32; } - finally + + /// + /// Compute xxHash for the data byte array + /// + /// The source of data + /// The offset of the data for hashing + /// The length of the data for hashing + /// The seed number + /// hash + public static unsafe uint ComputeHash(byte[] data, int offset, int length, uint seed = 0) { - // Free memory - ArrayPool.Shared.Return(buffer); - } - } + Debug.Assert(data != null); + Debug.Assert(length >= 0); + Debug.Assert(offset < data.Length); + Debug.Assert(length <= data.Length - offset); - /// - /// Compute xxHash for the data byte span - /// - /// The source of data - /// The length of the data for hashing - /// The seed number - /// hash - public static unsafe uint ComputeHash(Span data, int length, uint seed = 0) - { - Debug.Assert(data != null); - Debug.Assert(length >= 0); - Debug.Assert(length <= data.Length); - - fixed (byte* pData = &MemoryMarshal.GetReference(data)) - { - return UnsafeComputeHash(pData, length, seed); - } - } - - /// - /// Compute xxHash for the data byte span - /// - /// The source of data - /// The length of the data for hashing - /// The seed number - /// hash - public static unsafe uint ComputeHash(ReadOnlySpan data, int length, uint seed = 0) - { - Debug.Assert(data != null); - Debug.Assert(length >= 0); - Debug.Assert(length <= data.Length); - - fixed (byte* pData = &MemoryMarshal.GetReference(data)) - { - return UnsafeComputeHash(pData, length, seed); - } - } - - /// - /// 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) - { - Debug.Assert(stream != null); - Debug.Assert(bufferSize > 16); - - // Optimizing memory allocation - byte[] buffer = ArrayPool.Shared.Rent(bufferSize + 16); - - int readBytes; - int offset = 0; - long length = 0; - - // Prepare the seed vector - uint v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2; - uint v2 = seed + XXH_PRIME32_2; - uint v3 = seed + 0; - uint v4 = seed - XXH_PRIME32_1; - - try - { - // Read flow of bytes - while ((readBytes = stream.Read(buffer, offset, bufferSize)) > 0) + fixed (byte* pData = &data[0 + offset]) { - length = length + readBytes; - offset = offset + readBytes; - - if (offset < 16) continue; - - int r = offset % 16; // remain - int l = offset - r; // length - - // Process the next chunk - __inline__XXH32_stream_process(buffer, l, ref v1, ref v2, ref v3, ref v4); - - // Put remaining bytes to buffer - Utils.BlockCopy(buffer, l, buffer, 0, r); - offset = r; + return UnsafeComputeHash(pData, length, seed); } - - // Process the last chunk - uint h32 = __inline__XXH32_stream_finalize(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed); - - return h32; } - finally + + /// + /// Compute xxHash for the data byte array + /// + /// The source of data + /// The seed number + /// hash + public static ulong ComputeHash(ArraySegment data, uint seed = 0) { - // Free memory - ArrayPool.Shared.Return(buffer); + Debug.Assert(data != null); + + return ComputeHash(data.Array, data.Offset, data.Count, seed); } - } - /// - /// Compute xxHash for the string - /// - /// The source of data - /// The seed number - /// hash - public static unsafe uint ComputeHash(string str, uint seed = 0) - { - Debug.Assert(str != null); - - fixed (char* c = str) + /// + /// Compute xxHash for the async stream + /// + /// The stream of data + /// The buffer size + /// The seed number + /// The hash + public static async ValueTask ComputeHashAsync(Stream stream, int bufferSize = 4096, uint seed = 0) { - byte* ptr = (byte*) c; - int length = str.Length * 2; - - return UnsafeComputeHash(ptr, length, seed); + return await ComputeHashAsync(stream, bufferSize, seed, CancellationToken.None); } - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe uint UnsafeComputeHash(byte* ptr, int length, uint seed) - { - // Use inlined version - // return XXH32(ptr, length, seed); - - return __inline__XXH32(ptr, length, seed); + /// + /// Compute xxHash for the async stream + /// + /// The stream of data + /// The buffer size + /// The seed number + /// The cancellation token + /// The hash + public static async ValueTask ComputeHashAsync(Stream stream, int bufferSize, uint seed, CancellationToken cancellationToken) + { + Debug.Assert(stream != null); + Debug.Assert(bufferSize > 16); + + // Optimizing memory allocation + byte[] buffer = ArrayPool.Shared.Rent(bufferSize + 16); + + int readBytes; + int offset = 0; + long length = 0; + + // Prepare the seed vector + uint v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2; + uint v2 = seed + XXH_PRIME32_2; + uint v3 = seed + 0; + uint v4 = seed - XXH_PRIME32_1; + + try + { + // Read flow of bytes + while ((readBytes = + await stream.ReadAsync(buffer, offset, bufferSize, cancellationToken).ConfigureAwait(false)) > 0) + { + length = length + readBytes; + offset = offset + readBytes; + + if (offset < 16) continue; + + int r = offset % 16; // remain + int l = offset - r; // length + + // Process the next chunk + __inline__XXH32_stream_process(buffer, l, ref v1, ref v2, ref v3, ref v4); + + // Put remaining bytes to buffer + Utils.BlockCopy(buffer, l, buffer, 0, r); + offset = r; + } + + // Process the final chunk + uint h32 = __inline__XXH32_stream_finalize(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed); + + return h32; + } + finally + { + // Free memory + ArrayPool.Shared.Return(buffer); + } + } + + /// + /// Compute xxHash for the data byte span + /// + /// The source of data + /// The length of the data for hashing + /// The seed number + /// hash + public static unsafe uint ComputeHash(Span data, int length, uint seed = 0) + { + Debug.Assert(data != null); + Debug.Assert(length >= 0); + Debug.Assert(length <= data.Length); + + fixed (byte* pData = &MemoryMarshal.GetReference(data)) + { + return UnsafeComputeHash(pData, length, seed); + } + } + + /// + /// Compute xxHash for the data byte span + /// + /// The source of data + /// The length of the data for hashing + /// The seed number + /// hash + public static unsafe uint ComputeHash(ReadOnlySpan data, int length, uint seed = 0) + { + Debug.Assert(data != null); + Debug.Assert(length >= 0); + Debug.Assert(length <= data.Length); + + fixed (byte* pData = &MemoryMarshal.GetReference(data)) + { + return UnsafeComputeHash(pData, length, seed); + } + } + + /// + /// 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) + { + Debug.Assert(stream != null); + Debug.Assert(bufferSize > 16); + + // Optimizing memory allocation + byte[] buffer = ArrayPool.Shared.Rent(bufferSize + 16); + + int readBytes; + int offset = 0; + long length = 0; + + // Prepare the seed vector + uint v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2; + uint v2 = seed + XXH_PRIME32_2; + uint v3 = seed + 0; + uint v4 = seed - XXH_PRIME32_1; + + try + { + // Read flow of bytes + while ((readBytes = stream.Read(buffer, offset, bufferSize)) > 0) + { + length = length + readBytes; + offset = offset + readBytes; + + if (offset < 16) continue; + + int r = offset % 16; // remain + int l = offset - r; // length + + // Process the next chunk + __inline__XXH32_stream_process(buffer, l, ref v1, ref v2, ref v3, ref v4); + + // Put remaining bytes to buffer + Utils.BlockCopy(buffer, l, buffer, 0, r); + offset = r; + } + + // Process the last chunk + uint h32 = __inline__XXH32_stream_finalize(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed); + + return h32; + } + finally + { + // Free memory + ArrayPool.Shared.Return(buffer); + } + } + + /// + /// Compute xxHash for the string + /// + /// The source of data + /// The seed number + /// hash + public static unsafe uint ComputeHash(string str, uint seed = 0) + { + Debug.Assert(str != null); + + fixed (char* c = str) + { + byte* ptr = (byte*) c; + int length = str.Length * 2; + + return UnsafeComputeHash(ptr, length, seed); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static unsafe uint UnsafeComputeHash(byte* ptr, int length, uint seed) + { + // Use inlined version + // return XXH32(ptr, length, seed); + + return __inline__XXH32(ptr, length, seed); + } } } \ No newline at end of file diff --git a/src/Standart.Hash.xxHash/xxHash64.XXH.cs b/src/Standart.Hash.xxHash/xxHash64.XXH.cs index b7328c1..dafbed8 100644 --- a/src/Standart.Hash.xxHash/xxHash64.XXH.cs +++ b/src/Standart.Hash.xxHash/xxHash64.XXH.cs @@ -2,19 +2,20 @@ using System.Runtime.CompilerServices; -namespace Standart.Hash.xxHash; - -public static partial class xxHash64 +namespace Standart.Hash.xxHash { - private static readonly ulong XXH_PRIME64_1 = 11400714785074694791UL; - private static readonly ulong XXH_PRIME64_2 = 14029467366897019727UL; - private static readonly ulong XXH_PRIME64_3 = 1609587929392839161UL; - private static readonly ulong XXH_PRIME64_4 = 9650029242287828579UL; - private static readonly ulong XXH_PRIME64_5 = 2870177450012600261UL; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ulong XXH_rotl64(ulong x, int r) + public static partial class xxHash64 { - return (x << r) | (x >> (64 - r)); - } -} \ No newline at end of file + private static readonly ulong XXH_PRIME64_1 = 11400714785074694791UL; + private static readonly ulong XXH_PRIME64_2 = 14029467366897019727UL; + private static readonly ulong XXH_PRIME64_3 = 1609587929392839161UL; + private static readonly ulong XXH_PRIME64_4 = 9650029242287828579UL; + private static readonly ulong XXH_PRIME64_5 = 2870177450012600261UL; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ulong XXH_rotl64(ulong x, int r) + { + return (x << r) | (x >> (64 - r)); + } + } +} diff --git a/src/Standart.Hash.xxHash/xxHash64.cs b/src/Standart.Hash.xxHash/xxHash64.cs index 63becdb..08c31dc 100644 --- a/src/Standart.Hash.xxHash/xxHash64.cs +++ b/src/Standart.Hash.xxHash/xxHash64.cs @@ -9,256 +9,258 @@ using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; -namespace Standart.Hash.xxHash; - -public static partial class xxHash64 +namespace Standart.Hash.xxHash { - /// - /// Compute xxHash for the data byte array - /// - /// The source of data - /// The length of the data for hashing - /// The seed number - /// hash - public static unsafe ulong ComputeHash(byte[] data, int length, ulong seed = 0) + public static partial class xxHash64 { - Debug.Assert(data != null); - Debug.Assert(length >= 0); - Debug.Assert(length <= data.Length); - - fixed (byte* pData = &data[0]) + /// + /// Compute xxHash for the data byte array + /// + /// The source of data + /// The length of the data for hashing + /// The seed number + /// hash + public static unsafe ulong ComputeHash(byte[] data, int length, ulong seed = 0) { - return UnsafeComputeHash(pData, length, seed); - } - } + Debug.Assert(data != null); + Debug.Assert(length >= 0); + Debug.Assert(length <= data.Length); - /// - /// Compute xxHash for the data byte array - /// - /// The source of data - /// The length of the data for hashing - /// The seed number - /// hash - public static unsafe ulong ComputeHash(byte[] data, int offset, int length, ulong seed = 0) - { - Debug.Assert(data != null); - Debug.Assert(length >= 0); - Debug.Assert(offset < data.Length); - Debug.Assert(length <= data.Length - offset); - - fixed (byte* pData = &data[0 + offset]) - { - return UnsafeComputeHash(pData, length, seed); - } - } - - /// - /// Compute xxHash for the data byte array - /// - /// The source of data - /// The seed number - /// hash - public static unsafe ulong ComputeHash(System.ArraySegment data, ulong seed = 0) - { - Debug.Assert(data != null); - - return ComputeHash(data.Array, data.Offset, data.Count, seed); - } - - /// - /// Compute xxHash for the async stream - /// - /// The stream of data - /// The buffer size - /// The seed number - /// The hash - public static async ValueTask ComputeHashAsync(Stream stream, int bufferSize = 8192, ulong seed = 0) - { - return await ComputeHashAsync(stream, bufferSize, seed, CancellationToken.None); - } - - /// - /// Compute xxHash for the async stream - /// - /// The stream of data - /// The buffer size - /// The seed number - /// The cancelation token - /// The hash - public static async ValueTask ComputeHashAsync(Stream stream, int bufferSize, ulong seed, - CancellationToken cancellationToken) - { - Debug.Assert(stream != null); - Debug.Assert(bufferSize > 32); - - // Optimizing memory allocation - byte[] buffer = ArrayPool.Shared.Rent(bufferSize + 32); - - int readBytes; - int offset = 0; - long length = 0; - - // Prepare the seed vector - ulong v1 = seed + XXH_PRIME64_1 + XXH_PRIME64_2; - ulong v2 = seed + XXH_PRIME64_2; - ulong v3 = seed + 0; - ulong v4 = seed - XXH_PRIME64_1; - - try - { - // Read flow of bytes - while ((readBytes = - await stream.ReadAsync(buffer, offset, bufferSize, cancellationToken).ConfigureAwait(false)) > 0) + fixed (byte* pData = &data[0]) { - length = length + readBytes; - offset = offset + readBytes; - - if (offset < 32) continue; - - int r = offset % 32; // remain - int l = offset - r; // length - - // Process the next chunk - __inline__XXH64_stream_process(buffer, l, ref v1, ref v2, ref v3, ref v4); - - // Put remaining bytes to buffer - Utils.BlockCopy(buffer, l, buffer, 0, r); - offset = r; + return UnsafeComputeHash(pData, length, seed); } - - // Process the final chunk - ulong h64 = __inline__XXH64_stream_finalize(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed); - - return h64; } - finally + + /// + /// Compute xxHash for the data byte array + /// + /// The source of data + /// The length of the data for hashing + /// The seed number + /// hash + public static unsafe ulong ComputeHash(byte[] data, int offset, int length, ulong seed = 0) { - // Free memory - ArrayPool.Shared.Return(buffer); - } - } + Debug.Assert(data != null); + Debug.Assert(length >= 0); + Debug.Assert(offset < data.Length); + Debug.Assert(length <= data.Length - offset); - /// - /// Compute xxHash for the data byte span - /// - /// The source of data - /// The length of the data for hashing - /// The seed number - /// hash - public static unsafe ulong ComputeHash(Span data, int length, ulong seed = 0) - { - Debug.Assert(data != null); - Debug.Assert(length >= 0); - Debug.Assert(length <= data.Length); - - fixed (byte* pData = &MemoryMarshal.GetReference(data)) - { - return UnsafeComputeHash(pData, length, seed); - } - } - - /// - /// Compute xxHash for the data byte span - /// - /// The source of data - /// The length of the data for hashing - /// The seed number - /// hash - public static unsafe ulong ComputeHash(ReadOnlySpan data, int length, ulong seed = 0) - { - Debug.Assert(data != null); - Debug.Assert(length >= 0); - Debug.Assert(length <= data.Length); - - fixed (byte* pData = &MemoryMarshal.GetReference(data)) - { - return UnsafeComputeHash(pData, length, seed); - } - } - - /// - /// 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) - { - Debug.Assert(stream != null); - Debug.Assert(bufferSize > 32); - - // Optimizing memory allocation - byte[] buffer = ArrayPool.Shared.Rent(bufferSize + 32); - - int readBytes; - int offset = 0; - long length = 0; - - // Prepare the seed vector - ulong v1 = seed + XXH_PRIME64_1 + XXH_PRIME64_2; - ulong v2 = seed + XXH_PRIME64_2; - ulong v3 = seed + 0; - ulong v4 = seed - XXH_PRIME64_1; - - try - { - // Read flow of bytes - while ((readBytes = stream.Read(buffer, offset, bufferSize)) > 0) + fixed (byte* pData = &data[0 + offset]) { - length = length + readBytes; - offset = offset + readBytes; - - if (offset < 32) continue; - - int r = offset % 32; // remain - int l = offset - r; // length - - // Process the next chunk - __inline__XXH64_stream_process(buffer, l, ref v1, ref v2, ref v3, ref v4); - - // Put remaining bytes to buffer - Utils.BlockCopy(buffer, l, buffer, 0, r); - offset = r; + return UnsafeComputeHash(pData, length, seed); } - - // Process the final chunk - ulong h64 = __inline__XXH64_stream_finalize(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed); - - return h64; } - finally + + /// + /// Compute xxHash for the data byte array + /// + /// The source of data + /// The seed number + /// hash + public static unsafe ulong ComputeHash(System.ArraySegment data, ulong seed = 0) { - // Free memory - ArrayPool.Shared.Return(buffer); - } - } - - /// - /// Compute xxHash for the string - /// - /// The source of data - /// The seed number - /// hash - public static unsafe ulong ComputeHash(string str, uint seed = 0) - { - Debug.Assert(str != null); + Debug.Assert(data != null); - fixed (char* c = str) + return ComputeHash(data.Array, data.Offset, data.Count, seed); + } + + /// + /// Compute xxHash for the async stream + /// + /// The stream of data + /// The buffer size + /// The seed number + /// The hash + public static async ValueTask ComputeHashAsync(Stream stream, int bufferSize = 8192, ulong seed = 0) { - byte* ptr = (byte*) c; - int length = str.Length * 2; - - return UnsafeComputeHash(ptr, length, seed); + return await ComputeHashAsync(stream, bufferSize, seed, CancellationToken.None); + } + + /// + /// Compute xxHash for the async stream + /// + /// The stream of data + /// The buffer size + /// The seed number + /// The cancelation token + /// The hash + public static async ValueTask ComputeHashAsync(Stream stream, int bufferSize, ulong seed, + CancellationToken cancellationToken) + { + Debug.Assert(stream != null); + Debug.Assert(bufferSize > 32); + + // Optimizing memory allocation + byte[] buffer = ArrayPool.Shared.Rent(bufferSize + 32); + + int readBytes; + int offset = 0; + long length = 0; + + // Prepare the seed vector + ulong v1 = seed + XXH_PRIME64_1 + XXH_PRIME64_2; + ulong v2 = seed + XXH_PRIME64_2; + ulong v3 = seed + 0; + ulong v4 = seed - XXH_PRIME64_1; + + try + { + // Read flow of bytes + while ((readBytes = + await stream.ReadAsync(buffer, offset, bufferSize, cancellationToken).ConfigureAwait(false)) > 0) + { + length = length + readBytes; + offset = offset + readBytes; + + if (offset < 32) continue; + + int r = offset % 32; // remain + int l = offset - r; // length + + // Process the next chunk + __inline__XXH64_stream_process(buffer, l, ref v1, ref v2, ref v3, ref v4); + + // Put remaining bytes to buffer + Utils.BlockCopy(buffer, l, buffer, 0, r); + offset = r; + } + + // Process the final chunk + ulong h64 = __inline__XXH64_stream_finalize(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed); + + return h64; + } + finally + { + // Free memory + ArrayPool.Shared.Return(buffer); + } + } + + /// + /// Compute xxHash for the data byte span + /// + /// The source of data + /// The length of the data for hashing + /// The seed number + /// hash + public static unsafe ulong ComputeHash(Span data, int length, ulong seed = 0) + { + Debug.Assert(data != null); + Debug.Assert(length >= 0); + Debug.Assert(length <= data.Length); + + fixed (byte* pData = &MemoryMarshal.GetReference(data)) + { + return UnsafeComputeHash(pData, length, seed); + } + } + + /// + /// Compute xxHash for the data byte span + /// + /// The source of data + /// The length of the data for hashing + /// The seed number + /// hash + public static unsafe ulong ComputeHash(ReadOnlySpan data, int length, ulong seed = 0) + { + Debug.Assert(data != null); + Debug.Assert(length >= 0); + Debug.Assert(length <= data.Length); + + fixed (byte* pData = &MemoryMarshal.GetReference(data)) + { + return UnsafeComputeHash(pData, length, seed); + } + } + + /// + /// 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) + { + Debug.Assert(stream != null); + Debug.Assert(bufferSize > 32); + + // Optimizing memory allocation + byte[] buffer = ArrayPool.Shared.Rent(bufferSize + 32); + + int readBytes; + int offset = 0; + long length = 0; + + // Prepare the seed vector + ulong v1 = seed + XXH_PRIME64_1 + XXH_PRIME64_2; + ulong v2 = seed + XXH_PRIME64_2; + ulong v3 = seed + 0; + ulong v4 = seed - XXH_PRIME64_1; + + try + { + // Read flow of bytes + while ((readBytes = stream.Read(buffer, offset, bufferSize)) > 0) + { + length = length + readBytes; + offset = offset + readBytes; + + if (offset < 32) continue; + + int r = offset % 32; // remain + int l = offset - r; // length + + // Process the next chunk + __inline__XXH64_stream_process(buffer, l, ref v1, ref v2, ref v3, ref v4); + + // Put remaining bytes to buffer + Utils.BlockCopy(buffer, l, buffer, 0, r); + offset = r; + } + + // Process the final chunk + ulong h64 = __inline__XXH64_stream_finalize(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed); + + return h64; + } + finally + { + // Free memory + ArrayPool.Shared.Return(buffer); + } } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe ulong UnsafeComputeHash(byte* ptr, int length, ulong seed) - { - // Use inlined version - // return XXH64(ptr, length, seed); - return __inline__XXH64(ptr, length, seed); - } -} \ No newline at end of file + /// + /// Compute xxHash for the string + /// + /// The source of data + /// The seed number + /// hash + public static unsafe ulong ComputeHash(string str, uint seed = 0) + { + Debug.Assert(str != null); + + fixed (char* c = str) + { + byte* ptr = (byte*) c; + int length = str.Length * 2; + + return UnsafeComputeHash(ptr, length, seed); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static unsafe ulong UnsafeComputeHash(byte* ptr, int length, ulong seed) + { + // Use inlined version + // return XXH64(ptr, length, seed); + + return __inline__XXH64(ptr, length, seed); + } + } +} +