Add tests for xxHash128

This commit is contained in:
Oleksandr Melnyk 2022-06-03 15:02:55 +03:00
parent 8d6f7fa43b
commit c079a400a0
8 changed files with 288 additions and 9 deletions

View File

@ -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);
}
}
}

View File

@ -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]);
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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<byte, ulong>(ref bytes[0]) = value.high64;
Unsafe.As<byte, ulong>(ref bytes[8]) = value.low64;
Unsafe.As<byte, ulong>(ref bytes[0]) = value.low64;
Unsafe.As<byte, ulong>(ref bytes[8]) = value.high64;
return bytes;
}

View File

@ -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);
}
}
/// <summary>
/// Compute hash bytes for the data byte array
/// </summary>
/// <param name="data">The source of data</param>
/// <param name="length">The length of the data for hashing</param>
/// <param name="seed">The seed number</param>
/// <returns>hash</returns>
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();
}
}
/// <summary>
/// Compute hash bytes for the span
/// </summary>
/// <param name="data">The source of data</param>
/// <param name="length">The length of the data for hashing</param>
/// <param name="seed">The seed number</param>
/// <returns>hash</returns>
public static unsafe byte[] ComputeHashBytes(Span<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();
}
}
/// <summary>
/// Compute hash bytes for the data byte span
/// </summary>
/// <param name="data">The source of data</param>
/// <param name="length">The length of the data for hashing</param>
/// <param name="seed">The seed number</param>
/// <returns>hash</returns>
public static unsafe byte[] ComputeHashBytes(ReadOnlySpan<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();
}
}
/// <summary>
/// Compute hash bytes for the string
/// </summary>
/// <param name="str">The source of data</param>
/// <param name="seed">The seed number</param>
/// <returns>hash</returns>
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)
{

View File

@ -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);
}

View File

@ -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);
}