Compare commits

..

1 Commits

Author SHA1 Message Date
Oliver Booth a519c5b232
Merge d2924d7ac0 into 25062bbf8b 2024-06-12 03:00:38 +00:00
8 changed files with 61 additions and 78 deletions

View File

@ -58,7 +58,6 @@ 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

View File

@ -5,7 +5,7 @@ or submit a pull request.
### Pull request guidelines
This project uses C# 12.0 language features where feasible, and adheres to StyleCop rules with some minor adjustments.
This project uses C# 11.0 language features where feasible, and adheres to StyleCop rules with some minor adjustments.
There is an `.editorconfig` included in this repository. For quick and painless pull requests, ensure that the analyzer does not
throw warnings.
@ -17,7 +17,7 @@ convetional commits specification.
Below are a few pointers to which you may refer, but keep in mind this is not an exhaustive list:
- Use C# 12.0 features where possible
- Use C# 11.0 features where possible
- Try to ensure code is CLS-compliant. Where this is not possible, decorate methods with `CLSCompliantAttribute` and pass `false`
- Follow all .NET guidelines and coding conventions.
See https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/coding-style/coding-conventions

View File

@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<LangVersion>12.0</LangVersion>
<LangVersion>11.0</LangVersion>
<Optimize>true</Optimize>
<ImplicitUsings>true</ImplicitUsings>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>

View File

@ -1,54 +0,0 @@
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());
}
}

View File

@ -48,10 +48,9 @@ internal partial class StreamTests
Span<byte> actual = stackalloc byte[16];
ReadOnlySpan<byte> expected = stackalloc byte[]
{
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x68
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x10, 0x00, 0x00
};
int read = stream.Read(actual);
Trace.WriteLine(string.Join(' ', actual.ToArray()));
Assert.That(read, Is.EqualTo(16));
CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray());

View File

@ -92,12 +92,14 @@ public static class SpanExtensions
}
// dotcover disable
//NOSONAR
default:
#if NET7_0_OR_GREATER
throw new UnreachableException(string.Format(ExceptionMessages.EnumSizeIsUnexpected, Unsafe.SizeOf<T>()));
#else
throw new ArgumentException(string.Format(ExceptionMessages.EnumSizeIsUnexpected, Unsafe.SizeOf<T>()));
#endif
//NOSONAR
// dotcover enable
}
}

View File

@ -1,3 +1,4 @@
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Runtime.InteropServices;
@ -12,11 +13,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 16.</returns>
/// <returns>An array of bytes with length 4.</returns>
[Pure]
public static byte[] GetBigEndianBytes(this decimal value)
{
Span<byte> buffer = stackalloc byte[16];
Span<byte> buffer = stackalloc byte[4];
value.TryWriteBigEndianBytes(buffer);
return buffer.ToArray();
}
@ -25,11 +26,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 16.</returns>
/// <returns>An array of bytes with length 4.</returns>
[Pure]
public static byte[] GetLittleEndianBytes(this decimal value)
{
Span<byte> buffer = stackalloc byte[16];
Span<byte> buffer = stackalloc byte[4];
value.TryWriteLittleEndianBytes(buffer);
return buffer.ToArray();
}
@ -43,17 +44,23 @@ public static class DecimalExtensions
public static bool TryWriteBigEndianBytes(this decimal value, Span<byte> destination)
{
Span<int> buffer = stackalloc int[4];
decimal.GetBits(value, buffer);
GetBits(value, buffer);
Span<byte> result = stackalloc byte[16];
MemoryMarshal.Cast<int, byte>(buffer).CopyTo(result);
if (BitConverter.IsLittleEndian)
if (buffer[0].TryWriteBigEndianBytes(destination[..4]) &&
buffer[1].TryWriteBigEndianBytes(destination[4..8]) &&
buffer[2].TryWriteBigEndianBytes(destination[8..12]) &&
buffer[3].TryWriteBigEndianBytes(destination[12..]))
{
result.Reverse();
if (BitConverter.IsLittleEndian)
{
destination.Reverse();
}
return true;
}
return result.TryCopyTo(destination);
destination.Clear();
return false;
}
/// <summary>
@ -65,16 +72,44 @@ public static class DecimalExtensions
public static bool TryWriteLittleEndianBytes(this decimal value, Span<byte> destination)
{
Span<int> buffer = stackalloc int[4];
decimal.GetBits(value, buffer);
GetBits(value, buffer);
Span<byte> result = stackalloc byte[16];
MemoryMarshal.Cast<int, byte>(buffer).CopyTo(result);
if (!BitConverter.IsLittleEndian)
if (buffer[0].TryWriteLittleEndianBytes(destination[..4]) &&
buffer[1].TryWriteLittleEndianBytes(destination[4..8]) &&
buffer[2].TryWriteLittleEndianBytes(destination[8..12]) &&
buffer[3].TryWriteLittleEndianBytes(destination[12..]))
{
result.Reverse();
if (!BitConverter.IsLittleEndian)
{
destination.Reverse();
}
return true;
}
return result.TryCopyTo(destination);
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;
}
#endif
}

View File

@ -98,6 +98,7 @@ public static class RuneExtensions
}
// dotcover disable
//NOSONAR
default:
string exceptionFormat = ExceptionMessages.UnexpectedRuneUtf8SequenceLength;
string message = string.Format(CultureInfo.CurrentCulture, exceptionFormat, length);
@ -106,6 +107,7 @@ public static class RuneExtensions
#else
throw new InvalidOperationException(message);
#endif
//NOSONAR
// dotcover enable
}
}