diff --git a/X10D.Tests/src/Collections/BoolListTests.cs b/X10D.Tests/src/Collections/BoolListTests.cs index e67aafc..e0af3d1 100644 --- a/X10D.Tests/src/Collections/BoolListTests.cs +++ b/X10D.Tests/src/Collections/BoolListTests.cs @@ -6,6 +6,13 @@ namespace X10D.Tests.Collections; [TestClass] public class BoolListTests { + [TestMethod] + public void Pack8BitSpan_Should_Pack_Correctly() + { + Span span = stackalloc bool[8] { true, false, true, false, true, false, true, false }; + Assert.AreEqual(85, span.PackByte()); // 01010101 + } + [TestMethod] public void Pack8Bit_Should_Pack_Correctly() { diff --git a/X10D/src/Collections/ByteExtensions.cs b/X10D/src/Collections/ByteExtensions.cs index ecde8af..35403f8 100644 --- a/X10D/src/Collections/ByteExtensions.cs +++ b/X10D/src/Collections/ByteExtensions.cs @@ -22,7 +22,7 @@ public static class ByteExtensions [Pure] public static bool[] Unpack(this byte value) { - bool[] buffer = new bool[Size]; + var buffer = new bool[Size]; value.Unpack(buffer); return buffer; } @@ -59,10 +59,10 @@ public static class ByteExtensions 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 ); - var mask1Lo = Vector128.Create((byte)0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1); + var mask1 = Vector128.Create((byte)0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1); var vec = Vector128.Create(value).AsByte(); - var shuffle = Ssse3.Shuffle(vec, mask1Lo); + var shuffle = Ssse3.Shuffle(vec, mask1); var and = Sse2.AndNot(shuffle, mask2); var cmp = Sse2.CompareEqual(and, Vector128.Zero); var correctness = Sse2.And(cmp, Vector128.Create((byte)0x01)); diff --git a/X10D/src/Collections/DictionaryExtensions.cs b/X10D/src/Collections/DictionaryExtensions.cs index 3d25009..c293f4d 100644 --- a/X10D/src/Collections/DictionaryExtensions.cs +++ b/X10D/src/Collections/DictionaryExtensions.cs @@ -66,12 +66,12 @@ public static class DictionaryExtensions return value; #else - if (dictionary.TryGetValue(key, out var old)) + if (dictionary.TryGetValue(key, out TValue? old)) { - var newValue = updateValueFactory(key, old); - dictionary[key] = newValue; + var updated = updateValueFactory(key, old); + dictionary[key] = updated; - return newValue; + return updated; } else { @@ -124,12 +124,12 @@ public static class DictionaryExtensions } #endif - if (dictionary.TryGetValue(key, out var old)) + if (dictionary.TryGetValue(key, out TValue? old)) { - var newValue = updateValueFactory(key, old); - dictionary[key] = newValue; + var updated = updateValueFactory(key, old); + dictionary[key] = updated; - return newValue; + return updated; } else { @@ -192,7 +192,7 @@ public static class DictionaryExtensions #endif #if NET6_0_OR_GREATER - ref var value = ref CollectionsMarshal.GetValueRefOrAddDefault(dictionary, key, out bool exists); + ref TValue? value = ref CollectionsMarshal.GetValueRefOrAddDefault(dictionary, key, out bool exists); if (exists) { value = updateValueFactory(key, value!); @@ -204,12 +204,12 @@ public static class DictionaryExtensions return value; #else - if (dictionary.TryGetValue(key, out var old)) + if (dictionary.TryGetValue(key, out TValue? old)) { - var update = updateValueFactory(key, old); - dictionary[key] = update; + var updated = updateValueFactory(key, old); + dictionary[key] = updated; - return update; + return updated; } else { @@ -274,12 +274,12 @@ public static class DictionaryExtensions } #endif - if (dictionary.TryGetValue(key, out var old)) + if (dictionary.TryGetValue(key, out TValue? old)) { - var update = updateValueFactory(key, old); - dictionary[key] = update; + var updated = updateValueFactory(key, old); + dictionary[key] = updated; - return update; + return updated; } else { @@ -350,7 +350,7 @@ public static class DictionaryExtensions #endif #if NET6_0_OR_GREATER - ref var value = ref CollectionsMarshal.GetValueRefOrAddDefault(dictionary, key, out bool exists); + ref TValue? value = ref CollectionsMarshal.GetValueRefOrAddDefault(dictionary, key, out bool exists); if (exists) { value = updateValueFactory(key, value!, factoryArgument); @@ -362,12 +362,12 @@ public static class DictionaryExtensions return value; #else - if (dictionary.TryGetValue(key, out var old)) + if (dictionary.TryGetValue(key, out TValue? old)) { - var update = updateValueFactory(key, old, factoryArgument); - dictionary[key] = update; + var updated = updateValueFactory(key, old, factoryArgument); + dictionary[key] = updated; - return update; + return updated; } else { @@ -438,12 +438,12 @@ public static class DictionaryExtensions } #endif - if (dictionary.TryGetValue(key, out var old)) + if (dictionary.TryGetValue(key, out TValue? old)) { - var update = updateValueFactory(key, old, factoryArgument); - dictionary[key] = update; + var updated = updateValueFactory(key, old, factoryArgument); + dictionary[key] = updated; - return update; + return updated; } else { diff --git a/X10D/src/Collections/Int16Extensions.cs b/X10D/src/Collections/Int16Extensions.cs index 5257c61..1bf6176 100644 --- a/X10D/src/Collections/Int16Extensions.cs +++ b/X10D/src/Collections/Int16Extensions.cs @@ -22,7 +22,7 @@ public static class Int16Extensions [Pure] public static bool[] Unpack(this short value) { - bool[] ret = new bool[Size]; + var ret = new bool[Size]; value.Unpack(ret); return ret; } diff --git a/X10D/src/Collections/Int32Extensions.cs b/X10D/src/Collections/Int32Extensions.cs index 7f5b468..f226adf 100644 --- a/X10D/src/Collections/Int32Extensions.cs +++ b/X10D/src/Collections/Int32Extensions.cs @@ -22,7 +22,7 @@ public static class Int32Extensions [Pure] public static bool[] Unpack(this int value) { - bool[] ret = new bool[Size]; + var ret = new bool[Size]; value.Unpack(ret); return ret; } @@ -97,7 +97,7 @@ public static class Int32Extensions var mask1Hi = Vector128.Create((byte)2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3); var one = Vector128.Create((byte)0x01); - + var vec = Vector128.Create(value).AsByte(); var shuffle = Ssse3.Shuffle(vec, mask1Lo); var and = Sse2.AndNot(shuffle, mask2); diff --git a/X10D/src/Collections/Int64Extensions.cs b/X10D/src/Collections/Int64Extensions.cs index 8a5b197..4903138 100644 --- a/X10D/src/Collections/Int64Extensions.cs +++ b/X10D/src/Collections/Int64Extensions.cs @@ -17,7 +17,7 @@ public static class Int64Extensions [Pure] public static bool[] Unpack(this long value) { - bool[] ret = new bool[Size]; + var ret = new bool[Size]; value.Unpack(ret); return ret; } diff --git a/X10D/src/Core/SpanExtensions.cs b/X10D/src/Core/SpanExtensions.cs index af5dfdd..bfdea9b 100644 --- a/X10D/src/Core/SpanExtensions.cs +++ b/X10D/src/Core/SpanExtensions.cs @@ -2,6 +2,12 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +#if NETCOREAPP3_0_OR_GREATER +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; +using System.Runtime.Intrinsics.X86; +#endif + namespace X10D.Core; /// @@ -100,4 +106,93 @@ public static class SpanExtensions return false; #endif // NET6_0_OR_GREATER } + + /// + /// Packs a of booleans into a . + /// + /// The span of booleans to pack. + /// An 8-bit unsigned integer containing the packed booleans. + /// contains more than 8 elements. + [Pure] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte PackByte(this Span source) + { + return PackByte((ReadOnlySpan)source); + } + + /// + /// Packs a of booleans into a . + /// + /// The span of booleans to pack. + /// An 8-bit unsigned integer containing the packed booleans. + /// contains more than 8 elements. + [Pure] + public static byte PackByte(this ReadOnlySpan source) + { + switch (source.Length) + { + case > 8: throw new ArgumentException("Source cannot contain more than 8 elements.", nameof(source)); + case 8: +#if NETSTANDARD2_1 + // TODO: Think of a way to do fast boolean correctness. + goto default; +#else + unsafe + { + ulong reinterpret; + + // Boolean correctness. + if (Sse2.IsSupported) + { + fixed (bool* pSource = source) + { + var vec = Sse2.LoadScalarVector128((ulong*)pSource).AsByte(); + var cmp = Sse2.CompareEqual(vec, Vector128.Zero); + var correctness = Sse2.AndNot(cmp, Vector128.Create((byte)1)); + + reinterpret = correctness.AsUInt64().GetElement(0); + } + } + else if (AdvSimd.IsSupported) + { + // Haven't tested since March 6th 2023 (Reason: Unavailable hardware). + fixed (bool* pSource = source) + { + var vec = AdvSimd.LoadVector64((byte*)pSource); + var cmp = AdvSimd.CompareEqual(vec, Vector64.Zero); + var correctness = AdvSimd.BitwiseSelect(cmp, vec, Vector64.Zero); + + reinterpret = Unsafe.As, ulong>(ref correctness); + } + } + else + { + goto default; + } + + if (BitConverter.IsLittleEndian) + { + const ulong magic = 0b0000_0001_0000_0010_0000_0100_0000_1000_0001_0000_0010_0000_0100_0000_1000_0000; + + return unchecked((byte)(magic * reinterpret >> 56)); + } + else + { + // Haven't tested since March 6th 2023 (Reason: Unavailable hardware). + const ulong magic = 0b1000_0000_0100_0000_0010_0000_0001_0000_0000_1000_0000_0100_0000_0010_0000_0001; + return unchecked((byte)(magic * reinterpret >> 56)); + } + } +#endif + default: + byte result = 0; + + for (var i = 0; i < source.Length; i++) + { + result |= (byte)(source[i] ? 1 << i : 0); + } + + return result; + } + } } diff --git a/X10D/src/Drawing/ColorExtensions.cs b/X10D/src/Drawing/ColorExtensions.cs index bafafbf..e21cf9e 100644 --- a/X10D/src/Drawing/ColorExtensions.cs +++ b/X10D/src/Drawing/ColorExtensions.cs @@ -1,7 +1,6 @@ using System.Diagnostics.Contracts; using System.Drawing; using System.Runtime.CompilerServices; -using X10D.Collections; namespace X10D.Drawing; diff --git a/X10D/src/Math/ComparableExtensions.cs b/X10D/src/Math/ComparableExtensions.cs index ac6c335..58fae9a 100644 --- a/X10D/src/Math/ComparableExtensions.cs +++ b/X10D/src/Math/ComparableExtensions.cs @@ -133,7 +133,7 @@ public static class ComparableExtensions if (lower.GreaterThan(upper)) { throw new ArgumentException( - string.Format(null, ExceptionMessages.LowerCannotBeGreaterThanUpper, lower, upper), + string.Format(CultureInfo.CurrentCulture, ExceptionMessages.LowerCannotBeGreaterThanUpper, lower, upper), nameof(lower)); } diff --git a/X10D/src/Reflection/MemberInfoExtensions.cs b/X10D/src/Reflection/MemberInfoExtensions.cs index ede419f..b54f9b4 100644 --- a/X10D/src/Reflection/MemberInfoExtensions.cs +++ b/X10D/src/Reflection/MemberInfoExtensions.cs @@ -37,7 +37,6 @@ public static class MemberInfoExtensions throw new ArgumentNullException(nameof(member)); } #endif - return Attribute.IsDefined(member, typeof(T)); }