11using System ;
2+ using System . Runtime . CompilerServices ;
23
34namespace ICSharpCode . SharpZipLib . Checksum
45{
@@ -25,9 +26,19 @@ namespace ICSharpCode.SharpZipLib.Checksum
2526 /// out is a one). We start with the highest power (least significant bit) of
2627 /// q and repeat for all eight bits of q.
2728 ///
28- /// The table is simply the CRC of all possible eight bit values. This is all
29- /// the information needed to generate CRC's on data a byte at a time for all
30- /// combinations of CRC register values and incoming bytes.
29+ /// This implementation uses sixteen lookup tables stored in one linear array
30+ /// to implement the slicing-by-16 algorithm, a variant of the slicing-by-8
31+ /// algorithm described in this Intel white paper:
32+ ///
33+ /// https://web.archive.org/web/20120722193753/http://download.intel.com/technology/comms/perfnet/download/slicing-by-8.pdf
34+ ///
35+ /// The first lookup table is simply the CRC of all possible eight bit values.
36+ /// Each successive lookup table is derived from the original table generated
37+ /// by Sarwate's algorithm. Slicing a 16-bit input and XORing the outputs
38+ /// together will produce the same output as a byte-by-byte CRC loop with
39+ /// fewer arithmetic and bit manipulation operations, at the cost of increased
40+ /// memory consumed by the lookup tables. (Slicing-by-16 requires a 16KB table,
41+ /// which is still small enough to fit in most processors' L1 cache.)
3142 /// </remarks>
3243 public sealed class BZip2Crc : IChecksum
3344 {
@@ -36,72 +47,7 @@ public sealed class BZip2Crc : IChecksum
3647 private const uint crcInit = 0xFFFFFFFF ;
3748 //const uint crcXor = 0x00000000;
3849
39- private static readonly uint [ ] crcTable = {
40- 0X00000000 , 0X04C11DB7 , 0X09823B6E , 0X0D4326D9 ,
41- 0X130476DC , 0X17C56B6B , 0X1A864DB2 , 0X1E475005 ,
42- 0X2608EDB8 , 0X22C9F00F , 0X2F8AD6D6 , 0X2B4BCB61 ,
43- 0X350C9B64 , 0X31CD86D3 , 0X3C8EA00A , 0X384FBDBD ,
44- 0X4C11DB70 , 0X48D0C6C7 , 0X4593E01E , 0X4152FDA9 ,
45- 0X5F15ADAC , 0X5BD4B01B , 0X569796C2 , 0X52568B75 ,
46- 0X6A1936C8 , 0X6ED82B7F , 0X639B0DA6 , 0X675A1011 ,
47- 0X791D4014 , 0X7DDC5DA3 , 0X709F7B7A , 0X745E66CD ,
48- 0X9823B6E0 , 0X9CE2AB57 , 0X91A18D8E , 0X95609039 ,
49- 0X8B27C03C , 0X8FE6DD8B , 0X82A5FB52 , 0X8664E6E5 ,
50- 0XBE2B5B58 , 0XBAEA46EF , 0XB7A96036 , 0XB3687D81 ,
51- 0XAD2F2D84 , 0XA9EE3033 , 0XA4AD16EA , 0XA06C0B5D ,
52- 0XD4326D90 , 0XD0F37027 , 0XDDB056FE , 0XD9714B49 ,
53- 0XC7361B4C , 0XC3F706FB , 0XCEB42022 , 0XCA753D95 ,
54- 0XF23A8028 , 0XF6FB9D9F , 0XFBB8BB46 , 0XFF79A6F1 ,
55- 0XE13EF6F4 , 0XE5FFEB43 , 0XE8BCCD9A , 0XEC7DD02D ,
56- 0X34867077 , 0X30476DC0 , 0X3D044B19 , 0X39C556AE ,
57- 0X278206AB , 0X23431B1C , 0X2E003DC5 , 0X2AC12072 ,
58- 0X128E9DCF , 0X164F8078 , 0X1B0CA6A1 , 0X1FCDBB16 ,
59- 0X018AEB13 , 0X054BF6A4 , 0X0808D07D , 0X0CC9CDCA ,
60- 0X7897AB07 , 0X7C56B6B0 , 0X71159069 , 0X75D48DDE ,
61- 0X6B93DDDB , 0X6F52C06C , 0X6211E6B5 , 0X66D0FB02 ,
62- 0X5E9F46BF , 0X5A5E5B08 , 0X571D7DD1 , 0X53DC6066 ,
63- 0X4D9B3063 , 0X495A2DD4 , 0X44190B0D , 0X40D816BA ,
64- 0XACA5C697 , 0XA864DB20 , 0XA527FDF9 , 0XA1E6E04E ,
65- 0XBFA1B04B , 0XBB60ADFC , 0XB6238B25 , 0XB2E29692 ,
66- 0X8AAD2B2F , 0X8E6C3698 , 0X832F1041 , 0X87EE0DF6 ,
67- 0X99A95DF3 , 0X9D684044 , 0X902B669D , 0X94EA7B2A ,
68- 0XE0B41DE7 , 0XE4750050 , 0XE9362689 , 0XEDF73B3E ,
69- 0XF3B06B3B , 0XF771768C , 0XFA325055 , 0XFEF34DE2 ,
70- 0XC6BCF05F , 0XC27DEDE8 , 0XCF3ECB31 , 0XCBFFD686 ,
71- 0XD5B88683 , 0XD1799B34 , 0XDC3ABDED , 0XD8FBA05A ,
72- 0X690CE0EE , 0X6DCDFD59 , 0X608EDB80 , 0X644FC637 ,
73- 0X7A089632 , 0X7EC98B85 , 0X738AAD5C , 0X774BB0EB ,
74- 0X4F040D56 , 0X4BC510E1 , 0X46863638 , 0X42472B8F ,
75- 0X5C007B8A , 0X58C1663D , 0X558240E4 , 0X51435D53 ,
76- 0X251D3B9E , 0X21DC2629 , 0X2C9F00F0 , 0X285E1D47 ,
77- 0X36194D42 , 0X32D850F5 , 0X3F9B762C , 0X3B5A6B9B ,
78- 0X0315D626 , 0X07D4CB91 , 0X0A97ED48 , 0X0E56F0FF ,
79- 0X1011A0FA , 0X14D0BD4D , 0X19939B94 , 0X1D528623 ,
80- 0XF12F560E , 0XF5EE4BB9 , 0XF8AD6D60 , 0XFC6C70D7 ,
81- 0XE22B20D2 , 0XE6EA3D65 , 0XEBA91BBC , 0XEF68060B ,
82- 0XD727BBB6 , 0XD3E6A601 , 0XDEA580D8 , 0XDA649D6F ,
83- 0XC423CD6A , 0XC0E2D0DD , 0XCDA1F604 , 0XC960EBB3 ,
84- 0XBD3E8D7E , 0XB9FF90C9 , 0XB4BCB610 , 0XB07DABA7 ,
85- 0XAE3AFBA2 , 0XAAFBE615 , 0XA7B8C0CC , 0XA379DD7B ,
86- 0X9B3660C6 , 0X9FF77D71 , 0X92B45BA8 , 0X9675461F ,
87- 0X8832161A , 0X8CF30BAD , 0X81B02D74 , 0X857130C3 ,
88- 0X5D8A9099 , 0X594B8D2E , 0X5408ABF7 , 0X50C9B640 ,
89- 0X4E8EE645 , 0X4A4FFBF2 , 0X470CDD2B , 0X43CDC09C ,
90- 0X7B827D21 , 0X7F436096 , 0X7200464F , 0X76C15BF8 ,
91- 0X68860BFD , 0X6C47164A , 0X61043093 , 0X65C52D24 ,
92- 0X119B4BE9 , 0X155A565E , 0X18197087 , 0X1CD86D30 ,
93- 0X029F3D35 , 0X065E2082 , 0X0B1D065B , 0X0FDC1BEC ,
94- 0X3793A651 , 0X3352BBE6 , 0X3E119D3F , 0X3AD08088 ,
95- 0X2497D08D , 0X2056CD3A , 0X2D15EBE3 , 0X29D4F654 ,
96- 0XC5A92679 , 0XC1683BCE , 0XCC2B1D17 , 0XC8EA00A0 ,
97- 0XD6AD50A5 , 0XD26C4D12 , 0XDF2F6BCB , 0XDBEE767C ,
98- 0XE3A1CBC1 , 0XE760D676 , 0XEA23F0AF , 0XEEE2ED18 ,
99- 0XF0A5BD1D , 0XF464A0AA , 0XF9278673 , 0XFDE69BC4 ,
100- 0X89B8FD09 , 0X8D79E0BE , 0X803AC667 , 0X84FBDBD0 ,
101- 0X9ABC8BD5 , 0X9E7D9662 , 0X933EB0BB , 0X97FFAD0C ,
102- 0XAFB010B1 , 0XAB710D06 , 0XA6322BDF , 0XA2F33668 ,
103- 0XBCB4666D , 0XB8757BDA , 0XB5365D03 , 0XB1F740B4
104- } ;
50+ private static readonly uint [ ] crcTable = CrcUtilities . GenerateSlicingLookupTable ( 0x04C11DB7 , isReversed : false ) ;
10551
10652 /// <summary>
10753 /// The CRC data checksum so far.
@@ -149,6 +95,7 @@ public long Value
14995 /// the byte is taken as the lower 8 bits of bval
15096 /// </param>
15197 /// <remarks>Reversed Data = false</remarks>
98+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
15299 public void Update ( int bval )
153100 {
154101 checkValue = unchecked ( crcTable [ ( byte ) ( ( ( checkValue >> 24 ) & 0xFF ) ^ bval ) ] ^ ( checkValue << 8 ) ) ;
@@ -166,7 +113,7 @@ public void Update(byte[] buffer)
166113 throw new ArgumentNullException ( nameof ( buffer ) ) ;
167114 }
168115
169- Update ( new ArraySegment < byte > ( buffer , 0 , buffer . Length ) ) ;
116+ Update ( buffer , 0 , buffer . Length ) ;
170117 }
171118
172119 /// <summary>
@@ -177,11 +124,48 @@ public void Update(byte[] buffer)
177124 /// </param>
178125 public void Update ( ArraySegment < byte > segment )
179126 {
180- var count = segment . Count ;
181- var offset = segment . Offset ;
127+ Update ( segment . Array , segment . Offset , segment . Count ) ;
128+ }
129+
130+ /// <summary>
131+ /// Internal helper function for updating a block of data using slicing.
132+ /// </summary>
133+ /// <param name="data">The array containing the data to add</param>
134+ /// <param name="offset">Range start for <paramref name="data"/> (inclusive)</param>
135+ /// <param name="count">The number of bytes to checksum starting from <paramref name="offset"/></param>
136+ private void Update ( byte [ ] data , int offset , int count )
137+ {
138+ int remainder = count % CrcUtilities . SlicingDegree ;
139+ int end = offset + count - remainder ;
140+
141+ while ( offset != end )
142+ {
143+ checkValue = CrcUtilities . UpdateDataForNormalPoly ( data , offset , crcTable , checkValue ) ;
144+ offset += CrcUtilities . SlicingDegree ;
145+ }
182146
183- while ( -- count >= 0 )
184- Update ( segment . Array [ offset ++ ] ) ;
147+ if ( remainder != 0 )
148+ {
149+ SlowUpdateLoop ( data , offset , end + remainder ) ;
150+ }
151+ }
152+
153+ /// <summary>
154+ /// A non-inlined function for updating data that doesn't fit in a 16-byte
155+ /// block. We don't expect to enter this function most of the time, and when
156+ /// we do we're not here for long, so disabling inlining here improves
157+ /// performance overall.
158+ /// </summary>
159+ /// <param name="data">The array containing the data to add</param>
160+ /// <param name="offset">Range start for <paramref name="data"/> (inclusive)</param>
161+ /// <param name="end">Range end for <paramref name="data"/> (exclusive)</param>
162+ [ MethodImpl ( MethodImplOptions . NoInlining ) ]
163+ private void SlowUpdateLoop ( byte [ ] data , int offset , int end )
164+ {
165+ while ( offset != end )
166+ {
167+ Update ( data [ offset ++ ] ) ;
168+ }
185169 }
186170 }
187171}
0 commit comments