From c079a400a0d6f2034a0442b5a0a5413ff9771dd8 Mon Sep 17 00:00:00 2001 From: Oleksandr Melnyk Date: Fri, 3 Jun 2022 15:02:55 +0300 Subject: [PATCH] Add tests for xxHash128 --- src/Standart.Hash.xxHash.Test/UtilsTest.cs | 45 +++++++ .../xxHash128Test.cs | 113 ++++++++++++++++++ src/Standart.Hash.xxHash.Test/xxHash32Test.cs | 19 ++- src/Standart.Hash.xxHash.Test/xxHash64Test.cs | 18 ++- src/Standart.Hash.xxHash/Utils.cs | 20 +++- src/Standart.Hash.xxHash/xxHash128.cs | 78 +++++++++++- src/Standart.Hash.xxHash/xxHash32.cs | 2 +- src/Standart.Hash.xxHash/xxHash64.cs | 2 +- 8 files changed, 288 insertions(+), 9 deletions(-) create mode 100644 src/Standart.Hash.xxHash.Test/xxHash128Test.cs diff --git a/src/Standart.Hash.xxHash.Test/UtilsTest.cs b/src/Standart.Hash.xxHash.Test/UtilsTest.cs index 8309dd5..7515fcf 100644 --- a/src/Standart.Hash.xxHash.Test/UtilsTest.cs +++ b/src/Standart.Hash.xxHash.Test/UtilsTest.cs @@ -35,5 +35,50 @@ } } } + + [Fact] + public void Should_convert_to_bytes() + { + var hash = new uint128 + { + high64 = 3466251221427321594, + low64 = 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 actual = hash.ToBytes(); + + // Assert + for (int i = 0; i < 16; i++) + Assert.Equal(expected[i], actual[i]); + } + + [Fact] + public void Should_convert_to_guid() + { + var hash = new uint128 + { + high64 = 3466251221427321594, + low64 = 2862260537881727713 + }; + + // Act + var guid1 = new Guid(hash.ToBytes()); + var guid2 = hash.ToGuid(); + + // Assert + Assert.Equal(guid1, guid2); + } } } \ No newline at end of file diff --git a/src/Standart.Hash.xxHash.Test/xxHash128Test.cs b/src/Standart.Hash.xxHash.Test/xxHash128Test.cs new file mode 100644 index 0000000..51d4435 --- /dev/null +++ b/src/Standart.Hash.xxHash.Test/xxHash128Test.cs @@ -0,0 +1,113 @@ +using System; +using System.Text; +using Xunit; + +namespace Standart.Hash.xxHash.Test; + +public class xxHash128Test +{ + [Fact] + public void Compute_hash128_for_bytes() + { + // 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; + + // 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[] + { + 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; + + // 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 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[] + { + 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; + + // (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]); + } + +} \ No newline at end of file diff --git a/src/Standart.Hash.xxHash.Test/xxHash32Test.cs b/src/Standart.Hash.xxHash.Test/xxHash32Test.cs index 8996133..9009649 100644 --- a/src/Standart.Hash.xxHash.Test/xxHash32Test.cs +++ b/src/Standart.Hash.xxHash.Test/xxHash32Test.cs @@ -1,4 +1,6 @@ -namespace Standart.Hash.xxHash.Test +using System.Text; + +namespace Standart.Hash.xxHash.Test { using System; using System.IO; @@ -420,5 +422,20 @@ Assert.Equal(hash1, hash2); } } + + [Fact] + public void Compute_hash32_for_string() + { + // Arrange + var str = "veni vidi vici"; + var bytes = Encoding.Unicode.GetBytes(str); + + // Act + var hash1 = xxHash32.ComputeHash(str); + var hash2 = xxHash32.ComputeHash(bytes, bytes.Length); + + // 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 b8e7b38..eed097b 100644 --- a/src/Standart.Hash.xxHash.Test/xxHash64Test.cs +++ b/src/Standart.Hash.xxHash.Test/xxHash64Test.cs @@ -1,4 +1,6 @@ -namespace Standart.Hash.xxHash.Test +using System.Text; + +namespace Standart.Hash.xxHash.Test { using System; using System.IO; @@ -383,5 +385,19 @@ } } + [Fact] + public void Compute_hash64_for_string() + { + // Arrange + var str = "veni vidi vici"; + var bytes = Encoding.Unicode.GetBytes(str); + + // Act + var hash1 = xxHash64.ComputeHash(str); + var hash2 = xxHash64.ComputeHash(bytes, bytes.Length); + + // Assert + Assert.Equal(hash1, hash2); + } } } \ No newline at end of file diff --git a/src/Standart.Hash.xxHash/Utils.cs b/src/Standart.Hash.xxHash/Utils.cs index 2e78c1f..7168007 100644 --- a/src/Standart.Hash.xxHash/Utils.cs +++ b/src/Standart.Hash.xxHash/Utils.cs @@ -8,16 +8,28 @@ namespace Standart.Hash.xxHash { public static Guid ToGuid(this uint128 value) { - // allocation - return new Guid(value.ToBytes()); + var a = (Int32) (value.low64); + var b = (Int16) (value.low64 >> 32); + var c = (Int16) (value.low64 >> 48); + + var d = (Byte) (value.high64); + var e = (Byte) (value.high64 >> 8); + var f = (Byte) (value.high64 >> 16); + var g = (Byte) (value.high64 >> 24); + var h = (Byte) (value.high64 >> 32); + var i = (Byte) (value.high64 >> 40); + var j = (Byte) (value.high64 >> 48); + var k = (Byte) (value.high64 >> 56); + + return new Guid(a, b, c, d, e, f,g, h, i, j, k); } public static byte[] ToBytes(this uint128 value) { // allocation byte[] bytes = new byte[sizeof(ulong) * 2]; - Unsafe.As(ref bytes[0]) = value.high64; - Unsafe.As(ref bytes[8]) = value.low64; + Unsafe.As(ref bytes[0]) = value.low64; + Unsafe.As(ref bytes[8]) = value.high64; return bytes; } diff --git a/src/Standart.Hash.xxHash/xxHash128.cs b/src/Standart.Hash.xxHash/xxHash128.cs index b072acb..bf6c06d 100644 --- a/src/Standart.Hash.xxHash/xxHash128.cs +++ b/src/Standart.Hash.xxHash/xxHash128.cs @@ -79,12 +79,88 @@ namespace Standart.Hash.xxHash fixed (char* c = str) { byte* ptr = (byte*) c; - int length = str.Length; + int length = str.Length * 2; return UnsafeComputeHash(ptr, length, seed); } } + /// + /// Compute hash bytes for the data byte array + /// + /// The source of data + /// The length of the data for hashing + /// The seed number + /// hash + public static unsafe byte[] ComputeHashBytes(byte[] data, int length, ulong seed = 0) + { + Debug.Assert(data != null); + Debug.Assert(length >= 0); + Debug.Assert(length <= data.Length); + + fixed (byte* ptr = &data[0]) + { + return UnsafeComputeHash(ptr, length, seed).ToBytes(); + } + } + + /// + /// Compute hash bytes for the span + /// + /// The source of data + /// The length of the data for hashing + /// The seed number + /// hash + public static unsafe byte[] ComputeHashBytes(Span data, int length, ulong seed = 0) + { + Debug.Assert(data != null); + Debug.Assert(length >= 0); + Debug.Assert(length <= data.Length); + + fixed (byte* ptr = &data[0]) + { + return UnsafeComputeHash(ptr, length, seed).ToBytes(); + } + } + + /// + /// Compute hash bytes for the data byte span + /// + /// The source of data + /// The length of the data for hashing + /// The seed number + /// hash + public static unsafe byte[] ComputeHashBytes(ReadOnlySpan data, int length, ulong seed = 0) + { + Debug.Assert(data != null); + Debug.Assert(length >= 0); + Debug.Assert(length <= data.Length); + + fixed (byte* ptr = &data[0]) + { + return UnsafeComputeHash(ptr, length, seed).ToBytes(); + } + } + + /// + /// Compute hash bytes for the string + /// + /// The source of data + /// The seed number + /// hash + public static unsafe byte[] ComputeHashBytes(string str, ulong seed = 0) + { + Debug.Assert(str != null); + + fixed (char* c = str) + { + byte* ptr = (byte*) c; + int length = str.Length * 2; + + return UnsafeComputeHash(ptr, length, seed).ToBytes(); + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe uint128 UnsafeComputeHash(byte* input, int len, ulong seed) { diff --git a/src/Standart.Hash.xxHash/xxHash32.cs b/src/Standart.Hash.xxHash/xxHash32.cs index 87e6ace..78248d5 100644 --- a/src/Standart.Hash.xxHash/xxHash32.cs +++ b/src/Standart.Hash.xxHash/xxHash32.cs @@ -248,7 +248,7 @@ public static partial class xxHash32 fixed (char* c = str) { byte* ptr = (byte*) c; - int length = str.Length; + int length = str.Length * 2; return UnsafeComputeHash(ptr, length, seed); } diff --git a/src/Standart.Hash.xxHash/xxHash64.cs b/src/Standart.Hash.xxHash/xxHash64.cs index 074d0cc..693b4bd 100644 --- a/src/Standart.Hash.xxHash/xxHash64.cs +++ b/src/Standart.Hash.xxHash/xxHash64.cs @@ -247,7 +247,7 @@ public static partial class xxHash64 fixed (char* c = str) { byte* ptr = (byte*) c; - int length = str.Length; + int length = str.Length * 2; return UnsafeComputeHash(ptr, length, seed); }