Skip to content

Commit

Permalink
feat: add Unpack for IBinaryInteger<T>
Browse files Browse the repository at this point in the history
This introduces an experiment, to add support for generic math in X10D. So far, build and tests remain passing - this is a good sign. There is potential here.

This API is subject to change and may be removed without warning.
  • Loading branch information
oliverbooth committed Apr 5, 2023
1 parent 3ab1ab0 commit 87a85b8
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 4 deletions.
89 changes: 89 additions & 0 deletions X10D/src/Collections/BinaryIntegerExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#if NET7_0_OR_GREATER
using System.Diagnostics.Contracts;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics.X86;
using X10D.CompilerServices;

namespace X10D.Collections;

/// <summary>
/// Collection-related extension methods for <see cref="IBinaryInteger{T}" />.
/// </summary>
public static class BinaryIntegerExtensions
{
/// <summary>
/// Unpacks this integer into a boolean list, treating it as a bit field.
/// </summary>
/// <param name="value">The value to unpack.</param>
/// <returns>An array of <see cref="bool" /> with a length equal to the size of <typeparamref name="TInteger" />.</returns>
[Pure]
[MethodImpl(CompilerResources.MethodImplOptions)]
public static bool[] Unpack<TInteger>(this TInteger value)
where TInteger : unmanaged, IBinaryInteger<TInteger>
{
unsafe
{
var buffer = new bool[sizeof(TInteger) * 8];
value.Unpack(buffer);
return buffer;
}
}

/// <summary>
/// Unpacks this integer into a boolean list, treating it as a bit field.
/// </summary>
/// <param name="value">The value to unpack.</param>
/// <param name="destination">When this method returns, contains the unpacked booleans from <paramref name="value" />.</param>
/// <exception cref="ArgumentException"><paramref name="destination" /> is not large enough to contain the result.</exception>
[MethodImpl(CompilerResources.MethodImplOptions)]
public static void Unpack<TInteger>(this TInteger value, Span<bool> destination)
where TInteger : unmanaged, IBinaryInteger<TInteger>
{
unsafe
{
if (destination.Length < sizeof(TInteger) * 8)
{
throw new ArgumentException(ExceptionMessages.DestinationSpanLengthTooShort, nameof(destination));
}
}

switch (value)
{
case byte valueByte when Sse3.IsSupported:
valueByte.UnpackInternal_Ssse3(destination);
break;

case int valueInt32 when Avx2.IsSupported:
valueInt32.UnpackInternal_Ssse3(destination);
break;

case int valueInt32 when Sse3.IsSupported:
valueInt32.UnpackInternal_Ssse3(destination);
break;

case short valueInt16 when Sse3.IsSupported:
valueInt16.UnpackInternal_Ssse3(destination);
break;

default:
UnpackInternal_Fallback(value, destination);
break;
}
}

[MethodImpl(CompilerResources.MethodImplOptions)]
internal static void UnpackInternal_Fallback<TInteger>(this TInteger value, Span<bool> destination)
where TInteger : unmanaged, IBinaryInteger<TInteger>
{
unsafe
{
int bitCount = sizeof(TInteger) * 8;
for (var index = 0; index < bitCount; index++)
{
destination[index] = (value & (TInteger.One << index)) != TInteger.Zero;
}
}
}
}
#endif
6 changes: 5 additions & 1 deletion X10D/src/Collections/ByteExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System.Diagnostics.CodeAnalysis;
#if !NET7_0_OR_GREATER
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
#endif
using System.Runtime.CompilerServices;
using X10D.CompilerServices;

Expand All @@ -17,6 +19,7 @@ public static class ByteExtensions
{
private const int Size = sizeof(byte) * 8;

#if !NET7_0_OR_GREATER
/// <summary>
/// Unpacks this 8-bit unsigned integer into a boolean list, treating it as a bit field.
/// </summary>
Expand Down Expand Up @@ -56,6 +59,7 @@ public static void Unpack(this byte value, Span<bool> destination)

UnpackInternal_Fallback(value, destination);
}
#endif

[MethodImpl(CompilerResources.MethodImplOptions)]
internal static void UnpackInternal_Fallback(this byte value, Span<bool> destination)
Expand Down
6 changes: 5 additions & 1 deletion X10D/src/Collections/Int16Extensions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System.Diagnostics.CodeAnalysis;
#if !NET7_0_OR_GREATER
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
#endif
using System.Runtime.CompilerServices;
using X10D.CompilerServices;

Expand All @@ -17,6 +19,7 @@ public static class Int16Extensions
{
private const int Size = sizeof(short) * 8;

#if !NET7_0_OR_GREATER
/// <summary>
/// Unpacks this 16-bit signed integer into a boolean list, treating it as a bit field.
/// </summary>
Expand Down Expand Up @@ -56,6 +59,7 @@ public static void Unpack(this short value, Span<bool> destination)

UnpackInternal_Fallback(value, destination);
}
#endif

[MethodImpl(CompilerResources.MethodImplOptions)]
internal static void UnpackInternal_Fallback(this short value, Span<bool> destination)
Expand Down
6 changes: 5 additions & 1 deletion X10D/src/Collections/Int32Extensions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System.Diagnostics.CodeAnalysis;
#if !NET7_0_OR_GREATER
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
#endif
using System.Runtime.CompilerServices;
using X10D.CompilerServices;

Expand All @@ -17,6 +19,7 @@ public static class Int32Extensions
{
private const int Size = sizeof(int) * 8;

#if !NET7_0_OR_GREATER
/// <summary>
/// Unpacks this 32-bit signed integer into a boolean list, treating it as a bit field.
/// </summary>
Expand Down Expand Up @@ -62,6 +65,7 @@ public static void Unpack(this int value, Span<bool> destination)

UnpackInternal_Fallback(value, destination);
}
#endif

[MethodImpl(CompilerResources.MethodImplOptions)]
internal static void UnpackInternal_Fallback(this int value, Span<bool> destination)
Expand Down
4 changes: 3 additions & 1 deletion X10D/src/Collections/Int64Extensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Diagnostics.Contracts;
#if !NET7_0_OR_GREATER
using System.Diagnostics.Contracts;

namespace X10D.Collections;

Expand Down Expand Up @@ -41,3 +42,4 @@ public static void Unpack(this long value, Span<bool> destination)
}
}
}
#endif

0 comments on commit 87a85b8

Please sign in to comment.