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

Add uint256.ToSpanString() #1198

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
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
19 changes: 19 additions & 0 deletions NBitcoin.Bench/UInt256Bench.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,25 @@ public void WriteToString()
{
Value.ToString();
}

#if HAS_SPAN
[Benchmark]
[Arguments(new char[] {
'0','0','0','0','0','0','0','0',
'0','0','0','0','0','0','0','0',
'0','0','0','0','0','0','0','0',
'0','0','0','0','0','0','0','0',
'0','0','0','0','0','0','0','0',
'0','0','0','0','0','0','0','0',
'0','0','0','0','0','0','0','0',
'0','0','0','0','0','0','0','0'
})]
public void WriteToSpanString(Span<char> destinationSpan)
{
Value.ToSpanString(destinationSpan);
}
#endif

[Benchmark]
public void Read()
{
Expand Down
4 changes: 2 additions & 2 deletions NBitcoin.Tests/NBitcoin.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@
<ProjectReference Include="..\NBitcoin.Altcoins\NBitcoin.Altcoins.csproj" />
<ProjectReference Include="..\NBitcoin.TestFramework\NBitcoin.TestFramework.csproj" />
<PackageReference Include="Microsoft.CSharp" Version="4.6.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
<PackageReference Include="xunit" Version="2.6.5" />
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To allow testing with spans.

<PackageReference Include="xunit.runner.visualstudio" Version="2.5.6">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
Expand Down
22 changes: 15 additions & 7 deletions NBitcoin.Tests/uint256_tests.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
using NBitcoin.Protocol;
using System;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Xunit;

namespace NBitcoin.Tests
Expand Down Expand Up @@ -115,7 +111,7 @@ public void spanUintSerializationTests()

[Fact]
[Trait("UnitTest", "UnitTest")]
public void uitnSerializationTests2()
public void uintSerializationTests2()
{
var v = new uint256("0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20");
var vr = new uint256("201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201");
Expand Down Expand Up @@ -147,7 +143,7 @@ public void uitnSerializationTests2()

[Fact]
[Trait("UnitTest", "UnitTest")]
public void uitnSerializationTests()
public void uintSerializationTests()
{
MemoryStream ms = new MemoryStream();
BitcoinStream stream = new BitcoinStream(ms, true);
Expand Down Expand Up @@ -193,6 +189,18 @@ public void uitnSerializationTests()
Assert.True(vs2.SequenceEqual(vs));
}

#if HAS_SPAN && NET6_0_OR_GREATER // .NET Core 3.1 cannot compile this.
[Fact]
[Trait("UnitTest", "UnitTest")]
public void uintSpanSerializationTests()
{
var v1 = new uint256("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff");

Assert.Equal("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff", v1.ToString());
Assert.Equal("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff".AsSpan(), v1.ToSpanString());
}
#endif

private void AssertEquals(uint256 a, uint256 b)
{
Assert.Equal(a, b);
Expand Down
54 changes: 51 additions & 3 deletions NBitcoin/UInt256.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@

using NBitcoin.DataEncoders;
using System;
using System.Collections;
#if HAS_SPAN
using System.Buffers.Binary;
#endif
using System.Linq;
using System.Runtime.InteropServices;
using NBitcoin.DataEncoders;

namespace NBitcoin
{
Expand Down Expand Up @@ -161,6 +162,53 @@ public override string ToString()
return Encoder.EncodeData(bytes);
}

#if HAS_SPAN

/// <summary>
/// Returns HEX string representation.
/// </summary>
/// <remarks>The method allocates a new 64 char array.</remarks>
public Span<char> ToSpanString()
{
Span<char> result = new char[64];

ToSpanString(result);
return result;
}

/// <summary>
/// Returns HEX string representation.
/// </summary>
/// <remarks>The method does not allocate.</remarks>
public void ToSpanString(Span<char> destination)
{
Span<ulong> ulongs = stackalloc ulong[4];

if (BitConverter.IsLittleEndian)
{
ulongs[0] = pn0;
ulongs[1] = pn1;
ulongs[2] = pn2;
ulongs[3] = pn3;
}
else
{
ulongs[0] = BinaryPrimitives.ReverseEndianness(pn0);
ulongs[1] = BinaryPrimitives.ReverseEndianness(pn1);
ulongs[2] = BinaryPrimitives.ReverseEndianness(pn2);
ulongs[3] = BinaryPrimitives.ReverseEndianness(pn3);
}

Span<byte> bytes = MemoryMarshal.Cast<ulong, byte>(ulongs);

// Reverses order of bytes as pn0, pn1, pn2, and pn3 are set in a little endian manner.
for (int i = 31, j = 0; i >= 0; i--, j += 2)
{
HexEncoder.ToCharsBuffer(bytes[i], destination, startingIndex: j);
}
}
#endif

public uint256(ulong b)
{
pn0 = (uint)b;
Expand Down
Loading