Esempio n. 1
0
        /// <summary>
        /// Compute xxHash for the async stream
        /// </summary>
        /// <param name="stream">The stream of data</param>
        /// <param name="bufferSize">The buffer size</param>
        /// <param name="seed">The seed number</param>
        /// <param name="cancellationToken">The cancellation token</param>
        /// <returns>The hash</returns>
        public static async ValueTask <uint> ComputeHashAsync(Stream stream, int bufferSize, uint seed, CancellationToken cancellationToken)
        {
            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream));
            }

            Debug.Assert(stream != null);
            Debug.Assert(bufferSize > 16);

            // Optimizing memory allocation
            byte[] buffer = ArrayPool <byte> .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(true)) > 0)
                {
                    // Exit if the operation is canceled
                    if (cancellationToken.IsCancellationRequested)
                    {
                        return(await Task.FromCanceled <uint>(cancellationToken).ConfigureAwait(true));
                    }

                    length += readBytes;
                    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 <byte> .Shared.Return(buffer);
            }
        }