diff --git a/README.md b/README.md index 87e2dc9..ebb8c4b 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,48 @@ -# xxHash +### xxHash Extremely fast non-cryptographic hash algorithm http://www.xxhash.com/ + +### Benchmark +``` ini + +BenchmarkDotNet=v0.10.13, OS=Windows 10 Redstone 3 [1709, Fall Creators Update] (10.0.16299.309) +Intel Core i7-4700MQ CPU 2.40GHz (Haswell), 1 CPU, 8 logical cores and 4 physical cores +Frequency=2338346 Hz, Resolution=427.6527 ns, Timer=TSC + [Host] : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.2633.0 + DefaultJob : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.2633.0 + + +``` +### Platform (x64) +| Method | N | Mean | Error | StdDev | Min | Max | Rank | Allocated | +|------- |----------- |-----------------:|----------------:|----------------:|-----------------:|-----------------:|-----:|----------:| +| **Hash32** | **1024** | **179.1 ns** | **1.4130 ns** | **1.2526 ns** | **176.9 ns** | **181.5 ns** | **2** | **0 B** | +| Hash64 | 1024 | 112.8 ns | 0.2171 ns | 0.1695 ns | 112.5 ns | 113.1 ns | 1 | 0 B | +| **Hash32** | **1048576** | **167,038.5 ns** | **1,368.2279 ns** | **1,279.8411 ns** | **164,833.0 ns** | **168,950.2 ns** | **4** | **0 B** | +| Hash64 | 1048576 | 83,941.7 ns | 998.4934 ns | 833.7872 ns | 82,805.5 ns | 86,072.0 ns | 3 | 0 B | +| **Hash32** | **1073741824** | **198,183,743.4 ns** | **460,682.2634 ns** | **359,670.3777 ns** | **197,721,867.3 ns** | **198,782,071.8 ns** | **6** | **0 B** | +| Hash64 | 1073741824 | 112,638,993.1 ns | 579,672.5814 ns | 542,226.0395 ns | 111,995,167.3 ns | 113,573,740.3 ns | 5 | 0 B | + +### Platform (x86) +| Method | N | Mean | Error | StdDev | Min | Max | Rank | Allocated | +|------- |----------- |-------------------:|-------------------:|-------------------:|-------------------:|-------------------:|-----:|----------:| +| **Hash32** | **1024** | **354.9 ns** | **0.3559 ns** | **0.3329 ns** | **354.5 ns** | **355.5 ns** | **1** | **0 B** | +| Hash64 | 1024 | 1,380.3 ns | 16.4808 ns | 13.7622 ns | 1,361.0 ns | 1,398.3 ns | 2 | 0 B | +| **Hash32** | **1048576** | **357,399.4 ns** | **575.2125 ns** | **480.3285 ns** | **356,245.1 ns** | **358,044.0 ns** | **3** | **0 B** | +| Hash64 | 1048576 | 1,343,269.5 ns | 1,414.4992 ns | 1,253.9166 ns | 1,340,923.2 ns | 1,345,356.7 ns | 4 | 0 B | +| **Hash32** | **1073741824** | **365,925,742.3 ns** | **3,000,679.6175 ns** | **2,806,837.3028 ns** | **360,332,613.3 ns** | **369,159,819.6 ns** | **5** | **0 B** | +| Hash64 | 1073741824 | 1,388,585,469.4 ns | 20,271,183.1613 ns | 18,961,675.4611 ns | 1,368,307,867.2 ns | 1,428,744,362.7 ns | 6 | 0 B | + +### Speed +| Method | x86 | x64 | +|-------:|----------:|----------:| +| Hash32 | 2.73 GB/s | 720 MB/s | +| Hash64 | 5.05 GB/s | 8.92 GB/s | + +### How to use +``` cs + byte[] data = Encoding.UTF8.GetBytes("veni vidi vici"); + + uint hash64 = xxHash64.ComputeHash(data, data.Length); + ulong hash32 = xxHash32.ComputeHash(data, data.Length); + +``` \ No newline at end of file diff --git a/src/xxHash.Lib/Properties/AssemblyInfo.cs b/src/xxHash.Lib/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..1d9f795 --- /dev/null +++ b/src/xxHash.Lib/Properties/AssemblyInfo.cs @@ -0,0 +1,40 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("xxHash.Lib")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("xxHash.Lib")] +[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("1487b414-7f4b-4b4a-adf3-6c7f6c0a15ac")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AllowPartiallyTrustedCallers] +[assembly: SecurityTransparent] +[assembly: SecurityRules(SecurityRuleSet.Level2, SkipVerificationInFullTrust = true)] \ No newline at end of file diff --git a/src/xxHash.Lib/xxHash.Lib.csproj b/src/xxHash.Lib/xxHash.Lib.csproj new file mode 100644 index 0000000..efb74c2 --- /dev/null +++ b/src/xxHash.Lib/xxHash.Lib.csproj @@ -0,0 +1,45 @@ + + + + + Debug + AnyCPU + {1487B414-7F4B-4B4A-ADF3-6C7F6C0A15AC} + Library + Properties + xxHash.Lib + xxHash.Lib + v4.6.1 + 512 + + + true + full + true + bin\Debug\ + DEBUG;TRACE + prompt + 4 + true + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + true + x64 + + + + + + + + + + + + \ No newline at end of file diff --git a/src/xxHash.Lib/xxHash32.cs b/src/xxHash.Lib/xxHash32.cs new file mode 100644 index 0000000..5723f9c --- /dev/null +++ b/src/xxHash.Lib/xxHash32.cs @@ -0,0 +1,88 @@ +namespace xxHash.Lib +{ + public static class xxHash32 + { + private const uint p1 = 2654435761U; + private const uint p2 = 2246822519U; + private const uint p3 = 3266489917U; + private const uint p4 = 668265263U; + private const uint p5 = 374761393U; + + public static unsafe uint ComputeHash(byte[] data, int len, uint seed = 0) + { + fixed (byte* pData = &data[0]) + { + uint* ptr = (uint*) pData; + byte* end = pData + len; + uint h32; + + if (len >= 16) + { + byte* limit = end - 16; + + uint v1 = seed + p1 + p2; + uint v2 = seed + p2; + uint v3 = seed + 0; + uint v4 = seed - p1; + + do + { + v1 += ptr[0] * p2; + v1 = (v1 << 13) | (v1 >> (32 - 13)); // rotl 13 + v1 *= p1; + + v2 += ptr[1] * p2; + v2 = (v2 << 13) | (v2 >> (32 - 13)); // rotl 13 + v2 *= p1; + + v3 += ptr[2] * p2; + v3 = (v3 << 13) | (v3 >> (32 - 13)); // rotl 13 + v3 *= p1; + + v4 += ptr[3] * p2; + v4 = (v4 << 13) | (v4 >> (32 - 13)); // rotl 13 + v4 *= p1; + + ptr += 4; + + } while (ptr <= limit); + + h32 = ((v1 << 1) | (v1 >> (32 - 1))) + // rotl 1 + ((v2 << 7) | (v2 >> (32 - 7))) + // rotl 7 + ((v3 << 12) | (v3 >> (32 - 12))) + // rotl 12 + ((v4 << 18) | (v4 >> (32 - 18))); // rotl 18 + } + else + { + h32 = seed + p5; + } + h32 += (uint) len; + + // finalize + while (ptr <= end - 4) + { + h32 += ptr[0] * p3; + h32 = ((h32 << 17) | (h32 >> (32 - 17))) * p4; // (rotl 17) * p4 + ptr += 1; + } + + byte* lst = (byte*) ptr; + while (lst < end) + { + h32 += (*lst) * p5; + h32 = ((h32 << 11) | (h32 >> (32 - 11))) * p1; // (rotl 11) * p1 + lst += 1; + } + + // avalanche + h32 ^= h32 >> 15; + h32 *= p2; + h32 ^= h32 >> 13; + h32 *= p3; + h32 ^= h32 >> 16; + + return h32; + } + } + } +} diff --git a/src/xxHash.Lib/xxHash64.cs b/src/xxHash.Lib/xxHash64.cs new file mode 100644 index 0000000..2d763df --- /dev/null +++ b/src/xxHash.Lib/xxHash64.cs @@ -0,0 +1,128 @@ +namespace xxHash.Lib +{ + public static class xxHash64 + { + private const ulong p1 = 11400714785074694791UL; + private const ulong p2 = 14029467366897019727UL; + private const ulong p3 = 1609587929392839161UL; + private const ulong p4 = 9650029242287828579UL; + private const ulong p5 = 2870177450012600261UL; + + public static unsafe ulong ComputeHash(byte[] data, int len, ulong seed = 0) + { + fixed (byte* pData = &data[0]) + { + ulong* ptr = (ulong*) pData; + byte* end = pData + len; + ulong h64; + + if (len >= 32) + { + byte* limit = end - 32; + + ulong v1 = seed + p1 + p2; + ulong v2 = seed + p2; + ulong v3 = seed + 0; + ulong v4 = seed - p1; + + do + { + v1 += ptr[0] * p2; + v1 = (v1 << 31) | (v1 >> (64 - 31)); // rotl 31 + v1 *= p1; + + v2 += ptr[1] * p2; + v2 = (v2 << 31) | (v2 >> (64 - 31)); // rotl 31 + v2 *= p1; + + v3 += ptr[2] * p2; + v3 = (v3 << 31) | (v3 >> (64 - 31)); // rotl 31 + v3 *= p1; + + v4 += ptr[3] * p2; + v4 = (v4 << 31) | (v4 >> (64 - 31)); // rotl 31 + v4 *= p1; + + ptr += 4; + + } while (ptr <= limit); + + h64 = ((v1 << 1) | (v1 >> (64 - 1))) + // rotl 1 + ((v2 << 7) | (v2 >> (64 - 7))) + // rotl 7 + ((v3 << 12) | (v3 >> (64 - 12))) + // rotl 12 + ((v4 << 18) | (v4 >> (64 - 18))); // rotl 18 + + // merge round + v1 *= p2; + v1 = (v1 << 31) | (v1 >> (64 - 31)); // rotl 31 + v1 *= p1; + h64 ^= v1; + h64 = h64 * p1 + p4; + + // merge round + v2 *= p2; + v2 = (v2 << 31) | (v2 >> (64 - 31)); // rotl 31 + v2 *= p1; + h64 ^= v2; + h64 = h64 * p1 + p4; + + // merge round + v3 *= p2; + v3 = (v3 << 31) | (v3 >> (64 - 31)); // rotl 31 + v3 *= p1; + h64 ^= v3; + h64 = h64 * p1 + p4; + + // merge round + v4 *= p2; + v4 = (v4 << 31) | (v4 >> (64 - 31)); // rotl 31 + v4 *= p1; + h64 ^= v4; + h64 = h64 * p1 + p4; + } + else + { + h64 = seed + p5; + } + + h64 += (ulong) len; + + // finalize + while (ptr <= end - 8) + { + ulong t1 = ptr[0] * p2; + t1 = (t1 << 31) | (t1 >> (64 - 31)); // rotl 31 + t1 *= p1; + h64 ^= t1; + h64 = ((h64 << 27) | (h64 >> (64 - 27))) * p1 + p4; // (rotl 27) * p1 + p4 + ptr += 1; + } + + uint* l32 = (uint*) ptr; + if (l32 <= end - 4) + { + h64 ^= l32[0] * p1; + h64 = ((h64 << 23) | (h64 >> (64 - 23))) * p2 + p3; // (rotl 27) * p2 + p3 + l32 += 1; + } + + byte* lst = (byte*)l32; + while (lst < end) + { + h64 ^= lst[0] * p5; + h64 = ((h64 << 11) | (h64 >> (64 - 11))) * p1; // (rotl 11) * p1 + lst += 1; + } + + // avalanche + h64 ^= h64 >> 33; + h64 *= p2; + h64 ^= h64 >> 29; + h64 *= p3; + h64 ^= h64 >> 32; + + return h64; + } + } + } +} diff --git a/src/xxHash.Perf/App.config b/src/xxHash.Perf/App.config new file mode 100644 index 0000000..2bbc34d --- /dev/null +++ b/src/xxHash.Perf/App.config @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/xxHash.Perf/Program.cs b/src/xxHash.Perf/Program.cs new file mode 100644 index 0000000..134c1fe --- /dev/null +++ b/src/xxHash.Perf/Program.cs @@ -0,0 +1,12 @@ +namespace xxHash.Perf +{ + using BenchmarkDotNet.Running; + + class Program + { + static void Main(string[] args) + { + var summary = BenchmarkRunner.Run(); + } + } +} diff --git a/src/xxHash.Perf/Properties/AssemblyInfo.cs b/src/xxHash.Perf/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..3325470 --- /dev/null +++ b/src/xxHash.Perf/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("xxHash.Perf")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("xxHash.Perf")] +[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("2b643cdc-7b3a-4821-a736-4c7b1b280aff")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/xxHash.Perf/packages.config b/src/xxHash.Perf/packages.config new file mode 100644 index 0000000..b23f7a7 --- /dev/null +++ b/src/xxHash.Perf/packages.config @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/xxHash.Perf/xxHash.Perf.csproj b/src/xxHash.Perf/xxHash.Perf.csproj new file mode 100644 index 0000000..ce8f8b8 --- /dev/null +++ b/src/xxHash.Perf/xxHash.Perf.csproj @@ -0,0 +1,157 @@ + + + + + Debug + AnyCPU + {2B643CDC-7B3A-4821-A736-4C7B1B280AFF} + Exe + xxHash.Perf + xxHash.Perf + v4.6.1 + 512 + true + + + x64 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + x64 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\BenchmarkDotNet.0.10.13\lib\net46\BenchmarkDotNet.dll + + + ..\packages\BenchmarkDotNet.Core.0.10.13\lib\net46\BenchmarkDotNet.Core.dll + + + ..\packages\BenchmarkDotNet.Toolchains.Roslyn.0.10.13\lib\net46\BenchmarkDotNet.Toolchains.Roslyn.dll + + + ..\packages\Microsoft.CodeAnalysis.Common.2.6.1\lib\netstandard1.3\Microsoft.CodeAnalysis.dll + + + ..\packages\Microsoft.CodeAnalysis.CSharp.2.6.1\lib\netstandard1.3\Microsoft.CodeAnalysis.CSharp.dll + + + ..\packages\Microsoft.DotNet.InternalAbstractions.1.0.0\lib\net451\Microsoft.DotNet.InternalAbstractions.dll + + + ..\packages\Microsoft.DotNet.PlatformAbstractions.1.1.1\lib\net451\Microsoft.DotNet.PlatformAbstractions.dll + + + ..\packages\Microsoft.Win32.Registry.4.3.0\lib\net46\Microsoft.Win32.Registry.dll + + + + ..\packages\System.AppContext.4.3.0\lib\net46\System.AppContext.dll + True + + + ..\packages\System.Collections.Immutable.1.3.1\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll + True + + + + ..\packages\System.Console.4.3.0\lib\net46\System.Console.dll + + + + ..\packages\System.Diagnostics.FileVersionInfo.4.3.0\lib\net46\System.Diagnostics.FileVersionInfo.dll + + + ..\packages\System.Diagnostics.StackTrace.4.3.0\lib\net46\System.Diagnostics.StackTrace.dll + + + ..\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll + True + + + ..\packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll + + + ..\packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll + + + + + ..\packages\System.Reflection.Metadata.1.4.2\lib\portable-net45+win8\System.Reflection.Metadata.dll + + + ..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net461\System.Security.Cryptography.Algorithms.dll + + + ..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll + + + ..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll + + + ..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll + + + ..\packages\System.Text.Encoding.CodePages.4.3.0\lib\net46\System.Text.Encoding.CodePages.dll + + + ..\packages\System.Threading.Tasks.Extensions.4.3.0\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll + + + ..\packages\System.Threading.Thread.4.3.0\lib\net46\System.Threading.Thread.dll + + + ..\packages\System.ValueTuple.4.3.0\lib\netstandard1.0\System.ValueTuple.dll + + + + + + + + + ..\packages\System.Xml.ReaderWriter.4.3.0\lib\net46\System.Xml.ReaderWriter.dll + + + ..\packages\System.Xml.XmlDocument.4.3.0\lib\net46\System.Xml.XmlDocument.dll + + + ..\packages\System.Xml.XPath.4.3.0\lib\net46\System.Xml.XPath.dll + + + ..\packages\System.Xml.XPath.XDocument.4.3.0\lib\net46\System.Xml.XPath.XDocument.dll + + + + + + + + + + + + + + + + + + {1487b414-7f4b-4b4a-adf3-6c7f6c0a15ac} + xxHash.Lib + + + + \ No newline at end of file diff --git a/src/xxHash.Perf/xxHashTest.cs b/src/xxHash.Perf/xxHashTest.cs new file mode 100644 index 0000000..d517728 --- /dev/null +++ b/src/xxHash.Perf/xxHashTest.cs @@ -0,0 +1,43 @@ +namespace xxHash.Perf +{ + using System; + using BenchmarkDotNet.Attributes; + using BenchmarkDotNet.Attributes.Columns; + using BenchmarkDotNet.Attributes.Exporters; + using Lib; + + [RPlotExporter, RankColumn] + [MinColumn, MaxColumn] + [MemoryDiagnoser] + [DisassemblyDiagnoser(printAsm: true, printSource: true)] + public class xxHashTest + { + const int KB = 1024; + const int MB = 1024 * KB; + const int GB = 1024 * MB; + + private byte[] data; + + [Params(KB, MB, GB)] + public int N; + + [GlobalSetup] + public void Setup() + { + data = new byte[N]; + new Random(42).NextBytes(data); + } + + [Benchmark] + public uint Hash32() + { + return xxHash32.ComputeHash(data, data.Length); + } + + [Benchmark] + public ulong Hash64() + { + return xxHash64.ComputeHash(data, data.Length); + } + } +} diff --git a/src/xxHash.Test/Properties/AssemblyInfo.cs b/src/xxHash.Test/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..6f0e0d4 --- /dev/null +++ b/src/xxHash.Test/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("xxHash.Test")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("xxHash.Test")] +[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("30129d86-62b5-4f40-bbb8-25ff858c18d3")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/xxHash.Test/packages.config b/src/xxHash.Test/packages.config new file mode 100644 index 0000000..650487c --- /dev/null +++ b/src/xxHash.Test/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/xxHash.Test/xxHash.Test.csproj b/src/xxHash.Test/xxHash.Test.csproj new file mode 100644 index 0000000..0788f9d --- /dev/null +++ b/src/xxHash.Test/xxHash.Test.csproj @@ -0,0 +1,67 @@ + + + + + + Debug + AnyCPU + {30129D86-62B5-4F40-BBB8-25FF858C18D3} + Library + Properties + xxHash.Test + xxHash.Test + v4.6.1 + 512 + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + x64 + + + + ..\packages\NUnit.3.10.1\lib\net45\nunit.framework.dll + + + + + + + + + + + + {1487b414-7f4b-4b4a-adf3-6c7f6c0a15ac} + xxHash.Lib + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + \ No newline at end of file diff --git a/src/xxHash.Test/xxHash32Test.cs b/src/xxHash.Test/xxHash32Test.cs new file mode 100644 index 0000000..dad5d38 --- /dev/null +++ b/src/xxHash.Test/xxHash32Test.cs @@ -0,0 +1,48 @@ +namespace xxHash.Test +{ + using System.Text; + using Lib; + using NUnit.Framework; + + [TestFixture] + public class xxHash32Test + { + [Test] + public void Compute_hash_for_the_byte_array() + { + byte[] data = new byte[] + { + 0xde, 0x55, 0x47, 0x7f, 0x14, 0x8f, 0xf1, 0x48, + 0x22, 0x3a, 0x40, 0x96, 0x56, 0xc5, 0xdc, 0xbb, + 0x0e, 0x59, 0x4d, 0x42, 0xc5, 0x07, 0x21, 0x08, + 0x1c, 0x2c, 0xc9, 0x38, 0x7d, 0x43, 0x83, 0x11, + }; + + uint[] actual = new uint[] + { + 0x2330eac0, 0x2c006f7e, 0xa1481114, 0x28d386f9, 0x112348ba, 0x65da8e31, 0x7555bcbd, 0x46cf19ed, + 0x27802c05, 0x8d0a6fae, 0x6075daf0, 0x4c5aef64, 0x8c6b5a5e, 0x00c1810a, 0x863d91cf, 0xcdf89609, + 0xbca8f924, 0xed028fb5, 0x81c19b77, 0x1a0550fa, 0xf4518e14, 0xae2eace8, 0xe7f85aa8, 0xcf8df264, + 0xb4fd0c90, 0x511934b0, 0x796f989a, 0x26b664a6, 0x8c242079, 0x5842beef, 0xd1d0b350, 0xf8497daa, + }; + + for (int len = 1; len <= data.Length; len++) + { + // Act + uint hash = xxHash32.ComputeHash(data, len); + // Assert + Assert.AreEqual(hash, actual[len - 1]); + } + } + + [Test] + public void Compute_hash_for_the_string() + { + var data = Encoding.UTF8.GetBytes("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod"); + + var hash = xxHash32.ComputeHash(data, data.Length); + + Assert.AreEqual(hash, 0xe3cd4dee); + } + } +} diff --git a/src/xxHash.Test/xxHash64Test.cs b/src/xxHash.Test/xxHash64Test.cs new file mode 100644 index 0000000..5af8108 --- /dev/null +++ b/src/xxHash.Test/xxHash64Test.cs @@ -0,0 +1,56 @@ +namespace xxHash.Test +{ + using System.Text; + using Lib; + using NUnit.Framework; + + [TestFixture] + public class xxHash64Test + { + [Test] + public void Compute_hash_for_the_byte_array() + { + byte[] data = new byte[] + { + 0x60, 0x82, 0x40, 0x77, 0x8a, 0x0e, 0xe4, 0xd5, + 0x85, 0x1f, 0xa6, 0x86, 0x34, 0x01, 0xd7, 0xf2, + 0x30, 0x5d, 0x84, 0x54, 0x15, 0xf9, 0xbd, 0x03, + 0x4b, 0x0f, 0x90, 0x4e, 0xf5, 0x57, 0x21, 0x21, + 0xed, 0x8c, 0x19, 0x93, 0xbd, 0x01, 0x12, 0x0c, + 0x20, 0xb0, 0x33, 0x98, 0x4b, 0xe7, 0xc1, 0x0a, + 0x27, 0x6d, 0xb3, 0x5c, 0xc7, 0xc0, 0xd0, 0xa0, + 0x7e, 0x28, 0xce, 0x46, 0x85, 0xb7, 0x2b, 0x16, + }; + + ulong[] actual = new ulong[] + { + 0xb3e7ca6ca5ba3445, 0xc48d23e7117c5c9f, 0xbdde5e6c403b877f, 0xb1f2d0131359c662, 0x917b11ed024938fc, 0xf1f919ac6d7f76e4, 0xea769e99c9c9bbd8, 0x703ba74928ca5564, + 0xe7c3e0490a3b1d95, 0x3029ac2ba355e675, 0x4c0457cbdeef0b12, 0xe62ef3a1d378c12e, 0x9d1cb0d181d58bee, 0x9a5fb7dcdf81ce31, 0x4b34ada6b021b0f0, 0x06a48a5ee2da8aa0, + 0xc2c6ca165cef49be, 0xd65d8cf3e8303c45, 0x9c4fe072aa5ba2c3, 0x6fdcaa87f4c0027d, 0xdf36b78f6ed0d0c4, 0x4c2de293bd035f97, 0x80e9997ecb4b4dba, 0xedc569773e3c1aae, + 0xce488e21bb53a4e2, 0x9eba278ca7d6167f, 0xafc41ab957fc123c, 0x221bc4f34b8afc02, 0x89448861c1506213, 0x1e790a0825d2edd5, 0xbac80f4da00a5ddb, 0x9233096b7804e12c, + 0xa596aeb3e9e2a0fb, 0xe5e8a197b29353c0, 0x75adcf4cf52af71f, 0x98e480d02a353d0b, 0xba1959292dce8087, 0x244320e6b95005cf, 0xc7a8f723dedfcb7f, 0x5557772a50b43c1a, + 0xdfe1c66f17b8caad, 0xcce29f0e017c531c, 0xc7582d7753b82d55, 0xfd7a0f9119288736, 0xd9d70c5d5d544166, 0x1e45f4055ed9dd64, 0xbdc0b3dedd7f9ba6, 0xfef1d3bf774540d4, + 0xa9c399777e64b4fa, 0xa6a3a1e8bcfa2b2d, 0xb3e8ee1513ebb5cf, 0x1705345d27cd571e, 0x101c3fe5b4cbbc77, 0xc0990c64b0b3b7ab, 0x9e0a9991f51b4ff5, 0xd24f884f6c74e067, + 0x5ae156ca6a9202c9, 0x60786b148def4de5, 0x36648dcc3f16c761, 0x3b5d877329197688, 0x22cb98d859720834, 0x77c5f375685b7942, 0x7a9f2086cdc70d02, 0x4c0a65b1ef9ea060, + }; + + for (int len = 1; len <= data.Length; len++) + { + // Assert + ulong hash = xxHash64.ComputeHash(data, len); + // Act + Assert.AreEqual(hash, actual[len-1]); + } + } + + [Test] + public void Compute_hash_for_the_string() + { + var data = Encoding.UTF8.GetBytes("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod"); + + var hash = xxHash64.ComputeHash(data, data.Length); + + Assert.AreEqual(hash, 0x5dee64ff7c935d7f); + } + } +} diff --git a/src/xxHash.sln b/src/xxHash.sln new file mode 100644 index 0000000..509f638 --- /dev/null +++ b/src/xxHash.sln @@ -0,0 +1,65 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27130.2026 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "xxHash.Lib", "xxHash.Lib\xxHash.Lib.csproj", "{1487B414-7F4B-4B4A-ADF3-6C7F6C0A15AC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "xxHash.Test", "xxHash.Test\xxHash.Test.csproj", "{30129D86-62B5-4F40-BBB8-25FF858C18D3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "xxHash.Perf", "xxHash.Perf\xxHash.Perf.csproj", "{2B643CDC-7B3A-4821-A736-4C7B1B280AFF}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1487B414-7F4B-4B4A-ADF3-6C7F6C0A15AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1487B414-7F4B-4B4A-ADF3-6C7F6C0A15AC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1487B414-7F4B-4B4A-ADF3-6C7F6C0A15AC}.Debug|x64.ActiveCfg = Debug|Any CPU + {1487B414-7F4B-4B4A-ADF3-6C7F6C0A15AC}.Debug|x64.Build.0 = Debug|Any CPU + {1487B414-7F4B-4B4A-ADF3-6C7F6C0A15AC}.Debug|x86.ActiveCfg = Debug|Any CPU + {1487B414-7F4B-4B4A-ADF3-6C7F6C0A15AC}.Debug|x86.Build.0 = Debug|Any CPU + {1487B414-7F4B-4B4A-ADF3-6C7F6C0A15AC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1487B414-7F4B-4B4A-ADF3-6C7F6C0A15AC}.Release|Any CPU.Build.0 = Release|Any CPU + {1487B414-7F4B-4B4A-ADF3-6C7F6C0A15AC}.Release|x64.ActiveCfg = Release|Any CPU + {1487B414-7F4B-4B4A-ADF3-6C7F6C0A15AC}.Release|x64.Build.0 = Release|Any CPU + {1487B414-7F4B-4B4A-ADF3-6C7F6C0A15AC}.Release|x86.ActiveCfg = Release|Any CPU + {1487B414-7F4B-4B4A-ADF3-6C7F6C0A15AC}.Release|x86.Build.0 = Release|Any CPU + {30129D86-62B5-4F40-BBB8-25FF858C18D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {30129D86-62B5-4F40-BBB8-25FF858C18D3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {30129D86-62B5-4F40-BBB8-25FF858C18D3}.Debug|x64.ActiveCfg = Debug|Any CPU + {30129D86-62B5-4F40-BBB8-25FF858C18D3}.Debug|x64.Build.0 = Debug|Any CPU + {30129D86-62B5-4F40-BBB8-25FF858C18D3}.Debug|x86.ActiveCfg = Debug|Any CPU + {30129D86-62B5-4F40-BBB8-25FF858C18D3}.Debug|x86.Build.0 = Debug|Any CPU + {30129D86-62B5-4F40-BBB8-25FF858C18D3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {30129D86-62B5-4F40-BBB8-25FF858C18D3}.Release|Any CPU.Build.0 = Release|Any CPU + {30129D86-62B5-4F40-BBB8-25FF858C18D3}.Release|x64.ActiveCfg = Release|Any CPU + {30129D86-62B5-4F40-BBB8-25FF858C18D3}.Release|x64.Build.0 = Release|Any CPU + {30129D86-62B5-4F40-BBB8-25FF858C18D3}.Release|x86.ActiveCfg = Release|Any CPU + {30129D86-62B5-4F40-BBB8-25FF858C18D3}.Release|x86.Build.0 = Release|Any CPU + {2B643CDC-7B3A-4821-A736-4C7B1B280AFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2B643CDC-7B3A-4821-A736-4C7B1B280AFF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2B643CDC-7B3A-4821-A736-4C7B1B280AFF}.Debug|x64.ActiveCfg = Debug|Any CPU + {2B643CDC-7B3A-4821-A736-4C7B1B280AFF}.Debug|x64.Build.0 = Debug|Any CPU + {2B643CDC-7B3A-4821-A736-4C7B1B280AFF}.Debug|x86.ActiveCfg = Debug|Any CPU + {2B643CDC-7B3A-4821-A736-4C7B1B280AFF}.Debug|x86.Build.0 = Debug|Any CPU + {2B643CDC-7B3A-4821-A736-4C7B1B280AFF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2B643CDC-7B3A-4821-A736-4C7B1B280AFF}.Release|Any CPU.Build.0 = Release|Any CPU + {2B643CDC-7B3A-4821-A736-4C7B1B280AFF}.Release|x64.ActiveCfg = Release|Any CPU + {2B643CDC-7B3A-4821-A736-4C7B1B280AFF}.Release|x64.Build.0 = Release|Any CPU + {2B643CDC-7B3A-4821-A736-4C7B1B280AFF}.Release|x86.ActiveCfg = Release|Any CPU + {2B643CDC-7B3A-4821-A736-4C7B1B280AFF}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {5FB21551-AFF0-4BF4-8011-8BF4C703F80E} + EndGlobalSection +EndGlobal