File: System\IO\Hashing\Crc64ParameterSet.cs
Web Access
Project: src\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;
 
namespace System.IO.Hashing
{
    /// <summary>
    ///   Represents a set of parameters that define the behavior of a CRC-64 hash algorithm.
    /// </summary>
    /// <remarks>
    ///   <para>
    ///     The parameter-set instance precomputes values to be used in the CRC calculation.
    ///     As such, callers are expected to create a single instance of the parameter set and
    ///     reuse it for multiple hash calculations.
    ///   </para>
    /// </remarks>
    public partial class Crc64ParameterSet
    {
        /// <summary>Gets the polynomial value used for the CRC calculation.</summary>
        /// <value>The polynomial value used for the CRC calculation.</value>
        [CLSCompliant(false)]
        public ulong Polynomial { get; }
 
        /// <summary>Gets the initial value (seed) for the CRC calculation.</summary>
        /// <value>The initial value (seed) for the CRC calculation.</value>
        [CLSCompliant(false)]
        public ulong InitialValue { get; }
 
        /// <summary>Gets the value to XOR with the final CRC result.</summary>
        /// <value>The value to XOR with the final CRC result.</value>
        /// <remarks>For reflected-output CRC values, the final XOR is done after the bit-reflection.</remarks>
        [CLSCompliant(false)]
        public ulong FinalXorValue { get; }
 
        /// <summary>
        ///   Gets a value indicating whether the input and output bytes are most-significant-bit (MSB) first, or last.
        /// </summary>
        /// <value>
        ///   <see langword="true"/> if the MSB is the least significant bit of the last byte;
        ///   <see langword="false"/> if the MSB is the most significant bit of the first byte.
        /// </value>
        public bool ReflectValues { get; }
 
        private Crc64ParameterSet(ulong polynomial, ulong initialValue, ulong finalXorValue, bool reflectValues)
        {
            Polynomial = polynomial;
            InitialValue = initialValue;
            FinalXorValue = finalXorValue;
            ReflectValues = reflectValues;
        }
 
        /// <summary>Creates a new <see cref="Crc64ParameterSet"/> with the specified parameters.</summary>
        /// <param name="polynomial">The polynomial value used for the CRC calculation.</param>
        /// <param name="initialValue">The initial value (seed) for the CRC calculation.</param>
        /// <param name="finalXorValue">The value to XOR with the final CRC result.</param>
        /// <param name="reflectValues">
        ///   <see langword="true"/> if the input values are least-significant-bit (LSB) first;
        ///   <see langword="false"/> if the input values are most-significant-bit (MSB) first.
        /// </param>
        /// <returns>A new <see cref="Crc64ParameterSet"/> instance.</returns>
        [CLSCompliant(false)]
        public static Crc64ParameterSet Create(
            ulong polynomial,
            ulong initialValue,
            ulong finalXorValue,
            bool reflectValues)
        {
            return reflectValues ?
                new ReflectedTableBasedCrc64(polynomial, initialValue, finalXorValue) :
                new ForwardTableBasedCrc64(polynomial, initialValue, finalXorValue);
        }
 
        internal void WriteCrcToSpan(ulong crc, Span<byte> destination)
        {
            if (ReflectValues)
            {
                BinaryPrimitives.WriteUInt64LittleEndian(destination, crc);
            }
            else
            {
                BinaryPrimitives.WriteUInt64BigEndian(destination, crc);
            }
        }
 
        internal virtual ulong Update(ulong value, ReadOnlySpan<byte> source) =>
            throw new NotImplementedException();
 
        internal ulong Finalize(ulong value)
        {
            ulong crc = value;
 
            // If, in the future, refIn!=refOut is supported, then the
            // answer should (probably) be bit-reversed here before the final XOR.
 
            return crc ^ FinalXorValue;
        }
 
        private static ulong ReverseBits(ulong value)
        {
#if NET
            if (System.Runtime.Intrinsics.Arm.ArmBase.Arm64.IsSupported)
            {
                return System.Runtime.Intrinsics.Arm.ArmBase.Arm64.ReverseElementBits(value);
            }
#endif
 
            value = ((value & 0xAAAAAAAAAAAAAAAA) >> 1) | ((value & 0x5555555555555555) << 1);
            value = ((value & 0xCCCCCCCCCCCCCCCC) >> 2) | ((value & 0x3333333333333333) << 2);
            value = ((value & 0xF0F0F0F0F0F0F0F0) >> 4) | ((value & 0x0F0F0F0F0F0F0F0F) << 4);
 
            return BinaryPrimitives.ReverseEndianness(value);
        }
    }
}