Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ obj
packages
.tools
private.snk
.idea
.idea
BenchmarkDotNet.Artifacts/
18 changes: 18 additions & 0 deletions Crc32.NET.Benchmarks/Crc32.NET.Benchmarks.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net461;netcoreapp2.1;netcoreapp3.1</TargetFrameworks>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.12.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Crc32.NET\Crc32.NET.Core.csproj" />
</ItemGroup>

</Project>
43 changes: 43 additions & 0 deletions Crc32.NET.Benchmarks/Crc32.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Jobs;
using Force.Crc32;

namespace Crc32.NET.Benchmarks
{
[SimpleJob(RuntimeMoniker.NetCoreApp31)]
public class Crc32
{
private byte[] _input;
private byte[] _destination;

[Params(65536)]
public int Size { get; set; }

[GlobalSetup]
public void Setup()
{
_input = new byte[Size];
var random = new Random();
random.NextBytes(_input);

_destination = new byte[4];
}

[Benchmark(Baseline = true)]
public byte[] Array()
{
var crc = new Crc32Algorithm();
return crc.ComputeHash(_input);
}

#if NETCOREAPP3_1
[Benchmark]
public void Span()
{
var crc = new Crc32Algorithm();
crc.TryComputeHash(_input.AsSpan(), _destination.AsSpan(), out _);
}
#endif
}
}
10 changes: 10 additions & 0 deletions Crc32.NET.Benchmarks/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System;
using BenchmarkDotNet.Running;

namespace Crc32.NET.Benchmarks
{
class Program
{
static void Main(string[] args) => BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args, new StandardConfig());
}
}
23 changes: 23 additions & 0 deletions Crc32.NET.Benchmarks/StandardConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using BenchmarkDotNet.Columns;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Exporters;
using BenchmarkDotNet.Loggers;

namespace Crc32.NET.Benchmarks
{
public class StandardConfig : ManualConfig
{
public StandardConfig()
{
AddColumnProvider(DefaultColumnProviders.Instance);
AddColumn(RankColumn.Arabic);

AddExporter(DefaultExporters.CsvMeasurements);
AddExporter(DefaultExporters.Csv);
AddExporter(DefaultExporters.Markdown);
AddExporter(DefaultExporters.Html);

AddLogger(ConsoleLogger.Default);
}
}
}
17 changes: 13 additions & 4 deletions Crc32.NET.Core.sln
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26114.2
# Visual Studio Version 16
VisualStudioVersion = 16.0.30611.23
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Crc32.NET", "Crc32.NET\Crc32.NET.Core.csproj", "{E95FA3F3-4ED0-41FF-9A1F-DE80CE14A976}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Crc32.NET.Core", "Crc32.NET\Crc32.NET.Core.csproj", "{E95FA3F3-4ED0-41FF-9A1F-DE80CE14A976}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Crc32.NET.Tests", "Crc32.NET.Tests\Crc32.NET.Tests.Core.csproj", "{A602A9CA-793A-4096-A93C-799CA74519BF}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Crc32.NET.Tests.Core", "Crc32.NET.Tests\Crc32.NET.Tests.Core.csproj", "{A602A9CA-793A-4096-A93C-799CA74519BF}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{56B92A80-3AE8-4FD0-B1F6-3847919216DA}"
ProjectSection(SolutionItems) = preProject
README.md = README.md
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Crc32.NET.Benchmarks", "Crc32.NET.Benchmarks\Crc32.NET.Benchmarks.csproj", "{13C3DDAD-50F1-4804-95A1-D54766EA1247}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -26,8 +28,15 @@ Global
{A602A9CA-793A-4096-A93C-799CA74519BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A602A9CA-793A-4096-A93C-799CA74519BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A602A9CA-793A-4096-A93C-799CA74519BF}.Release|Any CPU.Build.0 = Release|Any CPU
{13C3DDAD-50F1-4804-95A1-D54766EA1247}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{13C3DDAD-50F1-4804-95A1-D54766EA1247}.Debug|Any CPU.Build.0 = Debug|Any CPU
{13C3DDAD-50F1-4804-95A1-D54766EA1247}.Release|Any CPU.ActiveCfg = Release|Any CPU
{13C3DDAD-50F1-4804-95A1-D54766EA1247}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A1461F74-929C-4C81-8E25-B44498AEEF6D}
EndGlobalSection
EndGlobal
5 changes: 4 additions & 1 deletion Crc32.NET.Tests/Crc32.NET.Tests.Core.csproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp1.0;netcoreapp2.0;net461</TargetFrameworks>
<TargetFrameworks>netcoreapp1.0;netcoreapp2.0;netcoreapp3.1;net461</TargetFrameworks>
<DebugType>portable</DebugType>
<AssemblyName>Crc32.NET.Tests</AssemblyName>
<OutputType>Exe</OutputType>
Expand Down Expand Up @@ -40,6 +40,9 @@
<PropertyGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.0' ">
<DefineConstants>$(DefineConstants);NETCORE;NETCORE20</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netcoreapp3.1' ">
<DefineConstants>$(DefineConstants);NETCORE;NETCORE30</DefineConstants>
</PropertyGroup>
<PropertyGroup>
<DefineConstants>$(DefineConstants);COREVERSION</DefineConstants>
</PropertyGroup>
Expand Down
28 changes: 26 additions & 2 deletions Crc32.NET.Tests/ImplementationTest.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using System;
#if NETCORE30
using System.Buffers.Binary;
#endif
using System.Linq;
using System.Text;

Expand Down Expand Up @@ -30,7 +33,7 @@ public void ResultConsistency(string text, int offset)
Assert.That(crc2, Is.EqualTo(crc1));
}
#endif

[Test]
public void ResultConsistency2()
{
Expand All @@ -52,7 +55,28 @@ public void ResultConsistencyAsHashAlgorithm()
Console.WriteLine(crc2.ToString("X8"));
Assert.That(crc1, Is.EqualTo(crc2));
}
#endif
#endif

#if NETCORE30
[Test]
public void ResultConsistencyAsHashAlgorithm_SpanVsArray()
{
var bytes = new byte[30000];
new Random().NextBytes(bytes);
var e = new Crc32Algorithm();
var c = new Crc32Algorithm();
var crc1 = BitConverter.ToInt32(e.ComputeHash(bytes), 0);

var dest = new byte[4];
Assert.That(c.TryComputeHash(bytes, dest, out var bytesWritten), Is.True);
Assert.That(bytesWritten, Is.EqualTo(4));
var crc2 = BinaryPrimitives.ReadInt32LittleEndian(dest);

Console.WriteLine(crc1.ToString("X8"));
Console.WriteLine(crc2.ToString("X8"));
Assert.That(crc1, Is.EqualTo(crc2));
}
#endif

[Test]
public void PartIsWhole()
Expand Down
8 changes: 7 additions & 1 deletion Crc32.NET/Crc32.NET.Core.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<VersionPrefix>1.2.1</VersionPrefix>
<TargetFrameworks>netstandard1.3;netstandard2.0;net20</TargetFrameworks>
<TargetFrameworks>netstandard1.3;netstandard2.0;netstandard2.1;net20</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>Crc32.NET</AssemblyName>
<!--DelaySign>true</DelaySign>
Expand Down Expand Up @@ -29,7 +29,13 @@
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
<DefineConstants>$(DefineConstants);NETCORE;NETCORE20</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard2.1' ">
<DefineConstants>$(DefineConstants);NETCORE;NETCORE30</DefineConstants>
</PropertyGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net20' ">
<Reference Include="System" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
<PackageReference Include="System.Memory" Version="4.5.4" />
</ItemGroup>
</Project>
90 changes: 85 additions & 5 deletions Crc32.NET/Crc32Algorithm.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using System;
#if NETCORE30
using System.Buffers.Binary;
#endif
using System.Security.Cryptography;

namespace Force.Crc32
Expand All @@ -14,7 +17,7 @@ public class Crc32Algorithm : HashAlgorithm
private readonly bool _isBigEndian = true;

/// <summary>
/// Initializes a new instance of the <see cref="Crc32Algorithm"/> class.
/// Initializes a new instance of the <see cref="Crc32Algorithm"/> class.
/// </summary>
public Crc32Algorithm()
{
Expand All @@ -24,7 +27,7 @@ public Crc32Algorithm()
}

/// <summary>
/// Initializes a new instance of the <see cref="Crc32Algorithm"/> class.
/// Initializes a new instance of the <see cref="Crc32Algorithm"/> class.
/// </summary>
/// <param name="isBigEndian">Should return bytes result as big endian or little endian</param>
// Crc32 by dariogriffo uses big endian, so, we need to be compatible and return big endian as default
Expand Down Expand Up @@ -72,6 +75,23 @@ public static uint Append(uint initial, byte[] input)
return AppendInternal(initial, input, 0, input.Length);
}

#if NETCORE20 || NETCORE30
/// <summary>
/// Computes CRC-32 from multiple buffers.
/// Call this method multiple times to chain multiple buffers.
/// </summary>
/// <param name="initial">
/// Initial CRC value for the algorithm. It is zero for the first buffer.
/// Subsequent buffers should have their initial value set to CRC value returned by previous call to this method.
/// </param>
/// <param name="input">Input buffer containing data to be checksummed.</param>
/// <returns>Accumulated CRC-32 of all buffers processed so far.</returns>
public static uint Append(uint initial, ReadOnlySpan<byte> input)
{
return AppendInternal(initial, input);
}
#endif

/// <summary>
/// Computes CRC-32 from input buffer.
/// </summary>
Expand All @@ -94,6 +114,18 @@ public static uint Compute(byte[] input)
return Append(0, input);
}

#if NETCORE20 || NETCORE30
/// <summary>
/// Computes CRC-32 from input buffer.
/// </summary>
/// <param name="input">Input buffer with data to be checksummed.</param>
/// <returns>CRC-32 of the data in the buffer.</returns>
public static uint Compute(ReadOnlySpan<byte> input)
{
return Append(0, input);
}
#endif

/// <summary>
/// Computes CRC-32 from input buffer and writes it after end of data (buffer should have 4 bytes reserved space for it). Can be used in conjunction with <see cref="IsValidWithCrcAtEnd(byte[],int,int)"/>
/// </summary>
Expand Down Expand Up @@ -162,12 +194,22 @@ public override void Initialize()
/// Appends CRC-32 from given buffer
/// </summary>
protected override void HashCore(byte[] input, int offset, int length)
{
{
_currentCrc = AppendInternal(_currentCrc, input, offset, length);
}

/// <summary>
/// Computes CRC-32 from <see cref="HashCore"/>
#if NETCORE30
/// <summary>
/// Appends CRC-32 from given buffer
/// </summary>
protected override void HashCore(ReadOnlySpan<byte> source)
{
_currentCrc = AppendInternal(_currentCrc, source);
}
#endif

/// <summary>
/// Computes CRC-32 from <see cref="HashCore(byte[], int, int)"/>
/// </summary>
protected override byte[] HashFinal()
{
Expand All @@ -177,6 +219,32 @@ protected override byte[] HashFinal()
return new[] { (byte)_currentCrc, (byte)(_currentCrc >> 8), (byte)(_currentCrc >> 16), (byte)(_currentCrc >> 24) };
}

#if NETCORE30
/// <summary>
/// Computes CRC-32 from <see cref="HashCore(ReadOnlySpan{byte})"/>
/// </summary>
protected override bool TryHashFinal(Span<byte> destination, out int bytesWritten)
{
if (destination.Length < 4)
{
bytesWritten = 0;
return false;
}

if (_isBigEndian)
{
BinaryPrimitives.WriteUInt32BigEndian(destination, _currentCrc);
}
else
{
BinaryPrimitives.WriteUInt32LittleEndian(destination, _currentCrc);
}

bytesWritten = 4;
return true;
}
#endif

private static readonly SafeProxy _proxy = new SafeProxy();

private static uint AppendInternal(uint initial, byte[] input, int offset, int length)
Expand All @@ -188,5 +256,17 @@ private static uint AppendInternal(uint initial, byte[] input, int offset, int l
else
return initial;
}

#if NETCORE20 || NETCORE30
private static uint AppendInternal(uint initial, ReadOnlySpan<byte> input)
{
if (input.Length > 0)
{
return _proxy.Append(initial, input);
}
else
return initial;
}
#endif
}
}
Loading