Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Checksum Support for ReadOnlySpan<byte> #841

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 16 additions & 5 deletions src/ICSharpCode.SharpZipLib/Checksum/Adler32.cs
Expand Up @@ -122,7 +122,7 @@ public void Update(byte[] buffer)
throw new ArgumentNullException(nameof(buffer));
}

Update(new ArraySegment<byte>(buffer, 0, buffer.Length));
Update((ReadOnlySpan<byte>)buffer);
}

/// <summary>
Expand All @@ -132,12 +132,23 @@ public void Update(byte[] buffer)
/// The chunk of data to add
/// </param>
public void Update(ArraySegment<byte> segment)
{
Update((ReadOnlySpan<byte>)segment);
}

/// <summary>
/// Update Adler32 data checksum based on a portion of a block of data
/// </summary>
/// <param name = "data">
/// The chunk of data to add
/// </param>
public void Update(ReadOnlySpan<byte> 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:
Expand All @@ -151,8 +162,8 @@ public void Update(ArraySegment<byte> 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;
Expand Down
23 changes: 12 additions & 11 deletions src/ICSharpCode.SharpZipLib/Checksum/BZip2Crc.cs
Expand Up @@ -113,7 +113,7 @@ public void Update(byte[] buffer)
throw new ArgumentNullException(nameof(buffer));
}

Update(buffer, 0, buffer.Length);
Update((ReadOnlySpan<byte>)buffer);
}

/// <summary>
Expand All @@ -124,20 +124,21 @@ public void Update(byte[] buffer)
/// </param>
public void Update(ArraySegment<byte> segment)
{
Update(segment.Array, segment.Offset, segment.Count);
Update((ReadOnlySpan<byte>)segment);
}

/// <summary>
/// Internal helper function for updating a block of data using slicing.
/// Update CRC data checksum based on a portion of a block of data
/// </summary>
/// <param name="data">The array containing the data to add</param>
/// <param name="offset">Range start for <paramref name="data"/> (inclusive)</param>
/// <param name="count">The number of bytes to checksum starting from <paramref name="offset"/></param>
private void Update(byte[] data, int offset, int count)
/// <param name = "data">
/// The chunk of data to add
/// </param>
public void Update(ReadOnlySpan<byte> 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);
Expand All @@ -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.
/// </summary>
/// <param name="data">The array containing the data to add</param>
/// <param name="data">The span containing the data to add</param>
/// <param name="offset">Range start for <paramref name="data"/> (inclusive)</param>
/// <param name="end">Range end for <paramref name="data"/> (exclusive)</param>
[MethodImpl(MethodImplOptions.NoInlining)]
private void SlowUpdateLoop(byte[] data, int offset, int end)
private void SlowUpdateLoop(ReadOnlySpan<byte> data, int offset, int end)
{
while (offset != end)
{
Expand Down
23 changes: 12 additions & 11 deletions src/ICSharpCode.SharpZipLib/Checksum/Crc32.cs
Expand Up @@ -115,7 +115,7 @@ public void Update(byte[] buffer)
throw new ArgumentNullException(nameof(buffer));
}

Update(buffer, 0, buffer.Length);
Update((ReadOnlySpan<byte>)buffer);
}

/// <summary>
Expand All @@ -126,20 +126,21 @@ public void Update(byte[] buffer)
/// </param>
public void Update(ArraySegment<byte> segment)
{
Update(segment.Array, segment.Offset, segment.Count);
Update((ReadOnlySpan<byte>)segment);
}

/// <summary>
/// Internal helper function for updating a block of data using slicing.
/// Update CRC data checksum based on a portion of a block of data
/// </summary>
/// <param name="data">The array containing the data to add</param>
/// <param name="offset">Range start for <paramref name="data"/> (inclusive)</param>
/// <param name="count">The number of bytes to checksum starting from <paramref name="offset"/></param>
private void Update(byte[] data, int offset, int count)
/// <param name = "data">
/// The chunk of data to add
/// </param>
public void Update(ReadOnlySpan<byte> 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);
Expand All @@ -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.
/// </summary>
/// <param name="data">The array containing the data to add</param>
/// <param name="data">The span containing the data to add</param>
/// <param name="offset">Range start for <paramref name="data"/> (inclusive)</param>
/// <param name="end">Range end for <paramref name="data"/> (exclusive)</param>
[MethodImpl(MethodImplOptions.NoInlining)]
private void SlowUpdateLoop(byte[] data, int offset, int end)
private void SlowUpdateLoop(ReadOnlySpan<byte> data, int offset, int end)
{
while (offset != end)
{
Expand Down
17 changes: 9 additions & 8 deletions src/ICSharpCode.SharpZipLib/Checksum/CrcUtilities.cs
@@ -1,4 +1,5 @@
using System.Runtime.CompilerServices;
using System;
using System.Runtime.CompilerServices;

namespace ICSharpCode.SharpZipLib.Checksum
{
Expand Down Expand Up @@ -55,7 +56,7 @@ internal static uint[] GenerateSlicingLookupTable(uint polynomial, bool isRevers
/// Mixes the first four bytes of input with <paramref name="checkValue"/>
/// using normal ordering before calling <see cref="UpdateDataCommon"/>.
/// </summary>
/// <param name="input">Array of data to checksum</param>
/// <param name="input">Span of data to checksum</param>
/// <param name="offset">Offset to start reading <paramref name="input"/> from</param>
/// <param name="crcTable">The table to use for slicing-by-16 lookup</param>
/// <param name="checkValue">Checksum state before this update call</param>
Expand All @@ -66,7 +67,7 @@ internal static uint[] GenerateSlicingLookupTable(uint polynomial, bool isRevers
/// For performance reasons, this must be checked by the caller.
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static uint UpdateDataForNormalPoly(byte[] input, int offset, uint[] crcTable, uint checkValue)
internal static uint UpdateDataForNormalPoly(ReadOnlySpan<byte> input, int offset, uint[] crcTable, uint checkValue)
{
byte x1 = (byte)((byte)(checkValue >> 24) ^ input[offset]);
byte x2 = (byte)((byte)(checkValue >> 16) ^ input[offset + 1]);
Expand All @@ -80,7 +81,7 @@ internal static uint UpdateDataForNormalPoly(byte[] input, int offset, uint[] cr
/// Mixes the first four bytes of input with <paramref name="checkValue"/>
/// using reflected ordering before calling <see cref="UpdateDataCommon"/>.
/// </summary>
/// <param name="input">Array of data to checksum</param>
/// <param name="input">Span of data to checksum</param>
/// <param name="offset">Offset to start reading <paramref name="input"/> from</param>
/// <param name="crcTable">The table to use for slicing-by-16 lookup</param>
/// <param name="checkValue">Checksum state before this update call</param>
Expand All @@ -91,7 +92,7 @@ internal static uint UpdateDataForNormalPoly(byte[] input, int offset, uint[] cr
/// For performance reasons, this must be checked by the caller.
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static uint UpdateDataForReversedPoly(byte[] input, int offset, uint[] crcTable, uint checkValue)
internal static uint UpdateDataForReversedPoly(ReadOnlySpan<byte> input, int offset, uint[] crcTable, uint checkValue)
{
byte x1 = (byte)((byte)checkValue ^ input[offset]);
byte x2 = (byte)((byte)(checkValue >>= 8) ^ input[offset + 1]);
Expand All @@ -104,7 +105,7 @@ internal static uint UpdateDataForReversedPoly(byte[] input, int offset, uint[]
/// <summary>
/// A shared method for updating an unfinalized CRC checksum using slicing-by-16.
/// </summary>
/// <param name="input">Array of data to checksum</param>
/// <param name="input">Span of data to checksum</param>
/// <param name="offset">Offset to start reading <paramref name="input"/> from</param>
/// <param name="crcTable">The table to use for slicing-by-16 lookup</param>
/// <param name="x1">First byte of input after mixing with the old CRC</param>
Expand All @@ -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.
/// </para>
/// </remarks>
[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<byte> input, int offset, uint[] crcTable, byte x1, byte x2, byte x3, byte x4)
{
uint result;
uint a1 = crcTable[x1 + 3840] ^ crcTable[x2 + 3584];
Expand Down
8 changes: 8 additions & 0 deletions src/ICSharpCode.SharpZipLib/Checksum/IChecksum.cs
Expand Up @@ -47,5 +47,13 @@ long Value
/// The chunk of data to add
/// </param>
void Update(ArraySegment<byte> segment);

/// <summary>
/// Adds the byte array to the data checksum.
/// </summary>
/// <param name = "data">
/// The chunk of data to add
/// </param>
void Update(ReadOnlySpan<byte> data);
}
}