Skip to content

Commit

Permalink
Support for netstandard2.1;netstandard2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
VNNCC committed May 21, 2024
1 parent 1a8a9ab commit 2bb2ee4
Show file tree
Hide file tree
Showing 30 changed files with 629 additions and 323 deletions.
10 changes: 10 additions & 0 deletions src/NuGetPackage.props
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,14 @@
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
</ItemGroup>

<!-- Framework Compatibility -->
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<PackageReference Include="System.Memory" Version="4.5.5" />
<PackageReference Include="IndexRange" Version="1.0.3" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.1'">
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Snowberry.IO.Benchmarks.Conversions;
[MediumRunJob]
public class Int16ConversionBenchmark
{
private static byte[] _data = { 0x12, 0x23, 0x14, 0x19 };
private static byte[] _data = [0x12, 0x23, 0x14, 0x19];

[Benchmark]
public short BitConverter_Int16()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Snowberry.IO.Benchmarks.Conversions;
[MediumRunJob]
public class Int32ConversionBenchmark
{
private static byte[] _data = { 0x12, 0x23, 0x14, 0x19, 0x12, 0x23, 0x14, 0x19 };
private static byte[] _data = [0x12, 0x23, 0x14, 0x19, 0x12, 0x23, 0x14, 0x19];

[Benchmark]
public int BitConverter_Int32()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Snowberry.IO.Benchmarks.Conversions;
[MediumRunJob]
public class Int64ConversionBenchmark
{
private static byte[] _data = { 0x12, 0x23, 0x14, 0x19, 0x12, 0x23, 0x14, 0x19, 0x12, 0x23, 0x14, 0x19, 0x12, 0x23, 0x14, 0x19 };
private static byte[] _data = [0x12, 0x23, 0x14, 0x19, 0x12, 0x23, 0x14, 0x19, 0x12, 0x23, 0x14, 0x19, 0x12, 0x23, 0x14, 0x19];

[Benchmark]
public long BitConverter_Int64()
Expand All @@ -21,7 +21,7 @@ public long BitConverter_Int64()
[Benchmark]
public unsafe long BinaryEndianConverter_Int64()
{
return BinaryEndianConverter.ToLong(_data.AsSpan(), EndianType.BIG);
return BinaryEndianConverter.ToLong(_data.AsSpan(), EndianType.LITTLE);
}

[Benchmark]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Snowberry.IO.Benchmarks.Conversions;
[MediumRunJob]
public class UInt32ConversionBenchmark
{
private static byte[] _data = { 0xD6, 0x87, 0x00, 0x00, 0xD6, 0x87, 0x00, 0x00 };
private static byte[] _data = [0xD6, 0x87, 0x00, 0x00, 0xD6, 0x87, 0x00, 0x00];

[Benchmark]
public uint BitConverter_UInt32()
Expand Down
6 changes: 3 additions & 3 deletions src/Snowberry.IO.Benchmarks/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ internal class Program
{
private static void Main(string[] args)
{
_ = BenchmarkRunner.Run(typeof(Int16ConversionBenchmark));
_ = BenchmarkRunner.Run(typeof(Int32ConversionBenchmark));
_ = BenchmarkRunner.Run(typeof(UInt32ConversionBenchmark));
//_ = BenchmarkRunner.Run(typeof(Int16ConversionBenchmark));
//_ = BenchmarkRunner.Run(typeof(Int32ConversionBenchmark));
//_ = BenchmarkRunner.Run(typeof(UInt32ConversionBenchmark));
_ = BenchmarkRunner.Run(typeof(Int64ConversionBenchmark));
}
}
56 changes: 50 additions & 6 deletions src/Snowberry.IO.Common/BinaryEndianConverter.Offsets.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
#if NET6_0_OR_GREATER
using System;
using System;
using System.Runtime.CompilerServices;

namespace Snowberry.IO.Common;

public static partial class BinaryEndianConverter
{
#if NETCOREAPP3_0_OR_GREATER
[SkipLocalsInit]
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
#endif
public static unsafe long ToLong(Span<byte> data, int offset, EndianType endian)
{
if (endian == EndianType.LITTLE)
Expand All @@ -18,8 +19,10 @@ public static unsafe long ToLong(Span<byte> data, int offset, EndianType endian)
| ((long)((bigSource[0] << 24) | (bigSource[1] << 16) | (bigSource[2] << 8) | bigSource[3]) << 32);
}

#if NETCOREAPP3_0_OR_GREATER
[SkipLocalsInit]
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
#endif
public static unsafe ulong ToULong(Span<byte> data, int offset, EndianType endian)
{
if (endian == EndianType.LITTLE)
Expand All @@ -30,8 +33,10 @@ public static unsafe ulong ToULong(Span<byte> data, int offset, EndianType endia
| ((long)((bigSource[0] << 24) | (bigSource[1] << 16) | (bigSource[2] << 8) | bigSource[3]) << 32)));
}

#if NETCOREAPP3_0_OR_GREATER
[SkipLocalsInit]
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
#endif
public static unsafe ushort ToUInt16(Span<byte> data, int offset, EndianType endian)
{
if (endian == EndianType.LITTLE)
Expand All @@ -41,8 +46,10 @@ public static unsafe ushort ToUInt16(Span<byte> data, int offset, EndianType end
return unchecked((ushort)(bigSource[1] | (bigSource[0] << 8)));
}

#if NETCOREAPP3_0_OR_GREATER
[SkipLocalsInit]
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
#endif
public static unsafe short ToInt16(Span<byte> data, int offset, EndianType endian)
{
if (endian == EndianType.LITTLE)
Expand All @@ -52,8 +59,10 @@ public static unsafe short ToInt16(Span<byte> data, int offset, EndianType endia
return (short)(bigSource[1] | (bigSource[0] << 8));
}

#if NETCOREAPP3_0_OR_GREATER
[SkipLocalsInit]
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
#endif
public static unsafe uint ToUInt32(Span<byte> data, int offset, EndianType endian)
{
if (endian == EndianType.LITTLE)
Expand All @@ -63,8 +72,10 @@ public static unsafe uint ToUInt32(Span<byte> data, int offset, EndianType endia
return unchecked((uint)(bigSource[3] | (bigSource[2] << 8) | (bigSource[1] << 16) | (bigSource[0] << 24)));
}

#if NETCOREAPP3_0_OR_GREATER
[SkipLocalsInit]
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
#endif
public static unsafe int ToInt32(Span<byte> data, int offset, EndianType endian)
{
if (endian == EndianType.LITTLE)
Expand All @@ -74,37 +85,53 @@ public static unsafe int ToInt32(Span<byte> data, int offset, EndianType endian)
return bigSource[3] | (bigSource[2] << 8) | (bigSource[1] << 16) | (bigSource[0] << 24);
}

#if NETCOREAPP3_0_OR_GREATER
[SkipLocalsInit]
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
#endif
public static Guid ToGuid(Span<byte> data, int offset, EndianType endian)
{
if (endian == EndianType.BIG)
{
return new(new[]
{
return new(
[
data[offset + 3], data[offset + 2], data[offset + 1], data[offset],
data[offset + 5], data[offset + 4], data[offset + 7], data[offset + 6],
data[offset + 8], data[offset + 9], data[offset + 10], data[offset + 11],
data[offset + 12], data[offset + 13], data[offset + 14], data[offset + 15]
});
]);
}

#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
return new(data.Slice(offset, 16));
#else
return new Guid(data.Slice(offset, 16).ToArray());
#endif
}

#if NETCOREAPP3_0_OR_GREATER
[SkipLocalsInit]
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
#endif
public static unsafe float ToFloat(Span<byte> data, int offset, EndianType endian)
{
if (endian == EndianType.LITTLE)
return Unsafe.ReadUnaligned<float>(ref data[offset]);

int temp = ToInt32(data, offset, EndianType.BIG);

#if NETSTANDARD2_0
return Int32BitsToSingle(temp);
#else
return BitConverter.Int32BitsToSingle(temp);
#endif

}

#if NETCOREAPP3_0_OR_GREATER
[SkipLocalsInit]
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
#endif
public static unsafe double ToDouble(Span<byte> data, int offset, EndianType endian)
{
if (endian == EndianType.LITTLE)
Expand All @@ -113,5 +140,22 @@ public static unsafe double ToDouble(Span<byte> data, int offset, EndianType end
long temp = ToLong(data, offset, EndianType.BIG);
return BitConverter.Int64BitsToDouble(temp);
}

#if NETSTANDARD2_0
/// <summary>
/// Converts the specified 32-bit signed integer to a single-precision floating-point number
/// by reinterpreting its bit pattern.
/// </summary>
/// <param name="value">The 32-bit signed integer to convert.</param>
/// <returns>A single-precision floating-point number with the same bit representation as the input integer.</returns>
public static float Int32BitsToSingle(int value)
{
unsafe
{
// Create a float pointer and assign the address of the integer
float result = *(float*)&value;
return result;
}
}
#endif
}
#endif
28 changes: 24 additions & 4 deletions src/Snowberry.IO.Common/BinaryEndianConverter.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
#if NET6_0_OR_GREATER
using System;
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace Snowberry.IO.Common;

public static partial class BinaryEndianConverter
{

#if NETCOREAPP3_0_OR_GREATER
[SkipLocalsInit]
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
#endif
public static unsafe int ToInt32(Span<byte> data, EndianType endian)
{
if (endian == EndianType.LITTLE)
Expand All @@ -18,8 +20,10 @@ public static unsafe int ToInt32(Span<byte> data, EndianType endian)
return bigSource[3] | (bigSource[2] << 8) | (bigSource[1] << 16) | (bigSource[0] << 24);
}

#if NETCOREAPP3_0_OR_GREATER
[SkipLocalsInit]
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
#endif
public static unsafe uint ToUInt32(Span<byte> data, EndianType endian)
{
if (endian == EndianType.LITTLE)
Expand All @@ -29,8 +33,10 @@ public static unsafe uint ToUInt32(Span<byte> data, EndianType endian)
return unchecked((uint)(bigSource[3] | (bigSource[2] << 8) | (bigSource[1] << 16) | (bigSource[0] << 24)));
}

#if NETCOREAPP3_0_OR_GREATER
[SkipLocalsInit]
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
#endif
public static unsafe ushort ToUInt16(Span<byte> data, EndianType endian)
{
if (endian == EndianType.LITTLE)
Expand All @@ -40,8 +46,10 @@ public static unsafe ushort ToUInt16(Span<byte> data, EndianType endian)
return unchecked((ushort)(bigSource[1] | (bigSource[0] << 8)));
}

#if NETCOREAPP3_0_OR_GREATER
[SkipLocalsInit]
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
#endif
public static unsafe short ToInt16(Span<byte> data, EndianType endian)
{
if (endian == EndianType.LITTLE)
Expand All @@ -51,19 +59,28 @@ public static unsafe short ToInt16(Span<byte> data, EndianType endian)
return (short)(bigSource[1] | (bigSource[0] << 8));
}

#if NETCOREAPP3_0_OR_GREATER
[SkipLocalsInit]
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
#endif
public static unsafe float ToFloat(Span<byte> data, EndianType endian)
{
if (endian == EndianType.LITTLE)
return Unsafe.ReadUnaligned<float>(ref MemoryMarshal.GetReference(data));

int temp = ToInt32(data, EndianType.BIG);

#if NETSTANDARD2_0
return Int32BitsToSingle(temp);
#else
return BitConverter.Int32BitsToSingle(temp);
#endif
}

#if NETCOREAPP3_0_OR_GREATER
[SkipLocalsInit]
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
#endif
public static unsafe double ToDouble(Span<byte> data, EndianType endian)
{
if (endian == EndianType.LITTLE)
Expand All @@ -73,8 +90,10 @@ public static unsafe double ToDouble(Span<byte> data, EndianType endian)
return BitConverter.Int64BitsToDouble(temp);
}

#if NETCOREAPP3_0_OR_GREATER
[SkipLocalsInit]
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
#endif
public static unsafe long ToLong(Span<byte> data, EndianType endian)
{
if (endian == EndianType.LITTLE)
Expand All @@ -85,8 +104,10 @@ public static unsafe long ToLong(Span<byte> data, EndianType endian)
| ((long)((bigSource[0] << 24) | (bigSource[1] << 16) | (bigSource[2] << 8) | bigSource[3]) << 32);
}

#if NETCOREAPP3_0_OR_GREATER
[SkipLocalsInit]
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
#endif
public static unsafe ulong ToULong(Span<byte> data, EndianType endian)
{
if (endian == EndianType.LITTLE)
Expand All @@ -96,5 +117,4 @@ public static unsafe ulong ToULong(Span<byte> data, EndianType endian)
return unchecked((ulong)((uint)((bigSource[4] << 24) | (bigSource[5] << 16) | (bigSource[6] << 8) | bigSource[7])
| ((long)((bigSource[0] << 24) | (bigSource[1] << 16) | (bigSource[2] << 8) | bigSource[3]) << 32)));
}
}
#endif
}
4 changes: 2 additions & 2 deletions src/Snowberry.IO.Common/BinaryUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ public static void ApplyAlignment(ref long position, byte alignment)
}

/// <summary>
/// Calcualtes the number of padding bytes required to align the start of a data structure.
/// Calculates the number of padding bytes required to align the start of a data structure.
/// </summary>
/// <param name="position">The current position/offset.</param>
/// <param name="alignment">The alignment.</param>
/// <returns>The number of padding bytest required to align the start of a data structure.</returns>
/// <returns>The number of padding bytes required to align the start of a data structure.</returns>
#if NET6_0_OR_GREATER
[MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)]
#else
Expand Down
9 changes: 5 additions & 4 deletions src/Snowberry.IO.Common/Reader/Analyzer.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Snowberry.IO.Common.Reader.Interfaces;
using System;
using Snowberry.IO.Common.Reader.Interfaces;

namespace Snowberry.IO.Common.Reader;

Expand All @@ -17,8 +18,8 @@ public abstract class Analyzer
/// Analyzes the read bytes in the specified <paramref name="buffer"/>.
/// </summary>
/// <param name="reader">The current reader instance.</param>
/// <param name="buffer">The buffer to analyze.</param>
/// <param name="buffer">The span of bytes to analyze.</param>
/// <param name="amount">The amount of bytes that were read.</param>
/// <param name="offset">The offset in the <paramref name="buffer"/> for the new read data, othwerise <see langword="-1"/>.</param>
public abstract void AnalyzeReadBytes(IEndianReader reader, byte[] buffer, int amount, long offset = -1);
/// <param name="offset">The offset in the <paramref name="buffer"/> for the new read data, otherwise <see langword="-1"/>.</param>
public abstract void AnalyzeReadBytes(IEndianReader reader, Span<byte> buffer, int amount, long offset = -1);
}
16 changes: 16 additions & 0 deletions src/Snowberry.IO.Common/Reader/Interfaces/IEndianReader.Span.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;

namespace Snowberry.IO.Common.Reader.Interfaces;

public partial interface IEndianReader
{
/// <summary>
/// Reads a specified number of bytes from the current stream into a buffer.
/// </summary>
/// <param name="buffer">The span of bytes where the read bytes will be stored.</param>
/// <returns>
/// The total number of bytes read into the buffer. This can be less than the number
/// of bytes requested if that many bytes are not currently available, or zero if the end of the stream is reached.
/// </returns>
int Read(Span<byte> buffer);
}
Loading

0 comments on commit 2bb2ee4

Please sign in to comment.