namespace Standart.Hash.xxHash
{
using System.Buffers;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
public static partial class xxHash32
{
///
/// Compute xxHash for the async stream
///
/// The stream of data
/// The buffer size
/// 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);
// Optimizing memory allocation
byte[] buffer = ArrayPool.Shared.Rent(bufferSize + 16);
int readBytes;
int offset = 0;
long length = 0;
// Prepare the seed vector
uint v1 = seed + p1 + p2;
uint v2 = seed + p2;
uint v3 = seed + 0;
uint v4 = seed - p1;
try
{
// Read flow of bytes
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;
if (offset < 16) continue;
int r = offset % 16; // remain
int l = offset - r; // length
// Process the next chunk
UnsafeAlign(buffer, l, ref v1, ref v2, ref v3, ref v4);
// Put remaining bytes to buffer
UnsafeBuffer.BlockCopy(buffer, l, buffer, 0, r);
offset = r;
}
// Process the final chunk
uint h32 = UnsafeFinal(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed);
return h32;
}
finally
{
// Free memory
ArrayPool.Shared.Return(buffer);
}
}
}
}