diff --git a/X10D/src/Collections/BinaryIntegerExtensions.cs b/X10D/src/Collections/BinaryIntegerExtensions.cs new file mode 100644 index 0000000..2f3a44c --- /dev/null +++ b/X10D/src/Collections/BinaryIntegerExtensions.cs @@ -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; + +/// +/// Collection-related extension methods for . +/// +public static class BinaryIntegerExtensions +{ + /// + /// Unpacks this integer into a boolean list, treating it as a bit field. + /// + /// The value to unpack. + /// An array of with a length equal to the size of . + [Pure] + [MethodImpl(CompilerResources.MethodImplOptions)] + public static bool[] Unpack(this TInteger value) + where TInteger : unmanaged, IBinaryInteger + { + unsafe + { + var buffer = new bool[sizeof(TInteger) * 8]; + value.Unpack(buffer); + return buffer; + } + } + + /// + /// Unpacks this integer into a boolean list, treating it as a bit field. + /// + /// The value to unpack. + /// When this method returns, contains the unpacked booleans from . + /// is not large enough to contain the result. + [MethodImpl(CompilerResources.MethodImplOptions)] + public static void Unpack(this TInteger value, Span destination) + where TInteger : unmanaged, IBinaryInteger + { + 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(this TInteger value, Span destination) + where TInteger : unmanaged, IBinaryInteger + { + unsafe + { + int bitCount = sizeof(TInteger) * 8; + for (var index = 0; index < bitCount; index++) + { + destination[index] = (value & (TInteger.One << index)) != TInteger.Zero; + } + } + } +} +#endif diff --git a/X10D/src/Collections/ByteExtensions.cs b/X10D/src/Collections/ByteExtensions.cs index 427afed..5590368 100644 --- a/X10D/src/Collections/ByteExtensions.cs +++ b/X10D/src/Collections/ByteExtensions.cs @@ -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; @@ -17,6 +19,7 @@ public static class ByteExtensions { private const int Size = sizeof(byte) * 8; +#if !NET7_0_OR_GREATER /// /// Unpacks this 8-bit unsigned integer into a boolean list, treating it as a bit field. /// @@ -56,6 +59,7 @@ public static class ByteExtensions UnpackInternal_Fallback(value, destination); } +#endif [MethodImpl(CompilerResources.MethodImplOptions)] internal static void UnpackInternal_Fallback(this byte value, Span destination) diff --git a/X10D/src/Collections/Int16Extensions.cs b/X10D/src/Collections/Int16Extensions.cs index c53c0fb..c5f8373 100644 --- a/X10D/src/Collections/Int16Extensions.cs +++ b/X10D/src/Collections/Int16Extensions.cs @@ -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; @@ -17,6 +19,7 @@ public static class Int16Extensions { private const int Size = sizeof(short) * 8; +#if !NET7_0_OR_GREATER /// /// Unpacks this 16-bit signed integer into a boolean list, treating it as a bit field. /// @@ -56,6 +59,7 @@ public static class Int16Extensions UnpackInternal_Fallback(value, destination); } +#endif [MethodImpl(CompilerResources.MethodImplOptions)] internal static void UnpackInternal_Fallback(this short value, Span destination) diff --git a/X10D/src/Collections/Int32Extensions.cs b/X10D/src/Collections/Int32Extensions.cs index 7e2ebaf..60455cd 100644 --- a/X10D/src/Collections/Int32Extensions.cs +++ b/X10D/src/Collections/Int32Extensions.cs @@ -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; @@ -17,6 +19,7 @@ public static class Int32Extensions { private const int Size = sizeof(int) * 8; +#if !NET7_0_OR_GREATER /// /// Unpacks this 32-bit signed integer into a boolean list, treating it as a bit field. /// @@ -62,6 +65,7 @@ public static class Int32Extensions UnpackInternal_Fallback(value, destination); } +#endif [MethodImpl(CompilerResources.MethodImplOptions)] internal static void UnpackInternal_Fallback(this int value, Span destination) diff --git a/X10D/src/Collections/Int64Extensions.cs b/X10D/src/Collections/Int64Extensions.cs index 5b31a1d..b6fd7ad 100644 --- a/X10D/src/Collections/Int64Extensions.cs +++ b/X10D/src/Collections/Int64Extensions.cs @@ -1,4 +1,5 @@ -using System.Diagnostics.Contracts; +#if !NET7_0_OR_GREATER +using System.Diagnostics.Contracts; namespace X10D.Collections; @@ -41,3 +42,4 @@ public static class Int64Extensions } } } +#endif