Skip to content

Commit

Permalink
Breaking change: Change extension method from Hash.AsSpanUnsafe to Ha…
Browse files Browse the repository at this point in the history
…sh.AsSpan() and use UnscopeRef to protect usage
  • Loading branch information
xoofx committed Oct 8, 2023
1 parent 0bb6593 commit 9a23e52
Show file tree
Hide file tree
Showing 9 changed files with 64 additions and 130 deletions.
4 changes: 2 additions & 2 deletions src/Blake3.Benchmarks/Blake3.Benchmarks.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
Expand All @@ -8,7 +8,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.6" />
<PackageReference Include="BenchmarkDotNet" Version="0.13.9" />
<PackageReference Include="SauceControl.Blake2Fast" Version="2.0.0" />
</ItemGroup>

Expand Down
5 changes: 2 additions & 3 deletions src/Blake3.Tests/Blake3.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net7.0;net48</TargetFrameworks>
<TargetFramework>net7.0</TargetFramework>
<IsPackable>false</IsPackable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>9.0</LangVersion>
<RuntimeIdentifier Condition="'$(RuntimeIdentifier)' == '' AND '$(PackAsTool)' != 'true'">$(NETCoreSdkRuntimeIdentifier)</RuntimeIdentifier>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.2" />
<Content Include="..\Blake3\runtimes\$(RuntimeIdentifier)\native\*.*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
Expand Down
10 changes: 1 addition & 9 deletions src/Blake3.Tests/Blake3StreamTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,7 @@ public void TestHashRead()
{
var stream = new MemoryStream(HasherTests.BigData);
using var blake3Stream = new Blake3Stream(stream);
#if NET5_0
blake3Stream.Read(new byte[HasherTests.BigData.Length]);
#else
blake3Stream.Read(new byte[HasherTests.BigData.Length], 0, HasherTests.BigData.Length);
#endif
_ = blake3Stream.Read(new byte[HasherTests.BigData.Length]);
AssertTextAreEqual(HasherTests.BigExpected, blake3Stream.ComputeHash().ToString());
}

Expand Down Expand Up @@ -57,11 +53,7 @@ public void TestHashWrite()
{
var stream = new MemoryStream();
using var blake3Stream = new Blake3Stream(stream);
#if NET5_0
blake3Stream.Write(HasherTests.BigData);
#else
blake3Stream.Write(HasherTests.BigData, 0, HasherTests.BigData.Length);
#endif
AssertTextAreEqual(HasherTests.BigExpected, blake3Stream.ComputeHash().ToString());
}
}
Expand Down
2 changes: 0 additions & 2 deletions src/Blake3.Tests/HashTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System;
using System.Linq;
using System.Text;
using NUnit.Framework;

namespace Blake3.Tests
Expand Down
22 changes: 20 additions & 2 deletions src/Blake3/Blake3.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@
<Import Project="Blake3.props" />

<PropertyGroup>
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<TargetFrameworks>net7.0</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<!--Add support for sourcelink-->
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<LangVersion>9.0</LangVersion>
</PropertyGroup>

<ItemGroup>
Expand All @@ -33,4 +32,23 @@
<!--Add support for sourcelink-->
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.*" PrivateAssets="All" />
</ItemGroup>

<ItemGroup>
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
</ItemGroup>

<ItemGroup>
<Compile Update="Blake3Core.generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Blake3Core.generated.tt</DependentUpon>
</Compile>
</ItemGroup>

<ItemGroup>
<None Update="Blake3Core.generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Blake3Core.generated.cs</LastGenOutput>
</None>
</ItemGroup>
</Project>
37 changes: 0 additions & 37 deletions src/Blake3/Blake3Extensions.cs

This file was deleted.

8 changes: 1 addition & 7 deletions src/Blake3/Blake3Stream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ protected override void Dispose(bool disposing)
}
}

#if NET5_0
public override async ValueTask DisposeAsync()
{
_hasher.Dispose();
Expand All @@ -51,7 +50,6 @@ public override async ValueTask DisposeAsync()
await _stream.DisposeAsync();
}
}
#endif

public override void Flush()
{
Expand Down Expand Up @@ -99,8 +97,6 @@ public override async Task<int> ReadAsync(byte[] buffer, int offset, int count,
return length;
}

#if NET5_0

public override async ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = new CancellationToken())
{
var length = await _stream.ReadAsync(buffer, cancellationToken);
Expand All @@ -120,7 +116,6 @@ public override int Read(Span<byte> buffer)
}
return length;
}
#endif

public override unsafe int ReadByte()
{
Expand Down Expand Up @@ -151,13 +146,12 @@ public override async Task WriteAsync(byte[] buffer, int offset, int count, Canc
}
}

#if NET5_0
public override void Write(ReadOnlySpan<byte> buffer)
{
_stream.Write(buffer);
_hasher.Update(buffer);
}
#endif

public override unsafe void WriteByte(byte value)
{
_stream.WriteByte(value);
Expand Down
26 changes: 0 additions & 26 deletions src/Blake3/FrameworkCompatibility.cs

This file was deleted.

80 changes: 38 additions & 42 deletions src/Blake3/Hash.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;

namespace Blake3
{
Expand Down Expand Up @@ -67,7 +66,7 @@ public struct Hash : IEquatable<Hash>
public void CopyFromBytes(ReadOnlySpan<byte> data)
{
if (data.Length != 32) ThrowArgumentOutOfRange(data.Length);
data.CopyTo(this.AsSpanUnsafe());
data.CopyTo(this.AsSpan());
}

/// <summary>
Expand All @@ -86,7 +85,7 @@ public static Hash FromBytes(ReadOnlySpan<byte> data)

public bool Equals(Hash other)
{
return this.AsSpanUnsafe().SequenceCompareTo(other.AsSpanUnsafe()) == 0;
return this.AsSpan().SequenceCompareTo(other.AsSpan()) == 0;
}

public override bool Equals(object obj)
Expand All @@ -96,7 +95,7 @@ public override bool Equals(object obj)

public override int GetHashCode()
{
var values = MemoryMarshal.Cast<byte, int>(this.AsSpanUnsafe());
var values = MemoryMarshal.Cast<byte, int>(this.AsSpan());
int hashcode = 0;
for (int i = 0; i < values.Length; i++)
{
Expand All @@ -107,33 +106,30 @@ public override int GetHashCode()

public override string ToString()
{
#if NET5_0
return string.Create(Size * 2, this, (span, hash) =>
{
var data = MemoryMarshal.AsBytes(MemoryMarshal.CreateSpan(ref hash, 1));
for (int i = 0; i < Size; i++)
var data = hash.AsSpan();
for (int i = 0; i < data.Length; i++)
{
var b = data[i];
span[i * 2] = Hex[(b >> 4) & 0xF];
span[i * 2 + 1] = Hex[b & 0xF];
span[i * 2] = (char)Hex[(b >> 4) & 0xF];
span[i * 2 + 1] = (char)Hex[b & 0xF];
}
});
#else
unsafe
{
var builder = new StringBuilder(Size * 2);
fixed (byte* pBytes = &_byte1)
{
for (int i = 0; i < Size; i++)
{
var b = pBytes[i];
builder.Append(Hex[(b >> 4) & 0xF]);
builder.Append(Hex[b & 0xF]);
}
}
return builder.ToString();
}
#endif
}

/// <summary>
/// Creates a span from a hash. The span returned has to follow the same lifetime than the hash referenced.
/// </summary>
/// <returns>The hash of the span</returns>
/// <remarks>This method is unsafe because you could return a Span from a local variable Hash that could be no longer valid on the stack.
/// Use this Span with the same variable scope of the original Hash.
/// It is safe to use this method if the referenced Hash is a field of a managed type.
/// </remarks>
[UnscopedRef]
public Span<byte> AsSpan()
{
return MemoryMarshal.AsBytes(MemoryMarshal.CreateSpan(ref this, 1));
}

public static bool operator ==(Hash left, Hash right)
Expand All @@ -153,24 +149,24 @@ private static void ThrowArgumentOutOfRange(int size)
throw new ArgumentOutOfRangeException("data", $"Invalid size {size} of the data. Expecting 32");
}

private static ReadOnlySpan<char> Hex => new ReadOnlySpan<char>(new char[]
private static ReadOnlySpan<byte> Hex => new ReadOnlySpan<byte>(new byte[]
{
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'a',
'b',
'c',
'd',
'e',
'f',
(byte)'0',
(byte)'1',
(byte)'2',
(byte)'3',
(byte)'4',
(byte)'5',
(byte)'6',
(byte)'7',
(byte)'8',
(byte)'9',
(byte)'a',
(byte)'b',
(byte)'c',
(byte)'d',
(byte)'e',
(byte)'f',
});
}
}

0 comments on commit 9a23e52

Please sign in to comment.