Skip to content
Merged
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
21 changes: 12 additions & 9 deletions src/Neo/UInt160.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public ReadOnlySpan<byte> GetSpan()
internal Span<byte> GetSpanLittleEndian()
{
Span<byte> buffer = new byte[Length];
SerializeSafeLittleEndian(buffer);
SafeSerialize(buffer);
return buffer; // Keep the same output as Serialize when BigEndian
}

Expand All @@ -128,20 +128,23 @@ public void Serialize(Span<byte> destination)
}
else
{
SerializeSafeLittleEndian(destination);
SafeSerialize(destination);
}
}

internal void SerializeSafeLittleEndian(Span<byte> destination)
// internal for testing, don't use it directly
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void SafeSerialize(Span<byte> destination)
{
// Avoid partial write and keep the same Exception as before if the buffer is too small
if (destination.Length < Length)
throw new ArgumentException($"buffer({destination.Length}) is too small", nameof(destination));

const int IxValue2 = sizeof(ulong);
const int IxValue3 = sizeof(ulong) * 2;

Span<byte> buffer = stackalloc byte[Length];
BinaryPrimitives.WriteUInt64LittleEndian(buffer, _value1);
BinaryPrimitives.WriteUInt64LittleEndian(buffer[IxValue2..], _value2);
BinaryPrimitives.WriteUInt32LittleEndian(buffer[IxValue3..], _value3);
buffer.CopyTo(destination);
BinaryPrimitives.WriteUInt64LittleEndian(destination, _value1);
BinaryPrimitives.WriteUInt64LittleEndian(destination[IxValue2..], _value2);
BinaryPrimitives.WriteUInt32LittleEndian(destination[IxValue3..], _value3);
}

/// <summary>
Expand Down
24 changes: 14 additions & 10 deletions src/Neo/UInt256.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ public ReadOnlySpan<byte> GetSpan()
internal Span<byte> GetSpanLittleEndian()
{
Span<byte> buffer = new byte[Length];
SerializeSafeLittleEndian(buffer);
SafeSerialize(buffer);
return buffer; // Keep the same output as Serialize when BigEndian
}

Expand All @@ -144,6 +144,7 @@ public void Serialize(BinaryWriter writer)
writer.Write(_value4);
}

/// <inheritdoc/>
public void Serialize(Span<byte> destination)
{
if (BitConverter.IsLittleEndian)
Expand All @@ -153,22 +154,25 @@ public void Serialize(Span<byte> destination)
}
else
{
SerializeSafeLittleEndian(destination);
SafeSerialize(destination);
}
}

internal void SerializeSafeLittleEndian(Span<byte> destination)
// internal for testing, don't use it directly
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void SafeSerialize(Span<byte> destination)
{
// Avoid partial write and keep the same Exception as before if the buffer is too small
if (destination.Length < Length)
throw new ArgumentException($"buffer({destination.Length}) is too small", nameof(destination));

const int IxValue2 = sizeof(ulong);
const int IxValue3 = sizeof(ulong) * 2;
const int IxValue4 = sizeof(ulong) * 3;

Span<byte> buffer = stackalloc byte[Length];
BinaryPrimitives.WriteUInt64LittleEndian(buffer, _value1);
BinaryPrimitives.WriteUInt64LittleEndian(buffer[IxValue2..], _value2);
BinaryPrimitives.WriteUInt64LittleEndian(buffer[IxValue3..], _value3);
BinaryPrimitives.WriteUInt64LittleEndian(buffer[IxValue4..], _value4);
buffer.CopyTo(destination);
BinaryPrimitives.WriteUInt64LittleEndian(destination, _value1);
BinaryPrimitives.WriteUInt64LittleEndian(destination[IxValue2..], _value2);
BinaryPrimitives.WriteUInt64LittleEndian(destination[IxValue3..], _value3);
BinaryPrimitives.WriteUInt64LittleEndian(destination[IxValue4..], _value4);
}

public override string ToString()
Expand Down
25 changes: 14 additions & 11 deletions tests/Neo.UnitTests/UT_UInt160.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,27 +152,30 @@ public void TestSpanAndSerialize()
}

[TestMethod]
public void TestSpanAndSerializeBigEndian()
public void TestSpanAndSerializeLittleEndian()
{
// random data
var random = new Random();
var data = new byte[UInt160.Length];
random.NextBytes(data);

var valueBigEndian = new UInt160(data);
var valueLittleEndian = new UInt160(data);
var value = new UInt160(data);

var span = valueBigEndian.GetSpanLittleEndian();
Assert.IsTrue(span.SequenceEqual(valueBigEndian.ToArray()));
var spanLittleEndian = value.GetSpanLittleEndian();
CollectionAssert.AreEqual(data, spanLittleEndian.ToArray());

data = new byte[UInt160.Length];
valueBigEndian.SerializeSafeLittleEndian(data.AsSpan());
CollectionAssert.AreEqual(data, valueBigEndian.ToArray());
var dataLittleEndian = new byte[UInt160.Length];
value.SafeSerialize(dataLittleEndian.AsSpan());
CollectionAssert.AreEqual(data, dataLittleEndian);

// Check that Serialize LittleEndian and Serialize BigEndian are equals
data = new byte[UInt160.Length];
valueLittleEndian.Serialize(data.AsSpan());
CollectionAssert.AreEqual(valueLittleEndian.ToArray(), valueBigEndian.ToArray());
var dataSerialized = new byte[UInt160.Length];
value.Serialize(dataSerialized.AsSpan());
CollectionAssert.AreEqual(value.ToArray(), dataSerialized);

var shortBuffer = new byte[UInt160.Length - 1];
Assert.ThrowsExactly<ArgumentException>(() => value.Serialize(shortBuffer.AsSpan()));
Assert.ThrowsExactly<ArgumentException>(() => value.SafeSerialize(shortBuffer.AsSpan()));
}
}
}
Expand Down
27 changes: 15 additions & 12 deletions tests/Neo.UnitTests/UT_UInt256.cs
Original file line number Diff line number Diff line change
Expand Up @@ -177,26 +177,29 @@ public void TestSpanAndSerialize()
}

[TestMethod]
public void TestSpanAndSerializeBigEndian()
public void TestSpanAndSerializeLittleEndian()
{
var random = new Random();
var data = new byte[UInt256.Length];
random.NextBytes(data);

var valueBigEndian = new UInt256(data);
var valueLittleEndian = new UInt256(data);

var span = valueBigEndian.GetSpanLittleEndian();
Assert.IsTrue(span.SequenceEqual(valueBigEndian.ToArray()));
var value = new UInt256(data);
var spanLittleEndian = value.GetSpanLittleEndian();
CollectionAssert.AreEqual(data, spanLittleEndian.ToArray());

data = new byte[UInt256.Length];
valueBigEndian.SerializeSafeLittleEndian(data.AsSpan());
CollectionAssert.AreEqual(data, valueBigEndian.ToArray());
// Check that Serialize LittleEndian and Serialize BigEndian are equals
var dataLittleEndian = new byte[UInt256.Length];
value.SafeSerialize(dataLittleEndian.AsSpan());
CollectionAssert.AreEqual(value.ToArray(), dataLittleEndian);

// Check that Serialize LittleEndian and Serialize BigEndian are equals
data = new byte[UInt256.Length];
valueLittleEndian.Serialize(data.AsSpan());
CollectionAssert.AreEqual(valueLittleEndian.ToArray(), valueBigEndian.ToArray());
var dataSerialized = new byte[UInt256.Length];
value.Serialize(dataSerialized.AsSpan());
CollectionAssert.AreEqual(value.ToArray(), dataSerialized);

var shortBuffer = new byte[UInt256.Length - 1];
Assert.ThrowsExactly<ArgumentException>(() => value.Serialize(shortBuffer.AsSpan()));
Assert.ThrowsExactly<ArgumentException>(() => value.SafeSerialize(shortBuffer.AsSpan()));
}
}
}