| File: System\IO\Hashing\XxHash32.State.cs | Web Access |
| Project: src\runtime\src\libraries\System.IO.Hashing\src\System.IO.Hashing.csproj (System.IO.Hashing) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Buffers.Binary; using System.Diagnostics; using System.Numerics; using System.Runtime.CompilerServices; using static System.IO.Hashing.XxHashShared; // Implemented from the specification at // https://github.com/Cyan4973/xxHash/blob/f9155bd4c57e2270a4ffbb176485e5d713de1c9b/doc/xxhash_spec.md namespace System.IO.Hashing { public sealed partial class XxHash32 { private struct State { private uint _acc1; private uint _acc2; private uint _acc3; private uint _acc4; private readonly uint _smallAcc; private bool _hadFullStripe; internal State(uint seed) { _acc1 = seed + unchecked(Prime32_1 + Prime32_2); _acc2 = seed + Prime32_2; _acc3 = seed; _acc4 = seed - Prime32_1; _smallAcc = seed + Prime32_5; _hadFullStripe = false; } internal void ProcessStripe(ReadOnlySpan<byte> source) { Debug.Assert(source.Length >= StripeSize); source = source.Slice(0, StripeSize); _acc1 = ApplyRound(_acc1, source); _acc2 = ApplyRound(_acc2, source.Slice(sizeof(uint))); _acc3 = ApplyRound(_acc3, source.Slice(2 * sizeof(uint))); _acc4 = ApplyRound(_acc4, source.Slice(3 * sizeof(uint))); _hadFullStripe = true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private readonly uint Converge() { return BitOperations.RotateLeft(_acc1, 1) + BitOperations.RotateLeft(_acc2, 7) + BitOperations.RotateLeft(_acc3, 12) + BitOperations.RotateLeft(_acc4, 18); } private static uint ApplyRound(uint acc, ReadOnlySpan<byte> lane) { acc += BinaryPrimitives.ReadUInt32LittleEndian(lane) * Prime32_2; acc = BitOperations.RotateLeft(acc, 13); acc *= Prime32_1; return acc; } internal readonly uint Complete(int length, ReadOnlySpan<byte> remaining) { uint acc = _hadFullStripe ? Converge() : _smallAcc; acc += (uint)length; while (remaining.Length >= sizeof(uint)) { uint lane = BinaryPrimitives.ReadUInt32LittleEndian(remaining); acc += lane * Prime32_3; acc = BitOperations.RotateLeft(acc, 17); acc *= Prime32_4; remaining = remaining.Slice(sizeof(uint)); } for (int i = 0; i < remaining.Length; i++) { uint lane = remaining[i]; acc += lane * Prime32_5; acc = BitOperations.RotateLeft(acc, 11); acc *= Prime32_1; } acc ^= (acc >> 15); acc *= Prime32_2; acc ^= (acc >> 13); acc *= Prime32_3; acc ^= (acc >> 16); return acc; } } } }