Skip to content

Commit 16821cc

Browse files
committed
some more CRC-related refactorings
1 parent 7acd083 commit 16821cc

1 file changed

Lines changed: 73 additions & 43 deletions

File tree

HashLib/src/Checksum/HlpCRC.pas

Lines changed: 73 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ interface
1010
uses
1111
SysUtils,
1212
TypInfo,
13+
Generics.Collections,
1314
HlpHashLibTypes,
1415
HlpHash,
1516
HlpIHash,
@@ -577,20 +578,37 @@ interface
577578
TCRC = class sealed(THash, IChecksum, ICRC, ITransformBlock)
578579

579580
strict private
581+
type
582+
TCRCCacheValue = record
583+
Table: THashLibMatrixUInt64Array;
584+
FoldConstants: TCRCFoldConstants;
585+
end;
586+
587+
class var
588+
FCache: TDictionary<String, TCRCCacheValue>;
589+
580590
var
581591
FNames: THashLibStringArray;
582592
FWidth: Int32;
583593
FPolynomial, FInitialValue, FOutputXor, FCheckValue, FCRCMask,
584594
FCRCHighBitMask, FHash: UInt64;
585-
FIsInputReflected, FIsOutputReflected, FIsTableGenerated: Boolean;
586-
FHasPclmulConstants: Boolean;
595+
FIsInputReflected, FIsOutputReflected: Boolean;
587596

588-
FCRCTable: THashLibMatrixUInt64Array;
589-
FPclmulConstants: TCRCFoldConstants;
597+
FCacheEntry: TCRCCacheValue;
590598

591599
const
592600
MinTableWidth = Int32(7);
593601

602+
class constructor CreateCRCCache;
603+
class destructor DestroyCRCCache;
604+
605+
class function MakeCacheKey(APoly: UInt64; AWidth: Int32;
606+
AReflected: Boolean): String; static;
607+
class function GetOrCreateCacheEntry(APoly: UInt64; AWidth: Int32;
608+
AReflected: Boolean): TCRCCacheValue; static;
609+
class function GenerateCRCTable(APoly: UInt64; AWidth: Int32;
610+
AReflected: Boolean): THashLibMatrixUInt64Array; static;
611+
594612
function GetNames: THashLibStringArray; inline;
595613
procedure SetNames(const AValue: THashLibStringArray); inline;
596614
function GetWidth: Int32; inline;
@@ -608,7 +626,6 @@ TCRC = class sealed(THash, IChecksum, ICRC, ITransformBlock)
608626
function GetCheckValue: UInt64; inline;
609627
procedure SetCheckValue(AValue: UInt64); inline;
610628

611-
procedure GenerateTable();
612629
// tables work only for CRCs with width > 7
613630
procedure CalculateCRCbyTable(AData: PByte; ADataLength, AIndex: Int32);
614631
// fast bit by bit algorithm without augmented zero bytes.
@@ -753,7 +770,7 @@ procedure TCRC.CalculateCRCbyTable(AData: PByte; ADataLength, AIndex: Int32);
753770
LLength := ADataLength;
754771
LPtrData := AData + AIndex;
755772
LTemp := FHash;
756-
LCRCTable := FCRCTable;
773+
LCRCTable := FCacheEntry.Table;
757774

758775
if IsInputReflected then
759776
begin
@@ -872,20 +889,14 @@ procedure TCRC.CalculateCRCdirect(AData: PByte; ADataLength, AIndex: Int32);
872889
function TCRC.Clone(): IHash;
873890
var
874891
LHashInstance: TCRC;
875-
LIdx: Int32;
876892
begin
877893
LHashInstance := TCRC.Create(Width, Polynomial, InitialValue,
878894
IsInputReflected, IsOutputReflected, OutputXor, CheckValue,
879895
System.Copy(Names));
880896
LHashInstance.FCRCMask := FCRCMask;
881897
LHashInstance.FCRCHighBitMask := FCRCHighBitMask;
882898
LHashInstance.FHash := FHash;
883-
LHashInstance.FIsTableGenerated := FIsTableGenerated;
884-
LHashInstance.FHasPclmulConstants := FHasPclmulConstants;
885-
LHashInstance.FPclmulConstants := FPclmulConstants;
886-
System.SetLength(LHashInstance.FCRCTable, System.Length(FCRCTable));
887-
for LIdx := 0 to System.High(FCRCTable) do
888-
LHashInstance.FCRCTable[LIdx] := System.Copy(FCRCTable[LIdx]);
899+
LHashInstance.FCacheEntry := FCacheEntry;
889900
Result := LHashInstance;
890901
Result.BufferSize := BufferSize;
891902
end;
@@ -901,9 +912,6 @@ constructor TCRC.Create(AWidth: Int32; APolynomial, AInitial: UInt64;
901912
[AWidth]);
902913
end;
903914

904-
FIsTableGenerated := False;
905-
FHasPclmulConstants := False;
906-
907915
inherited Create(-1, -1); // Dummy State
908916

909917
case AWidth of
@@ -1409,50 +1417,83 @@ class function TCRC.CreateCRCObject(AValue: TCRCStandard): ICRC;
14091417

14101418
{$ENDREGION}
14111419

1412-
procedure TCRC.GenerateTable;
1420+
class constructor TCRC.CreateCRCCache;
1421+
begin
1422+
FCache := TDictionary<String, TCRCCacheValue>.Create;
1423+
end;
1424+
1425+
class destructor TCRC.DestroyCRCCache;
1426+
begin
1427+
FCache.Free;
1428+
end;
1429+
1430+
class function TCRC.MakeCacheKey(APoly: UInt64; AWidth: Int32;
1431+
AReflected: Boolean): String;
1432+
begin
1433+
Result := Format('Poly-%x:Width-%d:Reflected-%s',
1434+
[APoly, AWidth, BoolToStr(AReflected, True)]);
1435+
end;
1436+
1437+
class function TCRC.GenerateCRCTable(APoly: UInt64; AWidth: Int32;
1438+
AReflected: Boolean): THashLibMatrixUInt64Array;
14131439
var
14141440
LCRC: UInt64;
14151441
LIdx, LRow, LBit: Int32;
1416-
LReflectedPoly: UInt64;
1442+
LReflectedPoly, LHighBitMask, LMask: UInt64;
14171443
begin
1418-
System.SetLength(FCRCTable, 16);
1444+
System.SetLength(Result, 16);
14191445
for LIdx := 0 to 15 do
1420-
System.SetLength(FCRCTable[LIdx], 256);
1446+
System.SetLength(Result[LIdx], 256);
14211447

1422-
if IsInputReflected then
1448+
if AReflected then
14231449
begin
1424-
LReflectedPoly := Reflect(Polynomial, Width);
1450+
LReflectedPoly := Reflect(APoly, AWidth);
14251451
for LIdx := 0 to 255 do
14261452
begin
14271453
LCRC := UInt64(LIdx);
14281454
for LRow := 0 to 15 do
14291455
begin
14301456
for LBit := 0 to 7 do
14311457
LCRC := (LCRC shr 1) xor (UInt64(-Int64(LCRC and 1)) and LReflectedPoly);
1432-
FCRCTable[LRow][LIdx] := LCRC;
1458+
Result[LRow][LIdx] := LCRC;
14331459
end;
14341460
end;
14351461
end
14361462
else
14371463
begin
1464+
LHighBitMask := UInt64(1) shl (AWidth - 1);
1465+
LMask := ((LHighBitMask - 1) shl 1) or 1;
14381466
for LIdx := 0 to 255 do
14391467
begin
1440-
LCRC := UInt64(LIdx) shl (Width - 8);
1468+
LCRC := UInt64(LIdx) shl (AWidth - 8);
14411469
for LRow := 0 to 15 do
14421470
begin
14431471
for LBit := 0 to 7 do
14441472
begin
1445-
if (LCRC and FCRCHighBitMask) <> 0 then
1446-
LCRC := ((LCRC shl 1) xor Polynomial) and FCRCMask
1473+
if (LCRC and LHighBitMask) <> 0 then
1474+
LCRC := ((LCRC shl 1) xor APoly) and LMask
14471475
else
1448-
LCRC := (LCRC shl 1) and FCRCMask;
1476+
LCRC := (LCRC shl 1) and LMask;
14491477
end;
1450-
FCRCTable[LRow][LIdx] := LCRC;
1478+
Result[LRow][LIdx] := LCRC;
14511479
end;
14521480
end;
14531481
end;
1482+
end;
14541483

1455-
FIsTableGenerated := True;
1484+
class function TCRC.GetOrCreateCacheEntry(APoly: UInt64; AWidth: Int32;
1485+
AReflected: Boolean): TCRCCacheValue;
1486+
var
1487+
LKey: String;
1488+
begin
1489+
LKey := MakeCacheKey(APoly, AWidth, AReflected);
1490+
if not FCache.TryGetValue(LKey, Result) then
1491+
begin
1492+
Result.Table := GenerateCRCTable(APoly, AWidth, AReflected);
1493+
TGF2.GenerateFoldConstants(APoly, AWidth, AReflected,
1494+
Result.FoldConstants);
1495+
FCache.Add(LKey, Result);
1496+
end;
14561497
end;
14571498

14581499
procedure TCRC.Initialize;
@@ -1463,18 +1504,7 @@ procedure TCRC.Initialize;
14631504

14641505
if Width > MinTableWidth then
14651506
begin
1466-
if not FIsTableGenerated then
1467-
GenerateTable();
1468-
1469-
if not FHasPclmulConstants then
1470-
begin
1471-
if (Width >= 8) and (Width <= 64) then
1472-
begin
1473-
TGF2.GenerateFoldConstants(Polynomial, Width, IsInputReflected,
1474-
FPclmulConstants);
1475-
FHasPclmulConstants := True;
1476-
end;
1477-
end;
1507+
FCacheEntry := GetOrCreateCacheEntry(Polynomial, Width, IsInputReflected);
14781508

14791509
if IsInputReflected then
14801510
FHash := Reflect(FHash, Width);
@@ -1517,7 +1547,7 @@ procedure TCRC.TransformBytes(const AData: THashLibByteArray;
15171547

15181548
if Width > MinTableWidth then
15191549
begin
1520-
if FHasPclmulConstants and (ALength >= MinSimdBytes) then
1550+
if ALength >= MinSimdBytes then
15211551
begin
15221552
if IsInputReflected then
15231553
begin
@@ -1538,7 +1568,7 @@ procedure TCRC.TransformBytes(const AData: THashLibByteArray;
15381568
LState[1] := 0;
15391569
LProcessed := ALength and (not Int32(15));
15401570
FHash := LFoldFunc(LPtrAData + AIndex, UInt32(LProcessed),
1541-
@LState[0], @FPclmulConstants) and FCRCMask;
1571+
@LState[0], @FCacheEntry.FoldConstants) and FCRCMask;
15421572
LTail := ALength - LProcessed;
15431573
if LTail > 0 then
15441574
CalculateCRCbyTable(LPtrAData, LTail, AIndex + LProcessed);

0 commit comments

Comments
 (0)