diff --git a/src/Standart.Hash.xxHash/xxHash128.__inline.cs b/src/Standart.Hash.xxHash/__inline__xxHash128.cs similarity index 99% rename from src/Standart.Hash.xxHash/xxHash128.__inline.cs rename to src/Standart.Hash.xxHash/__inline__xxHash128.cs index b515180..46ddbf4 100644 --- a/src/Standart.Hash.xxHash/xxHash128.__inline.cs +++ b/src/Standart.Hash.xxHash/__inline__xxHash128.cs @@ -13,7 +13,7 @@ namespace Standart.Hash.xxHash; public static partial class xxHash128 { [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe uint128 __XXH3_128bits_internal(byte* input, int len, ulong seed, byte* secret, int secretLen) + private static unsafe uint128 __inline__XXH3_128bits_internal(byte* input, int len, ulong seed, byte* secret, int secretLen) { if (len <= 16) { diff --git a/src/Standart.Hash.xxHash/__inline__xxHash32.cs b/src/Standart.Hash.xxHash/__inline__xxHash32.cs new file mode 100644 index 0000000..381fb93 --- /dev/null +++ b/src/Standart.Hash.xxHash/__inline__xxHash32.cs @@ -0,0 +1,183 @@ +/* +* This is the auto generated code. +* All function calls are inlined in XXH32 +* Please don't try to analyze it. +*/ + +using System.Runtime.CompilerServices; + +namespace Standart.Hash.xxHash; + +public partial class xxHash32 +{ + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static unsafe uint __inline__XXH32(byte* input, int len, uint seed) + { + uint h32; + + if (len >= 16) + { + 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 + { + // XXH32_round + v1 += *((uint*) input) * XXH_PRIME32_2; + v1 = (v1 << 13) | (v1 >> (32 - 13)); + v1 *= XXH_PRIME32_1; + input += 4; + + // XXH32_round + v2 += *((uint*) input) * XXH_PRIME32_2; + v2 = (v2 << 13) | (v2 >> (32 - 13)); + v2 *= XXH_PRIME32_1; + input += 4; + + // XXH32_round + v3 += *((uint*) input) * XXH_PRIME32_2; + v3 = (v3 << 13) | (v3 >> (32 - 13)); + v3 *= XXH_PRIME32_1; + input += 4; + + // XXH32_round + v4 += *((uint*) input) * XXH_PRIME32_2; + v4 = (v4 << 13) | (v4 >> (32 - 13)); + v4 *= XXH_PRIME32_1; + input += 4; + } 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 + { + // XXH32_round + v1 += *((uint*)ptr) * XXH_PRIME32_2; + v1 = (v1 << 13) | (v1 >> (32 - 13)); + v1 *= XXH_PRIME32_1; + ptr += 4; + + // XXH32_round + v2 += *((uint*)ptr) * XXH_PRIME32_2; + v2 = (v2 << 13) | (v2 >> (32 - 13)); + v2 *= XXH_PRIME32_1; + ptr += 4; + + // XXH32_round + v3 += *((uint*)ptr) * XXH_PRIME32_2; + v3 = (v3 << 13) | (v3 >> (32 - 13)); + v3 *= XXH_PRIME32_1; + ptr += 4; + + // XXH32_round + v4 += *((uint*)ptr) * XXH_PRIME32_2; + v4 = (v4 << 13) | (v4 >> (32 - 13)); + v4 *= XXH_PRIME32_1; + ptr += 4; + + } 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; + } + } +} \ No newline at end of file diff --git a/src/Standart.Hash.xxHash/xxHash128.cs b/src/Standart.Hash.xxHash/xxHash128.cs index c6b7f97..d1832a4 100644 --- a/src/Standart.Hash.xxHash/xxHash128.cs +++ b/src/Standart.Hash.xxHash/xxHash128.cs @@ -166,7 +166,10 @@ namespace Standart.Hash.xxHash { fixed (byte* secret = &XXH3_SECRET[0]) { - return __XXH3_128bits_internal(input, len, seed, secret, XXH3_SECRET_DEFAULT_SIZE); + // Use inlined version + // return XXH3_128bits_internal(input, len, seed, secret, XXH3_SECRET_DEFAULT_SIZE); + + return __inline__XXH3_128bits_internal(input, len, seed, secret, XXH3_SECRET_DEFAULT_SIZE); } } } diff --git a/src/Standart.Hash.xxHash/xxHash32.XXH32.cs b/src/Standart.Hash.xxHash/xxHash32.XXH32.cs index f9b950f..1ca5c9c 100644 --- a/src/Standart.Hash.xxHash/xxHash32.XXH32.cs +++ b/src/Standart.Hash.xxHash/xxHash32.XXH32.cs @@ -7,14 +7,14 @@ namespace Standart.Hash.xxHash public static partial class xxHash32 { [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe uint XXH32_internal(byte* input, int len, uint seed) + private static unsafe uint XXH32(byte* input, int len, uint seed) { - byte* end = input + len; uint h32; if (len >= 16) { - byte* limit = end - 16; + byte* end = input + len; + byte* limit = end - 15; uint v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2; uint v2 = seed + XXH_PRIME32_2; @@ -23,31 +23,11 @@ namespace Standart.Hash.xxHash do { - // XXH32_round - v1 += *((uint*)input) * XXH_PRIME32_2; - v1 = XXH_rotl32(v1, 13); - v1 *= XXH_PRIME32_1; - input += 4; - - // XXH32_round - v2 += *((uint*)input) * XXH_PRIME32_2; - v2 = XXH_rotl32(v2, 13); - v2 *= XXH_PRIME32_1; - input += 4; - - // XXH32_round - v3 += *((uint*)input) * XXH_PRIME32_2; - v3 = XXH_rotl32(v3, 13); - v3 *= XXH_PRIME32_1; - input += 4; - - // XXH32_round - v4 += *((uint*)input) * XXH_PRIME32_2; - v4 = XXH_rotl32(v4, 13); - v4 *= XXH_PRIME32_1; - input += 4; - - } while (input <= limit); + v1 = XXH32_round(v1, *(uint*) input); input += 4; + v2 = XXH32_round(v2, *(uint*) input); input += 4; + v3 = XXH32_round(v3, *(uint*) input); input += 4; + v4 = XXH32_round(v4, *(uint*) input); input += 4; + } while (input < limit); h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + @@ -61,116 +41,50 @@ namespace Standart.Hash.xxHash h32 += (uint)len; - // XXH32_finalize - while (input <= end - 4) - { - h32 += *((uint*)input) * XXH_PRIME32_3; - h32 = XXH_rotl32(h32, 17) * XXH_PRIME32_4; - input += 4; - } - - while (input < end) - { - h32 += *((byte*)input) * XXH_PRIME32_5; - h32 = XXH_rotl32(h32, 11) * XXH_PRIME32_1; - input += 1; - } - - // XXH32_avalanche - h32 ^= h32 >> 15; - h32 *= XXH_PRIME32_2; - h32 ^= h32 >> 13; - h32 *= XXH_PRIME32_3; - h32 ^= h32 >> 16; - - return h32; + return XXH32_finalize(h32, input, len); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe void __XXH32_stream_align(byte[] input, int len, ref uint v1, ref uint v2, ref uint v3, ref uint v4) + private static uint XXH32_round(uint acc, uint input) { - fixed (byte* pData = &input[0]) - { - byte* ptr = pData; - byte* limit = ptr + len; - - do - { - // XXH32_round - v1 += *((uint*)ptr) * XXH_PRIME32_2; - v1 = XXH_rotl32(v1, 13); - v1 *= XXH_PRIME32_1; - ptr += 4; - - // XXH32_round - v2 += *((uint*)ptr) * XXH_PRIME32_2; - v2 = XXH_rotl32(v2, 13); - v2 *= XXH_PRIME32_1; - ptr += 4; - - // XXH32_round - v3 += *((uint*)ptr) * XXH_PRIME32_2; - v3 = XXH_rotl32(v3, 13); - v3 *= XXH_PRIME32_1; - ptr += 4; - - // XXH32_round - v4 += *((uint*)ptr) * XXH_PRIME32_2; - v4 = XXH_rotl32(v4, 13); - v4 *= XXH_PRIME32_1; - ptr += 4; - - } while (ptr < limit); - } + acc += input * XXH_PRIME32_2; + acc = XXH_rotl32(acc, 13); + acc *= XXH_PRIME32_1; + return acc; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe uint __XXH32_stream_finalize(byte[] input, int len, ref uint v1, ref uint v2, ref uint v3, ref uint v4, long length, uint seed) + private static uint XXH32_avalanche(uint hash) { - fixed (byte* pData = &input[0]) + hash ^= hash >> 15; + hash *= XXH_PRIME32_2; + hash ^= hash >> 13; + hash *= XXH_PRIME32_3; + hash ^= hash >> 16; + return hash; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static unsafe uint XXH32_finalize(uint hash, byte* ptr, int len) + { + len &= 15; + while (len >= 4) { - byte* ptr = pData; - byte* end = pData + len; - uint h32; - - if (length >= 16) - { - h32 = XXH_rotl32(v1, 1) + - XXH_rotl32(v2, 7) + - XXH_rotl32(v3, 12) + - XXH_rotl32(v4, 18); - } - else - { - h32 = seed + XXH_PRIME32_5; - } - - h32 += (uint)length; - - // XXH32_finalize - while (ptr <= end - 4) - { - h32 += *((uint*)ptr) * XXH_PRIME32_3; - h32 = XXH_rotl32(h32, 17) * XXH_PRIME32_4; - ptr += 4; - } - - while (ptr < end) - { - h32 += *((byte*)ptr) * XXH_PRIME32_5; - h32 = XXH_rotl32(h32, 11) * XXH_PRIME32_1; - ptr += 1; - } - - // XXH32_avalanche - h32 ^= h32 >> 15; - h32 *= XXH_PRIME32_2; - h32 ^= h32 >> 13; - h32 *= XXH_PRIME32_3; - h32 ^= h32 >> 16; - - return h32; + hash += *((uint*)ptr) * XXH_PRIME32_3; + ptr += 4; + hash = XXH_rotl32(hash, 17) * XXH_PRIME32_4; + len -= 4; } + + while (len > 0) + { + hash += *((byte*)ptr) * XXH_PRIME32_5; + ptr++; + hash = XXH_rotl32(hash, 11) * XXH_PRIME32_1; + len--; + } + + return XXH32_avalanche(hash); } } } \ No newline at end of file diff --git a/src/Standart.Hash.xxHash/xxHash32.cs b/src/Standart.Hash.xxHash/xxHash32.cs index 78248d5..3fcb6f1 100644 --- a/src/Standart.Hash.xxHash/xxHash32.cs +++ b/src/Standart.Hash.xxHash/xxHash32.cs @@ -86,8 +86,7 @@ public static partial class xxHash32 /// The seed number /// The cancellation token /// The hash - public static async ValueTask ComputeHashAsync(Stream stream, int bufferSize, uint seed, - CancellationToken cancellationToken) + public static async ValueTask ComputeHashAsync(Stream stream, int bufferSize, uint seed, CancellationToken cancellationToken) { Debug.Assert(stream != null); Debug.Assert(bufferSize > 16); @@ -120,7 +119,7 @@ public static partial class xxHash32 int l = offset - r; // length // Process the next chunk - __XXH32_stream_align(buffer, l, ref v1, ref v2, ref v3, ref v4); + __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); @@ -128,7 +127,7 @@ public static partial class xxHash32 } // Process the final chunk - uint h32 = __XXH32_stream_finalize(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed); + uint h32 = __inline__XXH32_stream_finalize(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed); return h32; } @@ -216,7 +215,7 @@ public static partial class xxHash32 int l = offset - r; // length // Process the next chunk - __XXH32_stream_align(buffer, l, ref v1, ref v2, ref v3, ref v4); + __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); @@ -224,7 +223,7 @@ public static partial class xxHash32 } // Process the last chunk - uint h32 = __XXH32_stream_finalize(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed); + uint h32 = __inline__XXH32_stream_finalize(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed); return h32; } @@ -257,6 +256,9 @@ public static partial class xxHash32 [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe uint UnsafeComputeHash(byte* ptr, int length, uint seed) { - return XXH32_internal(ptr, length, seed); + // Use inlined version + // return XXH32(ptr, length, seed); + + return __inline__XXH32(ptr, length, seed); } } \ No newline at end of file