(data), data.Length);
+uint h32_4 = xxHash32.ComputeHash(new MemoryStream(data));
+uint h32_5 = await xxHash32.ComputeHashAsync(new MemoryStream(data));
```
---
diff --git a/nuget.props b/nuget.props
index 1a6385d..62eae8a 100644
--- a/nuget.props
+++ b/nuget.props
@@ -3,7 +3,7 @@
netstandard2.0
Standart.Hash.xxHash
- 1.0.5
+ 1.0.6
Standart.Hash.xxHash
Standart.Hash.xxHash
Alexander Melnik
diff --git a/src/Standart.Hash.xxHash.Perf/xxHashBenchmark.cs b/src/Standart.Hash.xxHash.Perf/xxHashBenchmark.cs
index 241489d..a94da32 100644
--- a/src/Standart.Hash.xxHash.Perf/xxHashBenchmark.cs
+++ b/src/Standart.Hash.xxHash.Perf/xxHashBenchmark.cs
@@ -8,7 +8,7 @@
[RPlotExporter, RankColumn]
[MinColumn, MaxColumn]
[MemoryDiagnoser]
- //[DisassemblyDiagnoser(printAsm: true, printSource: true)]
+ // [DisassemblyDiagnoser(printAsm: true, printSource: true)]
public class xxHashBenchmark
{
const int KB = 1024;
@@ -43,6 +43,13 @@
Span span = new Span(data);
return xxHash32.ComputeHash(span, span.Length);
}
+
+ [Benchmark]
+ public uint Hash32_ReadOnlySpan()
+ {
+ ReadOnlySpan span = new ReadOnlySpan(data);
+ return xxHash32.ComputeHash(span, span.Length);
+ }
[Benchmark]
public uint Hash32_Stream()
@@ -71,6 +78,13 @@
return xxHash64.ComputeHash(span, span.Length);
}
+ [Benchmark]
+ public ulong Hash64_ReadOnlySpan()
+ {
+ ReadOnlySpan span = new ReadOnlySpan(data);
+ return xxHash64.ComputeHash(span, span.Length);
+ }
+
[Benchmark]
public ulong Hash64_Stream()
{
diff --git a/src/Standart.Hash.xxHash.Test/xxHash32Test.cs b/src/Standart.Hash.xxHash.Test/xxHash32Test.cs
index 61214a8..8996133 100644
--- a/src/Standart.Hash.xxHash.Test/xxHash32Test.cs
+++ b/src/Standart.Hash.xxHash.Test/xxHash32Test.cs
@@ -2,6 +2,7 @@
{
using System;
using System.IO;
+ using System.Threading;
using System.Threading.Tasks;
using Xunit;
@@ -13,14 +14,17 @@
// Arrange
byte[] data = {0xde};
Span span = new Span(data);
+ ReadOnlySpan rspan = new ReadOnlySpan(data);
// Act
uint hash1 = xxHash32.ComputeHash(data, data.Length);
uint hash2 = xxHash32.ComputeHash(span, span.Length);
+ uint hash3 = xxHash32.ComputeHash(rspan, rspan.Length);
// Assert
Assert.Equal(hash1, (uint) 0x2330eac0);
Assert.Equal(hash2, (uint) 0x2330eac0);
+ Assert.Equal(hash3, (uint) 0x2330eac0);
}
[Fact]
@@ -29,14 +33,17 @@
// Arrange
byte[] data = {0xde, 0x55, 0x47, 0x7f, 0x14};
Span span = new Span(data);
+ ReadOnlySpan rspan = new ReadOnlySpan(data);
// Act
uint hash1 = xxHash32.ComputeHash(data, data.Length);
uint hash2 = xxHash32.ComputeHash(span, span.Length);
+ uint hash3 = xxHash32.ComputeHash(rspan, rspan.Length);
// Assert
Assert.Equal(hash1, (uint) 0x112348ba);
Assert.Equal(hash2, (uint) 0x112348ba);
+ Assert.Equal(hash3, (uint) 0x112348ba);
}
[Fact]
@@ -49,14 +56,17 @@
0x22, 0x3a, 0x40, 0x96, 0x56, 0xc5, 0xdc, 0xbb
};
Span span = new Span(data);
+ ReadOnlySpan rspan = new ReadOnlySpan(data);
// Act
uint hash1 = xxHash32.ComputeHash(data, data.Length);
uint hash2 = xxHash32.ComputeHash(span, span.Length);
+ uint hash3 = xxHash32.ComputeHash(rspan, rspan.Length);
// Assert
Assert.Equal(hash1, (uint) 0xcdf89609);
Assert.Equal(hash2, (uint) 0xcdf89609);
+ Assert.Equal(hash3, (uint) 0xcdf89609);
}
[Fact]
@@ -70,14 +80,17 @@
0x0e
};
Span span = new Span(data);
+ ReadOnlySpan rspan = new ReadOnlySpan(data);
// Act
uint hash1 = xxHash32.ComputeHash(data, data.Length);
uint hash2 = xxHash32.ComputeHash(span, span.Length);
+ uint hash3 = xxHash32.ComputeHash(rspan, rspan.Length);
// Assert
Assert.Equal(hash1, (uint) 0xbca8f924);
Assert.Equal(hash2, (uint) 0xbca8f924);
+ Assert.Equal(hash3, (uint) 0xbca8f924);
}
[Fact]
@@ -91,14 +104,17 @@
0x0e, 0x59, 0x4d, 0x42, 0xc5
};
Span span = new Span(data);
+ ReadOnlySpan rspan = new ReadOnlySpan(data);
// Act
uint hash1 = xxHash32.ComputeHash(data, data.Length);
uint hash2 = xxHash32.ComputeHash(span, span.Length);
+ uint hash3 = xxHash32.ComputeHash(rspan, rspan.Length);
// Assert
Assert.Equal(hash1, (uint) 0xf4518e14);
Assert.Equal(hash2, (uint) 0xf4518e14);
+ Assert.Equal(hash3, (uint) 0xf4518e14);
}
[Fact]
@@ -113,14 +129,17 @@
0x1c, 0x2c, 0xc9, 0x38, 0x7d, 0x43, 0x83, 0x11,
};
Span span = new Span(data);
+ ReadOnlySpan rspan = new ReadOnlySpan(data);
// Act
uint hash1 = xxHash32.ComputeHash(data, data.Length);
uint hash2 = xxHash32.ComputeHash(span, span.Length);
+ uint hash3 = xxHash32.ComputeHash(rspan, rspan.Length);
// Assert
Assert.Equal(hash1, (uint) 0xf8497daa);
Assert.Equal(hash2, (uint) 0xf8497daa);
+ Assert.Equal(hash3, (uint) 0xf8497daa);
}
[Fact]
@@ -348,6 +367,29 @@
// Assert
Assert.Equal(hash, (uint) 0xf8497daa);
}
+
+ [Fact]
+ public async Task Compute_hash32_for_the_async_stream_32_with_cancelation_token()
+ {
+ // Arrange
+ 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,
+ };
+ CancellationTokenSource tokenSource = new CancellationTokenSource();
+
+ // Act
+ tokenSource.Cancel();
+
+ // Assert
+ await Assert.ThrowsAsync(async () =>
+ {
+ await xxHash32.ComputeHashAsync(new MemoryStream(data), 4096, 0, tokenSource.Token);
+ });
+ }
[Fact]
public async Task Compute_hash32_for_the_async_random_stream()
diff --git a/src/Standart.Hash.xxHash.Test/xxHash64Test.cs b/src/Standart.Hash.xxHash.Test/xxHash64Test.cs
index 013159f..b8e7b38 100644
--- a/src/Standart.Hash.xxHash.Test/xxHash64Test.cs
+++ b/src/Standart.Hash.xxHash.Test/xxHash64Test.cs
@@ -2,6 +2,7 @@
{
using System;
using System.IO;
+ using System.Threading;
using System.Threading.Tasks;
using Xunit;
@@ -13,14 +14,17 @@
// Arrange
byte[] data = {0x60};
Span span = new Span(data);
+ ReadOnlySpan rspan = new ReadOnlySpan(data);
// Act
ulong hash1 = xxHash64.ComputeHash(data, data.Length);
- ulong hash2 = xxHash64.ComputeHash(span, data.Length);
+ ulong hash2 = xxHash64.ComputeHash(span, span.Length);
+ ulong hash3 = xxHash64.ComputeHash(rspan, rspan.Length);
// Assert
Assert.Equal(hash1, (ulong) 0xb3e7ca6ca5ba3445);
Assert.Equal(hash2, (ulong) 0xb3e7ca6ca5ba3445);
+ Assert.Equal(hash3, (ulong) 0xb3e7ca6ca5ba3445);
}
[Fact]
@@ -29,14 +33,17 @@
// Arrange
byte[] data = {0x60, 0x82, 0x40, 0x77, 0x8a};
Span span = new Span(data);
+ ReadOnlySpan rspan = new ReadOnlySpan(data);
// Act
ulong hash1 = xxHash64.ComputeHash(data, data.Length);
- ulong hash2 = xxHash64.ComputeHash(span, data.Length);
+ ulong hash2 = xxHash64.ComputeHash(span, span.Length);
+ ulong hash3 = xxHash64.ComputeHash(rspan, rspan.Length);
// Assert
Assert.Equal(hash1, (ulong) 0x917b11ed024938fc);
Assert.Equal(hash2, (ulong) 0x917b11ed024938fc);
+ Assert.Equal(hash3, (ulong) 0x917b11ed024938fc);
}
[Fact]
@@ -49,14 +56,17 @@
0x85, 0x1f, 0xa6, 0x86, 0x34,
};
Span span = new Span(data);
+ ReadOnlySpan rspan = new ReadOnlySpan(data);
// Act
ulong hash1 = xxHash64.ComputeHash(data, data.Length);
- ulong hash2 = xxHash64.ComputeHash(span, data.Length);
+ ulong hash2 = xxHash64.ComputeHash(span, span.Length);
+ ulong hash3 = xxHash64.ComputeHash(rspan, rspan.Length);
// Assert
Assert.Equal(hash1, (ulong) 0x9d1cb0d181d58bee);
Assert.Equal(hash2, (ulong) 0x9d1cb0d181d58bee);
+ Assert.Equal(hash3, (ulong) 0x9d1cb0d181d58bee);
}
[Fact]
@@ -71,14 +81,17 @@
0x4b, 0x0f, 0x90, 0x4e, 0xf5, 0x57, 0x21, 0x21,
};
Span span = new Span(data);
+ ReadOnlySpan rspan = new ReadOnlySpan(data);
// Act
ulong hash1 = xxHash64.ComputeHash(data, data.Length);
- ulong hash2 = xxHash64.ComputeHash(span, data.Length);
+ ulong hash2 = xxHash64.ComputeHash(span, span.Length);
+ ulong hash3 = xxHash64.ComputeHash(rspan, rspan.Length);
// Assert
Assert.Equal(hash1, (ulong) 0x9233096b7804e12c);
Assert.Equal(hash2, (ulong) 0x9233096b7804e12c);
+ Assert.Equal(hash3, (ulong) 0x9233096b7804e12c);
}
[Fact]
@@ -97,14 +110,17 @@
0x7e, 0x28, 0xce, 0x46, 0x85, 0xb7, 0x2b, 0x16,
};
Span span = new Span(data);
+ ReadOnlySpan rspan = new ReadOnlySpan(data);
// Act
ulong hash1 = xxHash64.ComputeHash(data, data.Length);
- ulong hash2 = xxHash64.ComputeHash(span, data.Length);
+ ulong hash2 = xxHash64.ComputeHash(span, span.Length);
+ ulong hash3 = xxHash64.ComputeHash(rspan, rspan.Length);
// Assert
Assert.Equal(hash1, (ulong) 0x4c0a65b1ef9ea060);
Assert.Equal(hash2, (ulong) 0x4c0a65b1ef9ea060);
+ Assert.Equal(hash3, (ulong) 0x4c0a65b1ef9ea060);
}
[Fact]
@@ -192,6 +208,7 @@
Assert.Equal(hash, (ulong) 0x4c0a65b1ef9ea060);
}
+
[Fact]
public void Compute_hash64_for_the_random_stream()
{
@@ -308,6 +325,33 @@
Assert.Equal(hash, (ulong) 0x4c0a65b1ef9ea060);
}
+ [Fact]
+ public async Task Compute_hash64_for_the_async_stream_64_with_cancelation_token()
+ {
+ // Arrange
+ byte[] data =
+ {
+ 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,
+ };
+ CancellationTokenSource tokenSource = new CancellationTokenSource();
+
+ // Act
+ tokenSource.Cancel();
+
+ // Assert
+ await Assert.ThrowsAsync(async() =>
+ {
+ await xxHash64.ComputeHashAsync(new MemoryStream(data), 8192, 0, tokenSource.Token);
+ });
+ }
+
[Fact]
public async Task Compute_hash64_for_the_async_random_stream()
{
diff --git a/src/Standart.Hash.xxHash/xxHash32.Async.cs b/src/Standart.Hash.xxHash/xxHash32.Async.cs
index 2dc935d..9f51024 100644
--- a/src/Standart.Hash.xxHash/xxHash32.Async.cs
+++ b/src/Standart.Hash.xxHash/xxHash32.Async.cs
@@ -3,6 +3,7 @@
using System.Buffers;
using System.Diagnostics;
using System.IO;
+ using System.Threading;
using System.Threading.Tasks;
public static partial class xxHash32
@@ -15,6 +16,20 @@
/// The seed number
/// The hash
public static async ValueTask ComputeHashAsync(Stream stream, int bufferSize = 4096, uint seed = 0)
+ {
+ return await ComputeHashAsync(stream, bufferSize, seed, CancellationToken.None);
+ }
+
+
+ ///
+ /// Compute xxHash for the async stream
+ ///
+ /// The stream of data
+ /// The buffer size
+ /// The seed number
+ /// The cancellation token
+ /// The hash
+ public static async ValueTask ComputeHashAsync(Stream stream, int bufferSize, uint seed, CancellationToken cancellationToken)
{
Debug.Assert(stream != null);
Debug.Assert(bufferSize > 16);
@@ -35,8 +50,14 @@
try
{
// Read flow of bytes
- while ((readBytes = await stream.ReadAsync(buffer, offset, bufferSize).ConfigureAwait(false)) > 0)
+ while ((readBytes = await stream.ReadAsync(buffer, offset, bufferSize, cancellationToken).ConfigureAwait(false)) > 0)
{
+ // Exit if the operation is canceled
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return await Task.FromCanceled(cancellationToken);
+ }
+
length = length + readBytes;
offset = offset + readBytes;
diff --git a/src/Standart.Hash.xxHash/xxHash32.Span.cs b/src/Standart.Hash.xxHash/xxHash32.Span.cs
index a59fc50..1e7114d 100644
--- a/src/Standart.Hash.xxHash/xxHash32.Span.cs
+++ b/src/Standart.Hash.xxHash/xxHash32.Span.cs
@@ -3,6 +3,8 @@ using System.Diagnostics;
namespace Standart.Hash.xxHash
{
+ using System.Runtime.InteropServices;
+
public static partial class xxHash32
{
///
@@ -18,7 +20,26 @@ namespace Standart.Hash.xxHash
Debug.Assert(length >= 0);
Debug.Assert(length <= data.Length);
- fixed (byte* pData = &data[0])
+ fixed (byte* pData = &MemoryMarshal.GetReference(data))
+ {
+ 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(ReadOnlySpan data, int length, uint seed = 0)
+ {
+ Debug.Assert(data != null);
+ Debug.Assert(length >= 0);
+ Debug.Assert(length <= data.Length);
+
+ fixed (byte* pData = &MemoryMarshal.GetReference(data))
{
return UnsafeComputeHash(pData, length, seed);
}
diff --git a/src/Standart.Hash.xxHash/xxHash64.Async.cs b/src/Standart.Hash.xxHash/xxHash64.Async.cs
index 3a3b5db..896611c 100644
--- a/src/Standart.Hash.xxHash/xxHash64.Async.cs
+++ b/src/Standart.Hash.xxHash/xxHash64.Async.cs
@@ -3,6 +3,7 @@
using System.Buffers;
using System.Diagnostics;
using System.IO;
+ using System.Threading;
using System.Threading.Tasks;
public static partial class xxHash64
@@ -15,6 +16,19 @@
/// The seed number
/// The hash
public static async ValueTask ComputeHashAsync(Stream stream, int bufferSize = 8192, ulong seed = 0)
+ {
+ return await ComputeHashAsync(stream, bufferSize, seed, CancellationToken.None);
+ }
+
+ ///
+ /// Compute xxHash for the async stream
+ ///
+ /// The stream of data
+ /// The buffer size
+ /// The seed number
+ /// The cancelation token
+ /// The hash
+ public static async ValueTask ComputeHashAsync(Stream stream, int bufferSize, ulong seed, CancellationToken cancellationToken)
{
Debug.Assert(stream != null);
Debug.Assert(bufferSize > 32);
@@ -35,8 +49,14 @@
try
{
// Read flow of bytes
- while ((readBytes = await stream.ReadAsync(buffer, offset, bufferSize).ConfigureAwait(false)) > 0)
- {
+ while ((readBytes = await stream.ReadAsync(buffer, offset, bufferSize, cancellationToken).ConfigureAwait(false)) > 0)
+ {
+ // Exit if the operation is canceled
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return await Task.FromCanceled(cancellationToken);
+ }
+
length = length + readBytes;
offset = offset + readBytes;
diff --git a/src/Standart.Hash.xxHash/xxHash64.Span.cs b/src/Standart.Hash.xxHash/xxHash64.Span.cs
index f393a8c..d8dbf0e 100644
--- a/src/Standart.Hash.xxHash/xxHash64.Span.cs
+++ b/src/Standart.Hash.xxHash/xxHash64.Span.cs
@@ -2,6 +2,7 @@
{
using System;
using System.Diagnostics;
+ using System.Runtime.InteropServices;
public static partial class xxHash64
{
@@ -18,7 +19,26 @@
Debug.Assert(length >= 0);
Debug.Assert(length <= data.Length);
- fixed (byte* pData = &data[0])
+ fixed (byte* pData = &MemoryMarshal.GetReference(data))
+ {
+ 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(ReadOnlySpan data, int length, ulong seed = 0)
+ {
+ Debug.Assert(data != null);
+ Debug.Assert(length >= 0);
+ Debug.Assert(length <= data.Length);
+
+ fixed (byte* pData = &MemoryMarshal.GetReference(data))
{
return UnsafeComputeHash(pData, length, seed);
}