< Summary

Information
Class: Hash.Core.CRC
Assembly: Hash.Core
File(s): /home/runner/work/HashCalculator/HashCalculator/src/Hash.Core/CRC.cs
Line coverage
100%
Covered lines: 83
Uncovered lines: 0
Coverable lines: 83
Total lines: 147
Line coverage: 100%
Branch coverage
97%
Covered branches: 36
Total branches: 37
Branch coverage: 97.2%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
Append(...)100%11100%
Reset()100%11100%
InitializeTable(...)100%2020100%
ReverseBits(...)100%22100%
CalculateHash(...)100%88100%
GetCurrentHashCore(...)85.71%77100%

File(s)

/home/runner/work/HashCalculator/HashCalculator/src/Hash.Core/CRC.cs

#LineLine coverage
 1// Copyright © 2021-present Hibi_10000
 2//
 3// This file is part of HashCalculator program.
 4//
 5// This program is free software: you can redistribute it and/or modify
 6// it under the terms of the GNU General Public License as published by
 7// the Free Software Foundation, either version 3 of the License, or
 8// (at your option) any later version.
 9//
 10// This program is distributed in the hope that it will be useful,
 11// but WITHOUT ANY WARRANTY; without even the implied warranty of
 12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 13// GNU General Public License for more details.
 14//
 15// You should have received a copy of the GNU General Public License
 16// along with this program. If not, see <http://www.gnu.org/licenses/>.
 17
 18using System;
 19using System.Buffers.Binary;
 20using System.IO.Hashing;
 21
 22namespace Hash.Core;
 23
 24public class CRC8_CCITT () : CRC(sizeof(byte), 0x07, 0x00, false);
 25public class CRC16_CCITT() : CRC(sizeof(ushort), 0x1021, 0x0000, true);
 26public class CRC16_IBM  () : CRC(sizeof(ushort), 0x8005, 0x0000, true);
 27public class CRC32      () : CRC(sizeof(uint), 0x04C11DB7, 0xffffffff, true);
 28public class CRC32C     () : CRC(sizeof(uint), 0x1EDC6F41, 0xffffffff, true);
 29public class CRC64_ECMA () : CRC(sizeof(ulong), 0x42F0E1EBA9EA3693, 0x0000000000000000, false);
 30public class CRC64_ISO  () : CRC(sizeof(ulong), 0x000000000000001B, 0xffffffffffffffff, true);
 31public class CRC64_XZ   () : CRC(sizeof(ulong), 0x42F0E1EBA9EA3693, 0xffffffffffffffff, true);
 32
 33public class CRC : NonCryptographicHashAlgorithm
 34{
 35    private ulong _hash;
 36    private readonly ulong[] _table;
 37    private readonly ulong _seed;
 38    private readonly bool _refOut;
 39    private readonly ulong _xorOut;
 40    private readonly int _size;
 41
 142    protected internal CRC(int size, ulong poly, ulong init, bool refInOut) : base(size)
 143    {
 144        _table = InitializeTable(size, poly, refInOut);
 145        _seed = init;
 146        _refOut = refInOut;
 147        _xorOut = init;
 148        _size = size;
 149        _hash = _seed;
 150    }
 51
 52    public override void Append(ReadOnlySpan<byte> source)
 153    {
 154        _hash = CalculateHash(_size, _table, _hash, _refOut, source);
 155    }
 56
 57    public override void Reset()
 158    {
 159        _hash = _seed;
 160    }
 61
 62    private static ulong[] InitializeTable(int size, ulong poly, bool refIn)
 163    {
 164        ulong[] table = new ulong[256]; //byte.MaxValue + 1
 165        if (refIn)
 166        {
 167            for (int i = 0; i < 256; i++)
 168            {
 169                ulong entry = (ulong)i;
 170                for (int j = 0; j < 8; j++)
 171                {
 172                    if ((entry & 1) != 0)
 173                        entry = (entry >> 1) ^ ReverseBits(poly, size * 8);
 74                    else
 175                        entry >>= 1;
 176                }
 177                table[i] = size == sizeof(byte) ? (byte)entry : entry;
 178            }
 179        }
 80        else
 181        {
 182            for (int i = 0; i < 256; i++)
 183            {
 184                ulong entry = size == sizeof(byte) ? (ulong)i : (ulong)i << 56;
 185                for (int j = 0; j < 8; j++)
 186                {
 187                    if ((entry & ReverseBits(1, size * 8)) != 0)
 188                        entry = (entry << 1) ^ poly;
 89                    else
 190                        entry <<= 1;
 191                }
 192                table[i] = size == sizeof(byte) ? (byte)entry : entry;
 193            }
 194        }
 195        return table;
 196    }
 97
 98    private static ulong ReverseBits(ulong source, int size)
 199    {
 1100        ulong reverse = 0;
 1101        for (int i = 0; i < size; i++)
 1102        {
 1103            reverse = (reverse << 1) | ((source >> i) & 1);
 1104        }
 1105        return reverse;
 1106    }
 107
 108    private static ulong CalculateHash(int size, ulong[] table, ulong seed, bool refOut, ReadOnlySpan<byte> buffer)
 1109    {
 1110        ulong crc = seed;
 1111        if (refOut)
 1112        {
 1113            foreach (byte bufferEntry in buffer)
 1114            {
 1115                crc = (crc >> 8) ^ table[(byte)(bufferEntry ^ crc)];
 1116            }
 1117        }
 118        else
 1119        {
 1120            foreach (byte bufferEntry in buffer)
 1121            {
 1122                crc = (crc << 8) ^ table[(byte)(bufferEntry ^ (size == sizeof(byte) ? crc : crc >> 56))];
 1123            }
 1124        }
 1125        return crc;
 1126    }
 127
 128    protected override void GetCurrentHashCore(Span<byte> destination)
 1129    {
 1130        ulong hash = _hash ^ _xorOut;
 1131        switch (_size)
 132        {
 133            case sizeof(byte  ): //1  8
 1134                destination[0] = (byte)hash;
 1135                break;
 136            case sizeof(ushort): //2 16
 1137                BinaryPrimitives.WriteUInt16BigEndian(destination, (ushort)hash);
 1138                break;
 139            case sizeof(uint  ): //4 32
 1140                BinaryPrimitives.WriteUInt32BigEndian(destination, (uint)  hash);
 1141                break;
 142            case sizeof(ulong ): //8 64
 1143                BinaryPrimitives.WriteUInt64BigEndian(destination,         hash);
 1144                break;
 145        }
 1146    }
 147}