diff --git a/README.md b/README.md
index 9e7ac50..865b64a 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,7 @@
-
+
@@ -39,16 +39,20 @@ This benchmark was launched on a **Windows 10 (10.0.16299.309)**. The reference
|---------------|----------:|
| Hash32 Array | 5.05 GB/s |
| Hash64 Array | 8.92 GB/s |
+| Hash32 Span | 5.05 GB/s |
+| Hash64 Span | 8.92 GB/s |
| Hash32 Stream | 3.22 GB/s |
| Hash64 Stream | 4.81 GB/s |
## Api
```cs
public static uint ComputeHash(byte[] data, int length, uint seed = 0) { throw null; }
+public static uint ComputeHash(Span data, int length, uint seed = 0) { throw null; }
public static uint ComputeHash(Stream stream, int bufferSize = 4096, uint seed = 0) { throw null; }
public static async Task ComputeHashAsync(Stream stream, int bufferSize = 4096, uint seed = 0) { throw null; }
public static ulong ComputeHash(byte[] data, int length, ulong seed = 0) { throw null; }
+public static ulong ComputeHash(Span data, int length, ulong seed = 0) { throw null; }
public static ulong ComputeHash(Stream stream, int bufferSize = 8192, ulong seed = 0) { throw null; }
public static async Task ComputeHashAsync(Stream stream, int bufferSize = 8192, ulong seed = 0) { throw null; }
```
diff --git a/deps.props b/deps.props
index f74040c..3413d54 100644
--- a/deps.props
+++ b/deps.props
@@ -1,11 +1,13 @@
- 4.4.0
+ 4.5.0
4.3.0
- 0.10.14
- 15.6.0
- 2.3.1
- 2.3.1
+ 4.5.1
+ 4.5.1
+ 0.11.1
+ 15.8.0
+ 2.4.0
+ 2.4.0
2.3.1
\ No newline at end of file
diff --git a/nuget.props b/nuget.props
index cc75e4d..1a6385d 100644
--- a/nuget.props
+++ b/nuget.props
@@ -3,7 +3,7 @@
netstandard2.0
Standart.Hash.xxHash
- 1.0.4
+ 1.0.5
Standart.Hash.xxHash
Standart.Hash.xxHash
Alexander Melnik
diff --git a/src/Standart.Hash.xxHash.Perf/xxBufferBenchmark.cs b/src/Standart.Hash.xxHash.Perf/UnsafeBufferBenchmark.cs
similarity index 73%
rename from src/Standart.Hash.xxHash.Perf/xxBufferBenchmark.cs
rename to src/Standart.Hash.xxHash.Perf/UnsafeBufferBenchmark.cs
index a25018c..e145ec3 100644
--- a/src/Standart.Hash.xxHash.Perf/xxBufferBenchmark.cs
+++ b/src/Standart.Hash.xxHash.Perf/UnsafeBufferBenchmark.cs
@@ -2,13 +2,11 @@
{
using System;
using BenchmarkDotNet.Attributes;
- using BenchmarkDotNet.Attributes.Columns;
- using BenchmarkDotNet.Attributes.Exporters;
[RPlotExporter, RankColumn]
[MinColumn, MaxColumn]
[MemoryDiagnoser]
- public class xxBufferBenchmark
+ public class UnsafeBufferBenchmark
{
private byte[] src;
private byte[] des;
@@ -33,9 +31,9 @@
}
[Benchmark]
- public void xxBufferCopy()
+ public void UnsafeBufferCopy()
{
- xxBuffer.BlockCopy(src, 0, des, 0, 32);
+ UnsafeBuffer.BlockCopy(src, 0, des, 0, 32);
}
}
}
\ No newline at end of file
diff --git a/src/Standart.Hash.xxHash.Perf/xxHashBenchmark.cs b/src/Standart.Hash.xxHash.Perf/xxHashBenchmark.cs
index 5450743..4e2249e 100644
--- a/src/Standart.Hash.xxHash.Perf/xxHashBenchmark.cs
+++ b/src/Standart.Hash.xxHash.Perf/xxHashBenchmark.cs
@@ -4,8 +4,6 @@
using System.IO;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
- using BenchmarkDotNet.Attributes.Columns;
- using BenchmarkDotNet.Attributes.Exporters;
[RPlotExporter, RankColumn]
[MinColumn, MaxColumn]
@@ -32,11 +30,18 @@
}
[Benchmark]
- public uint Hash32()
+ public uint Hash32_Array()
{
return xxHash32.ComputeHash(data, data.Length);
}
+ [Benchmark]
+ public uint Hash32_Span()
+ {
+ Span span = new Span(data);
+ return xxHash32.ComputeHash(span, span.Length);
+ }
+
[Benchmark]
public uint Hash32_Stream()
{
@@ -52,11 +57,18 @@
}
[Benchmark]
- public ulong Hash64()
+ public ulong Hash64_Array()
{
return xxHash64.ComputeHash(data, data.Length);
}
+ [Benchmark]
+ public ulong Hash64_Span()
+ {
+ Span span = new Span(data);
+ return xxHash64.ComputeHash(span, span.Length);
+ }
+
[Benchmark]
public ulong Hash64_Stream()
{
diff --git a/src/Standart.Hash.xxHash.Test/xxBufferTest.cs b/src/Standart.Hash.xxHash.Test/UnsafeBufferTest.cs
similarity index 86%
rename from src/Standart.Hash.xxHash.Test/xxBufferTest.cs
rename to src/Standart.Hash.xxHash.Test/UnsafeBufferTest.cs
index 6ca6a42..0000b57 100644
--- a/src/Standart.Hash.xxHash.Test/xxBufferTest.cs
+++ b/src/Standart.Hash.xxHash.Test/UnsafeBufferTest.cs
@@ -3,7 +3,7 @@
using System;
using Xunit;
- public class xxBufferTest
+ public class UnsafeBufferTest
{
[Fact]
public void Copy_different_blocks()
@@ -27,7 +27,7 @@
// Act, Assert
foreach (int count in counts)
{
- xxBuffer.BlockCopy(src, 0, dst, 0, count);
+ UnsafeBuffer.BlockCopy(src, 0, dst, 0, count);
for (int i = 0; i < count; i++)
{
diff --git a/src/Standart.Hash.xxHash.Test/xxHash32Test.cs b/src/Standart.Hash.xxHash.Test/xxHash32Test.cs
index 4a0bb9e..61214a8 100644
--- a/src/Standart.Hash.xxHash.Test/xxHash32Test.cs
+++ b/src/Standart.Hash.xxHash.Test/xxHash32Test.cs
@@ -12,12 +12,15 @@
{
// Arrange
byte[] data = {0xde};
+ Span span = new Span(data);
// Act
- uint hash = xxHash32.ComputeHash(data, data.Length);
+ uint hash1 = xxHash32.ComputeHash(data, data.Length);
+ uint hash2 = xxHash32.ComputeHash(span, span.Length);
// Assert
- Assert.Equal(hash, (uint) 0x2330eac0);
+ Assert.Equal(hash1, (uint) 0x2330eac0);
+ Assert.Equal(hash2, (uint) 0x2330eac0);
}
[Fact]
@@ -25,12 +28,15 @@
{
// Arrange
byte[] data = {0xde, 0x55, 0x47, 0x7f, 0x14};
+ Span span = new Span(data);
// Act
- uint hash = xxHash32.ComputeHash(data, data.Length);
+ uint hash1 = xxHash32.ComputeHash(data, data.Length);
+ uint hash2 = xxHash32.ComputeHash(span, span.Length);
// Assert
- Assert.Equal(hash, (uint) 0x112348ba);
+ Assert.Equal(hash1, (uint) 0x112348ba);
+ Assert.Equal(hash2, (uint) 0x112348ba);
}
[Fact]
@@ -42,12 +48,15 @@
0xde, 0x55, 0x47, 0x7f, 0x14, 0x8f, 0xf1, 0x48,
0x22, 0x3a, 0x40, 0x96, 0x56, 0xc5, 0xdc, 0xbb
};
-
+ Span span = new Span(data);
+
// Act
- uint hash = xxHash32.ComputeHash(data, data.Length);
+ uint hash1 = xxHash32.ComputeHash(data, data.Length);
+ uint hash2 = xxHash32.ComputeHash(span, span.Length);
// Assert
- Assert.Equal(hash, (uint) 0xcdf89609);
+ Assert.Equal(hash1, (uint) 0xcdf89609);
+ Assert.Equal(hash2, (uint) 0xcdf89609);
}
[Fact]
@@ -60,12 +69,15 @@
0x22, 0x3a, 0x40, 0x96, 0x56, 0xc5, 0xdc, 0xbb,
0x0e
};
-
+ Span span = new Span(data);
+
// Act
- uint hash = xxHash32.ComputeHash(data, data.Length);
+ uint hash1 = xxHash32.ComputeHash(data, data.Length);
+ uint hash2 = xxHash32.ComputeHash(span, span.Length);
// Assert
- Assert.Equal(hash, (uint) 0xbca8f924);
+ Assert.Equal(hash1, (uint) 0xbca8f924);
+ Assert.Equal(hash2, (uint) 0xbca8f924);
}
[Fact]
@@ -78,12 +90,15 @@
0x22, 0x3a, 0x40, 0x96, 0x56, 0xc5, 0xdc, 0xbb,
0x0e, 0x59, 0x4d, 0x42, 0xc5
};
-
+ Span span = new Span(data);
+
// Act
- uint hash = xxHash32.ComputeHash(data, data.Length);
+ uint hash1 = xxHash32.ComputeHash(data, data.Length);
+ uint hash2 = xxHash32.ComputeHash(span, span.Length);
// Assert
- Assert.Equal(hash, (uint) 0xf4518e14);
+ Assert.Equal(hash1, (uint) 0xf4518e14);
+ Assert.Equal(hash2, (uint) 0xf4518e14);
}
[Fact]
@@ -97,12 +112,15 @@
0x0e, 0x59, 0x4d, 0x42, 0xc5, 0x07, 0x21, 0x08,
0x1c, 0x2c, 0xc9, 0x38, 0x7d, 0x43, 0x83, 0x11,
};
-
+ Span span = new Span(data);
+
// Act
- uint hash = xxHash32.ComputeHash(data, data.Length);
+ uint hash1 = xxHash32.ComputeHash(data, data.Length);
+ uint hash2 = xxHash32.ComputeHash(span, span.Length);
// Assert
- Assert.Equal(hash, (uint) 0xf8497daa);
+ Assert.Equal(hash1, (uint) 0xf8497daa);
+ Assert.Equal(hash2, (uint) 0xf8497daa);
}
[Fact]
diff --git a/src/Standart.Hash.xxHash.Test/xxHash64Test.cs b/src/Standart.Hash.xxHash.Test/xxHash64Test.cs
index be65204..013159f 100644
--- a/src/Standart.Hash.xxHash.Test/xxHash64Test.cs
+++ b/src/Standart.Hash.xxHash.Test/xxHash64Test.cs
@@ -12,12 +12,15 @@
{
// Arrange
byte[] data = {0x60};
+ Span span = new Span(data);
// Act
- ulong hash = xxHash64.ComputeHash(data, data.Length);
+ ulong hash1 = xxHash64.ComputeHash(data, data.Length);
+ ulong hash2 = xxHash64.ComputeHash(span, data.Length);
// Assert
- Assert.Equal(hash, (ulong) 0xb3e7ca6ca5ba3445);
+ Assert.Equal(hash1, (ulong) 0xb3e7ca6ca5ba3445);
+ Assert.Equal(hash2, (ulong) 0xb3e7ca6ca5ba3445);
}
[Fact]
@@ -25,12 +28,15 @@
{
// Arrange
byte[] data = {0x60, 0x82, 0x40, 0x77, 0x8a};
+ Span span = new Span(data);
// Act
- ulong hash = xxHash64.ComputeHash(data, data.Length);
+ ulong hash1 = xxHash64.ComputeHash(data, data.Length);
+ ulong hash2 = xxHash64.ComputeHash(span, data.Length);
// Assert
- Assert.Equal(hash, (ulong) 0x917b11ed024938fc);
+ Assert.Equal(hash1, (ulong) 0x917b11ed024938fc);
+ Assert.Equal(hash2, (ulong) 0x917b11ed024938fc);
}
[Fact]
@@ -42,12 +48,15 @@
0x60, 0x82, 0x40, 0x77, 0x8a, 0x0e, 0xe4, 0xd5,
0x85, 0x1f, 0xa6, 0x86, 0x34,
};
+ Span span = new Span(data);
// Act
- ulong hash = xxHash64.ComputeHash(data, data.Length);
+ ulong hash1 = xxHash64.ComputeHash(data, data.Length);
+ ulong hash2 = xxHash64.ComputeHash(span, data.Length);
// Assert
- Assert.Equal(hash, (ulong) 0x9d1cb0d181d58bee);
+ Assert.Equal(hash1, (ulong) 0x9d1cb0d181d58bee);
+ Assert.Equal(hash2, (ulong) 0x9d1cb0d181d58bee);
}
[Fact]
@@ -61,12 +70,15 @@
0x30, 0x5d, 0x84, 0x54, 0x15, 0xf9, 0xbd, 0x03,
0x4b, 0x0f, 0x90, 0x4e, 0xf5, 0x57, 0x21, 0x21,
};
+ Span span = new Span(data);
// Act
- ulong hash = xxHash64.ComputeHash(data, data.Length);
+ ulong hash1 = xxHash64.ComputeHash(data, data.Length);
+ ulong hash2 = xxHash64.ComputeHash(span, data.Length);
// Assert
- Assert.Equal(hash, (ulong) 0x9233096b7804e12c);
+ Assert.Equal(hash1, (ulong) 0x9233096b7804e12c);
+ Assert.Equal(hash2, (ulong) 0x9233096b7804e12c);
}
[Fact]
@@ -84,12 +96,15 @@
0x27, 0x6d, 0xb3, 0x5c, 0xc7, 0xc0, 0xd0, 0xa0,
0x7e, 0x28, 0xce, 0x46, 0x85, 0xb7, 0x2b, 0x16,
};
+ Span span = new Span(data);
// Act
- ulong hash = xxHash64.ComputeHash(data, data.Length);
+ ulong hash1 = xxHash64.ComputeHash(data, data.Length);
+ ulong hash2 = xxHash64.ComputeHash(span, data.Length);
// Assert
- Assert.Equal(hash, (ulong) 0x4c0a65b1ef9ea060);
+ Assert.Equal(hash1, (ulong) 0x4c0a65b1ef9ea060);
+ Assert.Equal(hash2, (ulong) 0x4c0a65b1ef9ea060);
}
[Fact]
diff --git a/src/Standart.Hash.xxHash/AssemblyInfo.cs b/src/Standart.Hash.xxHash/AssemblyInfo.cs
new file mode 100644
index 0000000..62476bf
--- /dev/null
+++ b/src/Standart.Hash.xxHash/AssemblyInfo.cs
@@ -0,0 +1,4 @@
+using System.Runtime.CompilerServices;
+
+[assembly: InternalsVisibleTo("Standart.Hash.xxHash.Perf")]
+[assembly: InternalsVisibleTo("Standart.Hash.xxHash.Test")]
\ No newline at end of file
diff --git a/src/Standart.Hash.xxHash/Standart.Hash.xxHash.csproj b/src/Standart.Hash.xxHash/Standart.Hash.xxHash.csproj
index dc2d24c..5e797e4 100644
--- a/src/Standart.Hash.xxHash/Standart.Hash.xxHash.csproj
+++ b/src/Standart.Hash.xxHash/Standart.Hash.xxHash.csproj
@@ -13,6 +13,8 @@
-
+
+
+
\ No newline at end of file
diff --git a/src/Standart.Hash.xxHash/UnsafeBuffer.cs b/src/Standart.Hash.xxHash/UnsafeBuffer.cs
new file mode 100644
index 0000000..f674653
--- /dev/null
+++ b/src/Standart.Hash.xxHash/UnsafeBuffer.cs
@@ -0,0 +1,235 @@
+namespace Standart.Hash.xxHash
+{
+ using System.Diagnostics;
+ using System.Runtime.CompilerServices;
+
+ internal static class UnsafeBuffer
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe void BlockCopy(byte[] src, int srcOffset, byte[] dst, int dstOffset, int count)
+ {
+ Debug.Assert(src != null);
+ Debug.Assert(dst != null);
+ Debug.Assert(srcOffset >= 0 && srcOffset < src.Length);
+ Debug.Assert(dstOffset >= 0 && dstOffset < dst.Length);
+ Debug.Assert(count >= 0);
+ Debug.Assert(count + srcOffset <= src.Length);
+ Debug.Assert(count + dstOffset <= dst.Length);
+
+ fixed (byte* pSrc = &src[srcOffset])
+ fixed (byte* pDst = &dst[dstOffset])
+ {
+ byte* ptrSrc = pSrc;
+ byte* ptrDst = pDst;
+
+ SMALLTABLE:
+ switch (count)
+ {
+ case 0:
+ return;
+ case 1:
+ *ptrDst = *ptrSrc;
+ return;
+ case 2:
+ *(short*)ptrDst = *(short*)ptrSrc;
+ return;
+ case 3:
+ *(short*)(ptrDst + 0) = *(short*)(ptrSrc + 0);
+ *(ptrDst + 2) = *(ptrSrc + 2);
+ return;
+ case 4:
+ *(int*)ptrDst = *(int*)ptrSrc;
+ return;
+ case 5:
+ *(int*)(ptrDst + 0) = *(int*)(ptrSrc + 0);
+ *(ptrDst + 4) = *(ptrSrc + 4);
+ return;
+ case 6:
+ *(int*)(ptrDst + 0) = *(int*)(ptrSrc + 0);
+ *(short*)(ptrDst + 4) = *(short*)(ptrSrc + 4);
+ return;
+ case 7:
+ *(int*)(ptrDst + 0) = *(int*)(ptrSrc + 0);
+ *(short*)(ptrDst + 4) = *(short*)(ptrSrc + 4);
+ *(ptrDst + 6) = *(ptrSrc + 6);
+ return;
+ case 8:
+ *(long*)ptrDst = *(long*)ptrSrc;
+ return;
+ case 9:
+ *(long*)(ptrDst + 0) = *(long*)(ptrSrc + 0);
+ *(ptrDst + 8) = *(ptrSrc + 8);
+ return;
+ case 10:
+ *(long*)(ptrDst + 0) = *(long*)(ptrSrc + 0);
+ *(short*)(ptrDst + 8) = *(short*)(ptrSrc + 8);
+ return;
+ case 11:
+ *(long*)(ptrDst + 0) = *(long*)(ptrSrc + 0);
+ *(short*)(ptrDst + 8) = *(short*)(ptrSrc + 8);
+ *(ptrDst + 10) = *(ptrSrc + 10);
+ return;
+ case 12:
+ *(long*)ptrDst = *(long*)ptrSrc;
+ *(int*)(ptrDst + 8) = *(int*)(ptrSrc + 8);
+ return;
+ case 13:
+ *(long*)(ptrDst + 0) = *(long*)(ptrSrc + 0);
+ *(int*)(ptrDst + 8) = *(int*)(ptrSrc + 8);
+ *(ptrDst + 12) = *(ptrSrc + 12);
+ return;
+ case 14:
+ *(long*)(ptrDst + 0) = *(long*)(ptrSrc + 0);
+ *(int*)(ptrDst + 8) = *(int*)(ptrSrc + 8);
+ *(short*)(ptrDst + 12) = *(short*)(ptrSrc + 12);
+ return;
+ case 15:
+ *(long*)(ptrDst + 0) = *(long*)(ptrSrc + 0);
+ *(int*)(ptrDst + 8) = *(int*)(ptrSrc + 8);
+ *(short*)(ptrDst + 12) = *(short*)(ptrSrc + 12);
+ *(ptrDst + 14) = *(ptrSrc + 14);
+ return;
+ case 16:
+ *(long*)ptrDst = *(long*)ptrSrc;
+ *(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
+ return;
+ case 17:
+ *(long*)ptrDst = *(long*)ptrSrc;
+ *(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
+ *(ptrDst + 16) = *(ptrSrc + 16);
+ return;
+ case 18:
+ *(long*)ptrDst = *(long*)ptrSrc;
+ *(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
+ *(short*)(ptrDst + 16) = *(short*)(ptrSrc + 16);
+ return;
+ case 19:
+ *(long*)ptrDst = *(long*)ptrSrc;
+ *(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
+ *(short*)(ptrDst + 16) = *(short*)(ptrSrc + 16);
+ *(ptrDst + 18) = *(ptrSrc + 18);
+ return;
+ case 20:
+ *(long*)ptrDst = *(long*)ptrSrc;
+ *(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
+ *(int*)(ptrDst + 16) = *(int*)(ptrSrc + 16);
+ return;
+
+ case 21:
+ *(long*)ptrDst = *(long*)ptrSrc;
+ *(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
+ *(int*)(ptrDst + 16) = *(int*)(ptrSrc + 16);
+ *(ptrDst + 20) = *(ptrSrc + 20);
+ return;
+ case 22:
+ *(long*)ptrDst = *(long*)ptrSrc;
+ *(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
+ *(int*)(ptrDst + 16) = *(int*)(ptrSrc + 16);
+ *(short*)(ptrDst + 20) = *(short*)(ptrSrc + 20);
+ return;
+ case 23:
+ *(long*)ptrDst = *(long*)ptrSrc;
+ *(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
+ *(int*)(ptrDst + 16) = *(int*)(ptrSrc + 16);
+ *(short*)(ptrDst + 20) = *(short*)(ptrSrc + 20);
+ *(ptrDst + 22) = *(ptrSrc + 22);
+ return;
+ case 24:
+ *(long*)ptrDst = *(long*)ptrSrc;
+ *(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
+ *(long*)(ptrDst + 16) = *(long*)(ptrSrc + 16);
+ return;
+ case 25:
+ *(long*)ptrDst = *(long*)ptrSrc;
+ *(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
+ *(long*)(ptrDst + 16) = *(long*)(ptrSrc + 16);
+ *(ptrDst + 24) = *(ptrSrc + 24);
+ return;
+ case 26:
+ *(long*)ptrDst = *(long*)ptrSrc;
+ *(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
+ *(long*)(ptrDst + 16) = *(long*)(ptrSrc + 16);
+ *(short*)(ptrDst + 24) = *(short*)(ptrSrc + 24);
+ return;
+ case 27:
+ *(long*)ptrDst = *(long*)ptrSrc;
+ *(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
+ *(long*)(ptrDst + 16) = *(long*)(ptrSrc + 16);
+ *(short*)(ptrDst + 24) = *(short*)(ptrSrc + 24);
+ *(ptrDst + 26) = *(ptrSrc + 26);
+ return;
+ case 28:
+ *(long*)ptrDst = *(long*)ptrSrc;
+ *(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
+ *(long*)(ptrDst + 16) = *(long*)(ptrSrc + 16);
+ *(int*)(ptrDst + 24) = *(int*)(ptrSrc + 24);
+ return;
+ case 29:
+ *(long*)ptrDst = *(long*)ptrSrc;
+ *(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
+ *(long*)(ptrDst + 16) = *(long*)(ptrSrc + 16);
+ *(int*)(ptrDst + 24) = *(int*)(ptrSrc + 24);
+ *(ptrDst + 28) = *(ptrSrc + 28);
+ return;
+ case 30:
+ *(long*)ptrDst = *(long*)ptrSrc;
+ *(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
+ *(long*)(ptrDst + 16) = *(long*)(ptrSrc + 16);
+ *(int*)(ptrDst + 24) = *(int*)(ptrSrc + 24);
+ *(short*)(ptrDst + 28) = *(short*)(ptrSrc + 28);
+ return;
+ case 31:
+ *(long*)ptrDst = *(long*)ptrSrc;
+ *(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
+ *(long*)(ptrDst + 16) = *(long*)(ptrSrc + 16);
+ *(int*)(ptrDst + 24) = *(int*)(ptrSrc + 24);
+ *(short*)(ptrDst + 28) = *(short*)(ptrSrc + 28);
+ *(ptrDst + 30) = *(ptrSrc + 30);
+ return;
+ case 32:
+ *(long*)ptrDst = *(long*)ptrSrc;
+ *(long*)(ptrDst + 8) = *(long*)(ptrSrc + 8);
+ *(long*)(ptrDst + 16) = *(long*)(ptrSrc + 16);
+ *(long*)(ptrDst + 24) = *(long*)(ptrSrc + 24);
+ return;
+ default:
+ break;
+ }
+
+ long* lpSrc = (long*)ptrSrc;
+ long* ldSrc = (long*)ptrDst;
+ while (count >= 64)
+ {
+ *(ldSrc + 0) = *(lpSrc + 0);
+ *(ldSrc + 1) = *(lpSrc + 1);
+ *(ldSrc + 2) = *(lpSrc + 2);
+ *(ldSrc + 3) = *(lpSrc + 3);
+ *(ldSrc + 4) = *(lpSrc + 4);
+ *(ldSrc + 5) = *(lpSrc + 5);
+ *(ldSrc + 6) = *(lpSrc + 6);
+ *(ldSrc + 7) = *(lpSrc + 7);
+ if (count == 64)
+ return;
+ count -= 64;
+ lpSrc += 8;
+ ldSrc += 8;
+ }
+ if (count > 32)
+ {
+ *(ldSrc + 0) = *(lpSrc + 0);
+ *(ldSrc + 1) = *(lpSrc + 1);
+ *(ldSrc + 2) = *(lpSrc + 2);
+ *(ldSrc + 3) = *(lpSrc + 3);
+ count -= 32;
+ lpSrc += 4;
+ ldSrc += 4;
+ }
+
+ ptrSrc = (byte*)lpSrc;
+ ptrDst = (byte*)ldSrc;
+ goto SMALLTABLE;
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/Standart.Hash.xxHash/xxBuffer.cs b/src/Standart.Hash.xxHash/xxBuffer.cs
deleted file mode 100644
index fb65929..0000000
--- a/src/Standart.Hash.xxHash/xxBuffer.cs
+++ /dev/null
@@ -1,228 +0,0 @@
-namespace Standart.Hash.xxHash
-{
- using System.Runtime.CompilerServices;
-
- public static class xxBuffer
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static unsafe void BlockCopy(this byte[] src, int srcOffset, byte[] dst, int dstOffset, int count)
- {
- fixed (byte* ptrSrc = &src[srcOffset])
- fixed (byte* ptrDst = &dst[dstOffset])
- {
- UnsafeBlockCopy(ptrSrc, ptrDst, count);
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static unsafe void UnsafeBlockCopy(byte* src, byte* dst, int count)
- {
- SMALLTABLE:
- switch (count)
- {
- case 0:
- return;
- case 1:
- *dst = *src;
- return;
- case 2:
- *(short*)dst = *(short*)src;
- return;
- case 3:
- *(short*)(dst + 0) = *(short*)(src + 0);
- *(dst + 2) = *(src + 2);
- return;
- case 4:
- *(int*)dst = *(int*)src;
- return;
- case 5:
- *(int*)(dst + 0) = *(int*)(src + 0);
- *(dst + 4) = *(src + 4);
- return;
- case 6:
- *(int*)(dst + 0) = *(int*)(src + 0);
- *(short*)(dst + 4) = *(short*)(src + 4);
- return;
- case 7:
- *(int*)(dst + 0) = *(int*)(src + 0);
- *(short*)(dst + 4) = *(short*)(src + 4);
- *(dst + 6) = *(src + 6);
- return;
- case 8:
- *(long*)dst = *(long*)src;
- return;
- case 9:
- *(long*)(dst + 0) = *(long*)(src + 0);
- *(dst + 8) = *(src + 8);
- return;
- case 10:
- *(long*)(dst + 0) = *(long*)(src + 0);
- *(short*)(dst + 8) = *(short*)(src + 8);
- return;
- case 11:
- *(long*)(dst + 0) = *(long*)(src + 0);
- *(short*)(dst + 8) = *(short*)(src + 8);
- *(dst + 10) = *(src + 10);
- return;
- case 12:
- *(long*)dst = *(long*)src;
- *(int*)(dst + 8) = *(int*)(src + 8);
- return;
- case 13:
- *(long*)(dst + 0) = *(long*)(src + 0);
- *(int*)(dst + 8) = *(int*)(src + 8);
- *(dst + 12) = *(src + 12);
- return;
- case 14:
- *(long*)(dst + 0) = *(long*)(src + 0);
- *(int*)(dst + 8) = *(int*)(src + 8);
- *(short*)(dst + 12) = *(short*)(src + 12);
- return;
- case 15:
- *(long*)(dst + 0) = *(long*)(src + 0);
- *(int*)(dst + 8) = *(int*)(src + 8);
- *(short*)(dst + 12) = *(short*)(src + 12);
- *(dst + 14) = *(src + 14);
- return;
- case 16:
- *(long*)dst = *(long*)src;
- *(long*)(dst + 8) = *(long*)(src + 8);
- return;
- case 17:
- *(long*)dst = *(long*)src;
- *(long*)(dst + 8) = *(long*)(src + 8);
- *(dst + 16) = *(src + 16);
- return;
- case 18:
- *(long*)dst = *(long*)src;
- *(long*)(dst + 8) = *(long*)(src + 8);
- *(short*)(dst + 16) = *(short*)(src + 16);
- return;
- case 19:
- *(long*)dst = *(long*)src;
- *(long*)(dst + 8) = *(long*)(src + 8);
- *(short*)(dst + 16) = *(short*)(src + 16);
- *(dst + 18) = *(src + 18);
- return;
- case 20:
- *(long*)dst = *(long*)src;
- *(long*)(dst + 8) = *(long*)(src + 8);
- *(int*)(dst + 16) = *(int*)(src + 16);
- return;
-
- case 21:
- *(long*)dst = *(long*)src;
- *(long*)(dst + 8) = *(long*)(src + 8);
- *(int*)(dst + 16) = *(int*)(src + 16);
- *(dst + 20) = *(src + 20);
- return;
- case 22:
- *(long*)dst = *(long*)src;
- *(long*)(dst + 8) = *(long*)(src + 8);
- *(int*)(dst + 16) = *(int*)(src + 16);
- *(short*)(dst + 20) = *(short*)(src + 20);
- return;
- case 23:
- *(long*)dst = *(long*)src;
- *(long*)(dst + 8) = *(long*)(src + 8);
- *(int*)(dst + 16) = *(int*)(src + 16);
- *(short*)(dst + 20) = *(short*)(src + 20);
- *(dst + 22) = *(src + 22);
- return;
- case 24:
- *(long*)dst = *(long*)src;
- *(long*)(dst + 8) = *(long*)(src + 8);
- *(long*)(dst + 16) = *(long*)(src + 16);
- return;
- case 25:
- *(long*)dst = *(long*)src;
- *(long*)(dst + 8) = *(long*)(src + 8);
- *(long*)(dst + 16) = *(long*)(src + 16);
- *(dst + 24) = *(src + 24);
- return;
- case 26:
- *(long*)dst = *(long*)src;
- *(long*)(dst + 8) = *(long*)(src + 8);
- *(long*)(dst + 16) = *(long*)(src + 16);
- *(short*)(dst + 24) = *(short*)(src + 24);
- return;
- case 27:
- *(long*)dst = *(long*)src;
- *(long*)(dst + 8) = *(long*)(src + 8);
- *(long*)(dst + 16) = *(long*)(src + 16);
- *(short*)(dst + 24) = *(short*)(src + 24);
- *(dst + 26) = *(src + 26);
- return;
- case 28:
- *(long*)dst = *(long*)src;
- *(long*)(dst + 8) = *(long*)(src + 8);
- *(long*)(dst + 16) = *(long*)(src + 16);
- *(int*)(dst + 24) = *(int*)(src + 24);
- return;
- case 29:
- *(long*)dst = *(long*)src;
- *(long*)(dst + 8) = *(long*)(src + 8);
- *(long*)(dst + 16) = *(long*)(src + 16);
- *(int*)(dst + 24) = *(int*)(src + 24);
- *(dst + 28) = *(src + 28);
- return;
- case 30:
- *(long*)dst = *(long*)src;
- *(long*)(dst + 8) = *(long*)(src + 8);
- *(long*)(dst + 16) = *(long*)(src + 16);
- *(int*)(dst + 24) = *(int*)(src + 24);
- *(short*)(dst + 28) = *(short*)(src + 28);
- return;
- case 31:
- *(long*)dst = *(long*)src;
- *(long*)(dst + 8) = *(long*)(src + 8);
- *(long*)(dst + 16) = *(long*)(src + 16);
- *(int*)(dst + 24) = *(int*)(src + 24);
- *(short*)(dst + 28) = *(short*)(src + 28);
- *(dst + 30) = *(src + 30);
- return;
- case 32:
- *(long*)dst = *(long*)src;
- *(long*)(dst + 8) = *(long*)(src + 8);
- *(long*)(dst + 16) = *(long*)(src + 16);
- *(long*)(dst + 24) = *(long*)(src + 24);
- return;
- default:
- break;
- }
-
- long* lpSrc = (long*)src;
- long* ldSrc = (long*)dst;
- while (count >= 64)
- {
- *(ldSrc + 0) = *(lpSrc + 0);
- *(ldSrc + 1) = *(lpSrc + 1);
- *(ldSrc + 2) = *(lpSrc + 2);
- *(ldSrc + 3) = *(lpSrc + 3);
- *(ldSrc + 4) = *(lpSrc + 4);
- *(ldSrc + 5) = *(lpSrc + 5);
- *(ldSrc + 6) = *(lpSrc + 6);
- *(ldSrc + 7) = *(lpSrc + 7);
- if (count == 64)
- return;
- count -= 64;
- lpSrc += 8;
- ldSrc += 8;
- }
- if (count > 32)
- {
- *(ldSrc + 0) = *(lpSrc + 0);
- *(ldSrc + 1) = *(lpSrc + 1);
- *(ldSrc + 2) = *(lpSrc + 2);
- *(ldSrc + 3) = *(lpSrc + 3);
- count -= 32;
- lpSrc += 4;
- ldSrc += 4;
- }
-
- src = (byte*)lpSrc;
- dst = (byte*)ldSrc;
- goto SMALLTABLE;
- }
- }
-}
\ No newline at end of file
diff --git a/src/Standart.Hash.xxHash/xxHash32.Stream.cs b/src/Standart.Hash.xxHash/xxHash32.Stream.cs
index 77e1ef3..15d1dda 100644
--- a/src/Standart.Hash.xxHash/xxHash32.Stream.cs
+++ b/src/Standart.Hash.xxHash/xxHash32.Stream.cs
@@ -1,7 +1,7 @@
namespace Standart.Hash.xxHash
{
- using System;
using System.Buffers;
+ using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
@@ -101,6 +101,9 @@
/// The hash
public static uint ComputeHash(Stream stream, int bufferSize = 4096, uint seed = 0)
{
+ Debug.Assert(stream != null);
+ Debug.Assert(bufferSize > 16);
+
// Optimizing memory allocation
byte[] buffer = ArrayPool.Shared.Rent(bufferSize + 16);
@@ -131,7 +134,7 @@
Shift(buffer, l, ref v1, ref v2, ref v3, ref v4);
// Put remaining bytes to buffer
- xxBuffer.BlockCopy(buffer, l, buffer, 0, r);
+ UnsafeBuffer.BlockCopy(buffer, l, buffer, 0, r);
offset = r;
}
@@ -154,8 +157,11 @@
/// The buffer size
/// The seed number
/// The hash
- public static async Task ComputeHashAsync(Stream stream, int bufferSize = 4096, uint seed = 0)
+ public static async ValueTask ComputeHashAsync(Stream stream, int bufferSize = 4096, uint seed = 0)
{
+ Debug.Assert(stream != null);
+ Debug.Assert(bufferSize > 16);
+
// Optimizing memory allocation
byte[] buffer = ArrayPool.Shared.Rent(bufferSize + 16);
@@ -186,7 +192,7 @@
Shift(buffer, l, ref v1, ref v2, ref v3, ref v4);
// Put remaining bytes to buffer
- xxBuffer.BlockCopy(buffer, l, buffer, 0, r);
+ UnsafeBuffer.BlockCopy(buffer,l, buffer, 0, r);
offset = r;
}
diff --git a/src/Standart.Hash.xxHash/xxHash32.cs b/src/Standart.Hash.xxHash/xxHash32.cs
index 9eac1b8..47153f0 100644
--- a/src/Standart.Hash.xxHash/xxHash32.cs
+++ b/src/Standart.Hash.xxHash/xxHash32.cs
@@ -1,5 +1,9 @@
namespace Standart.Hash.xxHash
{
+ using System;
+ using System.Diagnostics;
+ using System.Runtime.CompilerServices;
+
public static partial class xxHash32
{
private const uint p1 = 2654435761U;
@@ -8,7 +12,7 @@
private const uint p4 = 668265263U;
private const uint p5 = 374761393U;
- /// d
+ ///
/// Compute xxHash for the data byte array
///
/// The source of data
@@ -17,10 +21,39 @@
/// hash
public static unsafe uint ComputeHash(byte[] data, int length, uint seed = 0)
{
+ Debug.Assert(data != null);
+ Debug.Assert(length >= 0);
+ Debug.Assert(length <= data.Length);
+
fixed (byte* pData = &data[0])
{
- byte* ptr = pData;
- byte* end = pData + length;
+ return UnsafeComputeHash(pData, length, seed);
+ }
+ }
+
+ ///
+ /// Compute xxHash for the data byte span
+ ///
+ /// The source of data
+ /// The length of the data for hashing
+ /// The seed number
+ /// hash
+ public static unsafe uint ComputeHash(Span data, int length, uint seed = 0)
+ {
+ Debug.Assert(data != null);
+ Debug.Assert(length >= 0);
+ Debug.Assert(length <= data.Length);
+
+ fixed (byte* pData = &data[0])
+ {
+ return UnsafeComputeHash(pData, length, seed);
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static unsafe uint UnsafeComputeHash(byte* ptr, int length, uint seed)
+ {
+ byte* end = ptr + length;
uint h32;
if (length >= 16)
@@ -91,7 +124,6 @@
h32 ^= h32 >> 16;
return h32;
- }
}
}
}
\ No newline at end of file
diff --git a/src/Standart.Hash.xxHash/xxHash64.Stream.cs b/src/Standart.Hash.xxHash/xxHash64.Stream.cs
index 0cf3b88..f089143 100644
--- a/src/Standart.Hash.xxHash/xxHash64.Stream.cs
+++ b/src/Standart.Hash.xxHash/xxHash64.Stream.cs
@@ -1,7 +1,7 @@
namespace Standart.Hash.xxHash
{
- using System;
using System.Buffers;
+ using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
@@ -45,14 +45,14 @@
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe ulong Final(byte[] data, int l, ref ulong v1, ref ulong v2, ref ulong v3, ref ulong v4, long length, ulong seed)
- {
+ {
fixed (byte* pData = &data[0])
{
byte* ptr = pData;
byte* end = pData + l;
ulong h64;
- if (length >= 16)
+ if (length >= 32)
{
h64 = ((v1 << 1) | (v1 >> (64 - 1))) + // rotl 1
((v2 << 7) | (v2 >> (64 - 7))) + // rotl 7
@@ -140,6 +140,9 @@
/// The hash
public static ulong ComputeHash(Stream stream, int bufferSize = 8192, ulong seed = 0)
{
+ Debug.Assert(stream != null);
+ Debug.Assert(bufferSize > 32);
+
// Optimizing memory allocation
byte[] buffer = ArrayPool.Shared.Rent(bufferSize + 32);
@@ -170,7 +173,7 @@
Shift(buffer, l, ref v1, ref v2, ref v3, ref v4);
// Put remaining bytes to buffer
- xxBuffer.BlockCopy(buffer, l, buffer, 0, r);
+ UnsafeBuffer.BlockCopy(buffer, l, buffer, 0, r);
offset = r;
}
@@ -193,8 +196,11 @@
/// The buffer size
/// The seed number
/// The hash
- public static async Task ComputeHashAsync(Stream stream, int bufferSize = 8192, ulong seed = 0)
+ public static async ValueTask ComputeHashAsync(Stream stream, int bufferSize = 8192, ulong seed = 0)
{
+ Debug.Assert(stream != null);
+ Debug.Assert(bufferSize > 32);
+
// Optimizing memory allocation
byte[] buffer = ArrayPool.Shared.Rent(bufferSize + 32);
@@ -225,7 +231,7 @@
Shift(buffer, l, ref v1, ref v2, ref v3, ref v4);
// Put remaining bytes to buffer
- xxBuffer.BlockCopy(buffer, l, buffer, 0, r);
+ UnsafeBuffer.BlockCopy(buffer, l, buffer, 0, r);
offset = r;
}
diff --git a/src/Standart.Hash.xxHash/xxHash64.cs b/src/Standart.Hash.xxHash/xxHash64.cs
index 8e643ba..c2ce918 100644
--- a/src/Standart.Hash.xxHash/xxHash64.cs
+++ b/src/Standart.Hash.xxHash/xxHash64.cs
@@ -1,5 +1,9 @@
namespace Standart.Hash.xxHash
{
+ using System;
+ using System.Diagnostics;
+ using System.Runtime.CompilerServices;
+
public static partial class xxHash64
{
private const ulong p1 = 11400714785074694791UL;
@@ -17,10 +21,39 @@
/// hash
public static unsafe ulong ComputeHash(byte[] data, int length, ulong seed = 0)
{
+ Debug.Assert(data != null);
+ Debug.Assert(length >= 0);
+ Debug.Assert(length <= data.Length);
+
fixed (byte* pData = &data[0])
{
- byte* ptr = pData;
- byte* end = pData + length;
+ return UnsafeComputeHash(pData, length, seed);
+ }
+ }
+
+ ///
+ /// Compute xxHash for the data byte span
+ ///
+ /// The source of data
+ /// The length of the data for hashing
+ /// The seed number
+ /// hash
+ public static unsafe ulong ComputeHash(Span data, int length, ulong seed = 0)
+ {
+ Debug.Assert(data != null);
+ Debug.Assert(length >= 0);
+ Debug.Assert(length <= data.Length);
+
+ fixed (byte* pData = &data[0])
+ {
+ return UnsafeComputeHash(pData, length, seed);
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static unsafe ulong UnsafeComputeHash(byte* ptr, int length, ulong seed)
+ {
+ byte* end = ptr + length;
ulong h64;
if (length >= 32)
@@ -129,7 +162,6 @@
h64 ^= h64 >> 32;
return h64;
- }
}
}
}
\ No newline at end of file