Skip to content

Commit

Permalink
fix: fix order of bytes in decimal write bytes methods
Browse files Browse the repository at this point in the history
  • Loading branch information
oliverbooth committed Jun 12, 2024
1 parent e5e27c0 commit 68197ef
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 54 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ TypeInitializationException.

### Fixed

- X10D: Fixed `decimal.TryWriteBigEndianBytes` and `decimal.TryWriteLittleEndianBytes`.
- X10D.Hosting: Fixed `AddHostedSingleton` not accepting an interface as the service type.

## [3.3.0] - 2023-08-21
Expand Down
54 changes: 54 additions & 0 deletions X10D.Tests/src/IO/DecimalTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using NUnit.Framework;
using X10D.IO;

namespace X10D.Tests.IO;

[TestFixture]
internal class DecimalTests
{
[Test]
public void GetBigEndianBytes_ShouldReturnBytes_InBigEndian()
{
const decimal value = 1234m;
byte[] expected = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 210];

byte[] bytes = value.GetBigEndianBytes();

CollectionAssert.AreEqual(expected, bytes);
}

[Test]
public void GetLittleEndianBytes_ShouldReturnBytes_InLittleEndian()
{
const decimal value = 1234m;
byte[] expected = [210, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];

byte[] bytes = value.GetLittleEndianBytes();

CollectionAssert.AreEqual(expected, bytes);
}

[Test]
public void TryWriteBigEndianBytes_ShouldWriteBytes_InBigEndian()
{
const decimal value = 1234m;
byte[] expected = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 210];

Span<byte> bytes = stackalloc byte[16];
value.TryWriteBigEndianBytes(bytes);

CollectionAssert.AreEqual(expected, bytes.ToArray());
}

[Test]
public void TryWriteLittleEndianBytes_ShouldWriteBytes_InLittleEndian()
{
const decimal value = 1234m;
byte[] expected = [210, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];

Span<byte> bytes = stackalloc byte[16];
value.TryWriteLittleEndianBytes(bytes);

CollectionAssert.AreEqual(expected, bytes.ToArray());
}
}
3 changes: 2 additions & 1 deletion X10D.Tests/src/IO/StreamTests.WriteDecimal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,10 @@ public void WriteBigEndian_ShouldWriteBigEndian_GivenDecimalArgument()
Span<byte> actual = stackalloc byte[16];
ReadOnlySpan<byte> expected = stackalloc byte[]
{
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x10, 0x00, 0x00
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x68
};
int read = stream.Read(actual);
Trace.WriteLine(string.Join(' ', actual.ToArray()));

Assert.That(read, Is.EqualTo(16));
CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray());
Expand Down
71 changes: 18 additions & 53 deletions X10D/src/IO/DecimalExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Runtime.InteropServices;

Expand All @@ -13,11 +12,11 @@ public static class DecimalExtensions
/// Converts the current decimal number into an array of bytes, as little endian.
/// </summary>
/// <param name="value">The <see cref="int" /> value.</param>
/// <returns>An array of bytes with length 4.</returns>
/// <returns>An array of bytes with length 16.</returns>
[Pure]
public static byte[] GetBigEndianBytes(this decimal value)
{
Span<byte> buffer = stackalloc byte[4];
Span<byte> buffer = stackalloc byte[16];
value.TryWriteBigEndianBytes(buffer);
return buffer.ToArray();
}
Expand All @@ -26,11 +25,11 @@ public static byte[] GetBigEndianBytes(this decimal value)
/// Converts the current decimal number into an array of bytes, as little endian.
/// </summary>
/// <param name="value">The <see cref="int" /> value.</param>
/// <returns>An array of bytes with length 4.</returns>
/// <returns>An array of bytes with length 16.</returns>
[Pure]
public static byte[] GetLittleEndianBytes(this decimal value)
{
Span<byte> buffer = stackalloc byte[4];
Span<byte> buffer = stackalloc byte[16];
value.TryWriteLittleEndianBytes(buffer);
return buffer.ToArray();
}
Expand All @@ -44,23 +43,17 @@ public static byte[] GetLittleEndianBytes(this decimal value)
public static bool TryWriteBigEndianBytes(this decimal value, Span<byte> destination)
{
Span<int> buffer = stackalloc int[4];
GetBits(value, buffer);
decimal.GetBits(value, buffer);

if (buffer[0].TryWriteBigEndianBytes(destination[..4]) &&
buffer[1].TryWriteBigEndianBytes(destination[4..8]) &&
buffer[2].TryWriteBigEndianBytes(destination[8..12]) &&
buffer[3].TryWriteBigEndianBytes(destination[12..]))
{
if (BitConverter.IsLittleEndian)
{
destination.Reverse();
}
Span<byte> result = stackalloc byte[16];
MemoryMarshal.Cast<int, byte>(buffer).CopyTo(result);

return true;
if (BitConverter.IsLittleEndian)
{
result.Reverse();
}

destination.Clear();
return false;
return result.TryCopyTo(destination);
}

/// <summary>
Expand All @@ -72,44 +65,16 @@ public static bool TryWriteBigEndianBytes(this decimal value, Span<byte> destina
public static bool TryWriteLittleEndianBytes(this decimal value, Span<byte> destination)
{
Span<int> buffer = stackalloc int[4];
GetBits(value, buffer);
decimal.GetBits(value, buffer);

if (buffer[0].TryWriteLittleEndianBytes(destination[..4]) &&
buffer[1].TryWriteLittleEndianBytes(destination[4..8]) &&
buffer[2].TryWriteLittleEndianBytes(destination[8..12]) &&
buffer[3].TryWriteLittleEndianBytes(destination[12..]))
{
if (!BitConverter.IsLittleEndian)
{
destination.Reverse();
}
Span<byte> result = stackalloc byte[16];
MemoryMarshal.Cast<int, byte>(buffer).CopyTo(result);

return true;
if (!BitConverter.IsLittleEndian)
{
result.Reverse();
}

destination.Clear();
return false;
}

private static void GetBits(decimal value, Span<int> destination)
{
_ = decimal.GetBits(value, destination);
}

#if !NET5_0_OR_GREATER
private static void WriteBits(Span<int> destination, Span<byte> buffer)
{
var flags = MemoryMarshal.Read<int>(buffer[..4]);
var hi = MemoryMarshal.Read<int>(buffer[4..8]);
var lo = MemoryMarshal.Read<long>(buffer[8..]);

var low = (uint)lo;
var mid = (uint)(lo >> 32);

destination[0] = (int)low;
destination[1] = (int)mid;
destination[2] = hi;
destination[3] = flags;
return result.TryCopyTo(destination);
}
#endif
}

0 comments on commit 68197ef

Please sign in to comment.