diff --git a/src/Arch.Benchmarks/HashCodeBenchmark.cs b/src/Arch.Benchmarks/HashCodeBenchmark.cs deleted file mode 100644 index c2cd47b7..00000000 --- a/src/Arch.Benchmarks/HashCodeBenchmark.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Arch.Core.Utils; - -namespace Arch.Benchmarks; - -[HtmlExporter] -public class HashCodeBenchmark -{ - private byte[]? _bytes; - - [Params(1000, 10000)] - public int N; - - [GlobalSetup] - public void Setup() - { - _bytes = new byte[N]; - new Random(42).NextBytes(_bytes); - } - - [Benchmark] - public uint MurmurHash() - { - return MurmurHash3.Hash32(_bytes!, 7); - } - - [Benchmark] - public uint HashCode() - { - var c = new HashCode(); - c.AddBytes(_bytes!); - return unchecked((uint)c.ToHashCode()); - } -} diff --git a/src/Arch/Core/Extensions/Internal/HashCodeExtensions.cs b/src/Arch/Core/Extensions/Internal/HashCodeExtensions.cs new file mode 100644 index 00000000..ab8dbd25 --- /dev/null +++ b/src/Arch/Core/Extensions/Internal/HashCodeExtensions.cs @@ -0,0 +1,26 @@ +namespace Arch.Core.Extensions.Internal; + +internal static class HashCodeExtensions +{ +#if !NET5_0_OR_GREATER + public static void AddBytes(ref this HashCode hashCode, ReadOnlySpan bytes) + { + for (int i = 0; i < bytes.Length; i++) + { + hashCode.Add(bytes[i]); + } + } +#endif + + public static void AddSpan(ref this HashCode hashCode, ReadOnlySpan items) + where T : unmanaged + { + hashCode.AddBytes(MemoryMarshal.AsBytes(items)); + } + + public static void AddSpan(ref this HashCode hashCode, Span items) + where T : unmanaged + { + hashCode.AddBytes(MemoryMarshal.AsBytes(items)); + } +} diff --git a/src/Arch/Core/Utils/CompileTimeStatics.cs b/src/Arch/Core/Utils/CompileTimeStatics.cs index cc20ffe8..dfc1abad 100644 --- a/src/Arch/Core/Utils/CompileTimeStatics.cs +++ b/src/Arch/Core/Utils/CompileTimeStatics.cs @@ -455,17 +455,12 @@ public static int GetHashCode(Span obj) return GetHashCode(stack); } - /// - /// Calculates the hash code of a bitset span, which is unique for the elements contained in the array. - /// The order of the elements does not change the hashcode, so it depends on the elements themselves. - /// - /// The . - /// A unique hashcode for the contained elements, regardless of their order. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int GetHashCode(Span span) { - var bytes = MemoryMarshal.AsBytes(span); - return (int)MurmurHash3.Hash32(bytes, 0); + var hashCode = new HashCode(); + hashCode.AddSpan(span); + return hashCode.ToHashCode(); } } diff --git a/src/Arch/Core/Utils/MurmurHash3.cs b/src/Arch/Core/Utils/MurmurHash3.cs deleted file mode 100644 index b690fd36..00000000 --- a/src/Arch/Core/Utils/MurmurHash3.cs +++ /dev/null @@ -1,66 +0,0 @@ -namespace Arch.Core.Utils; - -// From https://github.com/odinmillion/MurmurHash.Net/blob/master/src/MurmurHash.Net/MurmurHash3.cs -/// -/// The class -/// represents a utility to calculate a MurMurHash3 used to map querys and descriptions to archetypes. -/// -public static class MurmurHash3 -{ - /// - /// Calculates the hash as a 32 bit integer and returns it. - /// - /// The of bytes to hash. - /// The seed. - /// The 32 bit integer hash. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static uint Hash32(ReadOnlySpan bytes, uint seed) - { - var length = bytes.Length; - var h1 = seed; - var remainder = length & 3; - var position = length - remainder; - - for (var start = 0; start < position; start += 4) - { - h1 = (uint) ((int) RotateLeft(h1 ^ RotateLeft(BitConverter.ToUInt32(bytes.Slice(start, 4)) * 3432918353U,15) * 461845907U, 13) * 5 - 430675100); - } - - if (remainder > 0) - { - uint num = 0; - switch (remainder) - { - case 1: - num ^= (uint) bytes[position]; - break; - case 2: - num ^= (uint) bytes[position + 1] << 8; - goto case 1; - case 3: - num ^= (uint) bytes[position + 2] << 16; - goto case 2; - } - - h1 ^= RotateLeft(num * 3432918353U, 15) * 461845907U; - } - - h1 = FMix(h1 ^ (uint) length); - - return h1; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint RotateLeft(uint x, byte r) - { - return (x << (int) r) | (x >> (32 - (int) r)); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint FMix(uint h) - { - h = (uint) (((int) h ^ (int) (h >> 16)) * -2048144789); - h = (uint) (((int) h ^ (int) (h >> 13)) * -1028477387); - return h ^ (h >> 16); - } -}