diff --git a/NBitcoin.Bench/UInt256Bench.cs b/NBitcoin.Bench/UInt256Bench.cs index 546a435324..6eac93befb 100644 --- a/NBitcoin.Bench/UInt256Bench.cs +++ b/NBitcoin.Bench/UInt256Bench.cs @@ -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 destinationSpan) + { + Value.ToSpanString(destinationSpan); + } +#endif + [Benchmark] public void Read() { diff --git a/NBitcoin.Tests/NBitcoin.Tests.csproj b/NBitcoin.Tests/NBitcoin.Tests.csproj index 06a46c31ad..45f99e2aa5 100644 --- a/NBitcoin.Tests/NBitcoin.Tests.csproj +++ b/NBitcoin.Tests/NBitcoin.Tests.csproj @@ -41,8 +41,8 @@ - - + + all runtime; build; native; contentfiles; analyzers diff --git a/NBitcoin.Tests/uint256_tests.cs b/NBitcoin.Tests/uint256_tests.cs index b6c2647fa3..cc0da43fb9 100644 --- a/NBitcoin.Tests/uint256_tests.cs +++ b/NBitcoin.Tests/uint256_tests.cs @@ -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 @@ -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"); @@ -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); @@ -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); diff --git a/NBitcoin/UInt256.cs b/NBitcoin/UInt256.cs index 1ad6eb37de..4db276c37f 100644 --- a/NBitcoin/UInt256.cs +++ b/NBitcoin/UInt256.cs @@ -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 { @@ -161,6 +162,53 @@ public override string ToString() return Encoder.EncodeData(bytes); } +#if HAS_SPAN + + /// + /// Returns HEX string representation. + /// + /// The method allocates a new 64 char array. + public Span ToSpanString() + { + Span result = new char[64]; + + ToSpanString(result); + return result; + } + + /// + /// Returns HEX string representation. + /// + /// The method does not allocate. + public void ToSpanString(Span destination) + { + Span 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 bytes = MemoryMarshal.Cast(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;