@@ -10,6 +10,7 @@ interface
1010uses
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);
872889function TCRC.Clone (): IHash;
873890var
874891 LHashInstance: TCRC;
875- LIdx: Int32;
876892begin
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;
891902end ;
@@ -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;
14131439var
14141440 LCRC: UInt64;
14151441 LIdx, LRow, LBit: Int32;
1416- LReflectedPoly: UInt64;
1442+ LReflectedPoly, LHighBitMask, LMask : UInt64;
14171443begin
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 ;
14561497end ;
14571498
14581499procedure 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