diff --git a/src/ICSharpCode.SharpZipLib/Checksum/Adler32.cs b/src/ICSharpCode.SharpZipLib/Checksum/Adler32.cs index b2a0f151a..71510d718 100644 --- a/src/ICSharpCode.SharpZipLib/Checksum/Adler32.cs +++ b/src/ICSharpCode.SharpZipLib/Checksum/Adler32.cs @@ -122,7 +122,7 @@ public void Update(byte[] buffer) throw new ArgumentNullException(nameof(buffer)); } - Update(new ArraySegment(buffer, 0, buffer.Length)); + Update((ReadOnlySpan)buffer); } /// @@ -132,12 +132,23 @@ public void Update(byte[] buffer) /// The chunk of data to add /// public void Update(ArraySegment segment) + { + Update((ReadOnlySpan)segment); + } + + /// + /// Update Adler32 data checksum based on a portion of a block of data + /// + /// + /// The chunk of data to add + /// + public void Update(ReadOnlySpan data) { //(By Per Bothner) uint s1 = checkValue & 0xFFFF; uint s2 = checkValue >> 16; - var count = segment.Count; - var offset = segment.Offset; + var count = data.Length; + var offset = 0; while (count > 0) { // We can defer the modulo operation: @@ -151,8 +162,8 @@ public void Update(ArraySegment segment) count -= n; while (--n >= 0) { - s1 = s1 + (uint)(segment.Array[offset++] & 0xff); - s2 = s2 + s1; + s1 += (uint)(data[offset++] & 0xff); + s2 += s1; } s1 %= BASE; s2 %= BASE; diff --git a/src/ICSharpCode.SharpZipLib/Checksum/BZip2Crc.cs b/src/ICSharpCode.SharpZipLib/Checksum/BZip2Crc.cs index be76da11e..2f751d60c 100644 --- a/src/ICSharpCode.SharpZipLib/Checksum/BZip2Crc.cs +++ b/src/ICSharpCode.SharpZipLib/Checksum/BZip2Crc.cs @@ -113,7 +113,7 @@ public void Update(byte[] buffer) throw new ArgumentNullException(nameof(buffer)); } - Update(buffer, 0, buffer.Length); + Update((ReadOnlySpan)buffer); } /// @@ -124,20 +124,21 @@ public void Update(byte[] buffer) /// public void Update(ArraySegment segment) { - Update(segment.Array, segment.Offset, segment.Count); + Update((ReadOnlySpan)segment); } /// - /// Internal helper function for updating a block of data using slicing. + /// Update CRC data checksum based on a portion of a block of data /// - /// The array containing the data to add - /// Range start for (inclusive) - /// The number of bytes to checksum starting from - private void Update(byte[] data, int offset, int count) + /// + /// The chunk of data to add + /// + public void Update(ReadOnlySpan data) { - int remainder = count % CrcUtilities.SlicingDegree; - int end = offset + count - remainder; + int remainder = data.Length % CrcUtilities.SlicingDegree; + int end = data.Length - remainder; + int offset = 0; while (offset != end) { checkValue = CrcUtilities.UpdateDataForNormalPoly(data, offset, crcTable, checkValue); @@ -156,11 +157,11 @@ private void Update(byte[] data, int offset, int count) /// we do we're not here for long, so disabling inlining here improves /// performance overall. /// - /// The array containing the data to add + /// The span containing the data to add /// Range start for (inclusive) /// Range end for (exclusive) [MethodImpl(MethodImplOptions.NoInlining)] - private void SlowUpdateLoop(byte[] data, int offset, int end) + private void SlowUpdateLoop(ReadOnlySpan data, int offset, int end) { while (offset != end) { diff --git a/src/ICSharpCode.SharpZipLib/Checksum/Crc32.cs b/src/ICSharpCode.SharpZipLib/Checksum/Crc32.cs index 740aff566..9a9cf6f68 100644 --- a/src/ICSharpCode.SharpZipLib/Checksum/Crc32.cs +++ b/src/ICSharpCode.SharpZipLib/Checksum/Crc32.cs @@ -115,7 +115,7 @@ public void Update(byte[] buffer) throw new ArgumentNullException(nameof(buffer)); } - Update(buffer, 0, buffer.Length); + Update((ReadOnlySpan)buffer); } /// @@ -126,20 +126,21 @@ public void Update(byte[] buffer) /// public void Update(ArraySegment segment) { - Update(segment.Array, segment.Offset, segment.Count); + Update((ReadOnlySpan)segment); } /// - /// Internal helper function for updating a block of data using slicing. + /// Update CRC data checksum based on a portion of a block of data /// - /// The array containing the data to add - /// Range start for (inclusive) - /// The number of bytes to checksum starting from - private void Update(byte[] data, int offset, int count) + /// + /// The chunk of data to add + /// + public void Update(ReadOnlySpan data) { - int remainder = count % CrcUtilities.SlicingDegree; - int end = offset + count - remainder; + int remainder = data.Length % CrcUtilities.SlicingDegree; + int end = data.Length - remainder; + int offset = 0; while (offset != end) { checkValue = CrcUtilities.UpdateDataForReversedPoly(data, offset, crcTable, checkValue); @@ -158,11 +159,11 @@ private void Update(byte[] data, int offset, int count) /// we do we're not here for long, so disabling inlining here improves /// performance overall. /// - /// The array containing the data to add + /// The span containing the data to add /// Range start for (inclusive) /// Range end for (exclusive) [MethodImpl(MethodImplOptions.NoInlining)] - private void SlowUpdateLoop(byte[] data, int offset, int end) + private void SlowUpdateLoop(ReadOnlySpan data, int offset, int end) { while (offset != end) { diff --git a/src/ICSharpCode.SharpZipLib/Checksum/CrcUtilities.cs b/src/ICSharpCode.SharpZipLib/Checksum/CrcUtilities.cs index 575abe08b..fcb840709 100644 --- a/src/ICSharpCode.SharpZipLib/Checksum/CrcUtilities.cs +++ b/src/ICSharpCode.SharpZipLib/Checksum/CrcUtilities.cs @@ -1,4 +1,5 @@ -using System.Runtime.CompilerServices; +using System; +using System.Runtime.CompilerServices; namespace ICSharpCode.SharpZipLib.Checksum { @@ -55,7 +56,7 @@ internal static uint[] GenerateSlicingLookupTable(uint polynomial, bool isRevers /// Mixes the first four bytes of input with /// using normal ordering before calling . /// - /// Array of data to checksum + /// Span of data to checksum /// Offset to start reading from /// The table to use for slicing-by-16 lookup /// Checksum state before this update call @@ -66,7 +67,7 @@ internal static uint[] GenerateSlicingLookupTable(uint polynomial, bool isRevers /// For performance reasons, this must be checked by the caller. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static uint UpdateDataForNormalPoly(byte[] input, int offset, uint[] crcTable, uint checkValue) + internal static uint UpdateDataForNormalPoly(ReadOnlySpan input, int offset, uint[] crcTable, uint checkValue) { byte x1 = (byte)((byte)(checkValue >> 24) ^ input[offset]); byte x2 = (byte)((byte)(checkValue >> 16) ^ input[offset + 1]); @@ -80,7 +81,7 @@ internal static uint UpdateDataForNormalPoly(byte[] input, int offset, uint[] cr /// Mixes the first four bytes of input with /// using reflected ordering before calling . /// - /// Array of data to checksum + /// Span of data to checksum /// Offset to start reading from /// The table to use for slicing-by-16 lookup /// Checksum state before this update call @@ -91,7 +92,7 @@ internal static uint UpdateDataForNormalPoly(byte[] input, int offset, uint[] cr /// For performance reasons, this must be checked by the caller. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static uint UpdateDataForReversedPoly(byte[] input, int offset, uint[] crcTable, uint checkValue) + internal static uint UpdateDataForReversedPoly(ReadOnlySpan input, int offset, uint[] crcTable, uint checkValue) { byte x1 = (byte)((byte)checkValue ^ input[offset]); byte x2 = (byte)((byte)(checkValue >>= 8) ^ input[offset + 1]); @@ -104,7 +105,7 @@ internal static uint UpdateDataForReversedPoly(byte[] input, int offset, uint[] /// /// A shared method for updating an unfinalized CRC checksum using slicing-by-16. /// - /// Array of data to checksum + /// Span of data to checksum /// Offset to start reading from /// The table to use for slicing-by-16 lookup /// First byte of input after mixing with the old CRC @@ -124,14 +125,14 @@ internal static uint UpdateDataForReversedPoly(byte[] input, int offset, uint[] /// Because most processors running C# have some kind of instruction-level /// parallelism, the order of XOR operations can affect performance. This /// ordering assumes that the assembly code generated by the just-in-time - /// compiler will emit a bunch of arithmetic operations for checking array + /// compiler will emit a bunch of arithmetic operations for checking span /// bounds. Then it opportunistically XORs a1 and a2 to keep the processor /// busy while those other parts of the pipeline handle the range check /// calculations. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint UpdateDataCommon(byte[] input, int offset, uint[] crcTable, byte x1, byte x2, byte x3, byte x4) + private static uint UpdateDataCommon(ReadOnlySpan input, int offset, uint[] crcTable, byte x1, byte x2, byte x3, byte x4) { uint result; uint a1 = crcTable[x1 + 3840] ^ crcTable[x2 + 3584]; diff --git a/src/ICSharpCode.SharpZipLib/Checksum/IChecksum.cs b/src/ICSharpCode.SharpZipLib/Checksum/IChecksum.cs index db74a5a5d..93d7df103 100644 --- a/src/ICSharpCode.SharpZipLib/Checksum/IChecksum.cs +++ b/src/ICSharpCode.SharpZipLib/Checksum/IChecksum.cs @@ -47,5 +47,13 @@ long Value /// The chunk of data to add /// void Update(ArraySegment segment); + + /// + /// Adds the byte array to the data checksum. + /// + /// + /// The chunk of data to add + /// + void Update(ReadOnlySpan data); } }