DotNext by .NET Foundation and Contributors

<PackageReference Include="DotNext" Version="4.10.0" />

 BinaryTransformations

public static class BinaryTransformations
Provides various binary transformations.
using DotNext.Runtime; using System; using System.Buffers.Binary; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; using System.Runtime.Versioning; namespace DotNext.Buffers.Binary { public static class BinaryTransformations { [StructLayout(LayoutKind.Sequential, Size = 1)] [RequiresPreviewFeatures] private readonly struct BitwiseAndTransformation : IBinaryTransformation<UIntPtr>, IBinaryTransformation<Vector<byte>> { static Vector<byte> IBinaryTransformation<Vector<byte>>.Transform(Vector<byte> x, Vector<byte> y) { return Vector.BitwiseAnd(x, y); } [return: System.Runtime.CompilerServices.NativeInteger] static unsafe UIntPtr IBinaryTransformation<UIntPtr>.Transform([System.Runtime.CompilerServices.NativeInteger] UIntPtr x, [System.Runtime.CompilerServices.NativeInteger] UIntPtr y) { return (UIntPtr)(void*)((long)(ulong)x & (long)(ulong)y); } } [StructLayout(LayoutKind.Sequential, Size = 1)] [RequiresPreviewFeatures] private readonly struct BitwiseOrTransformation : IBinaryTransformation<UIntPtr>, IBinaryTransformation<Vector<byte>> { static Vector<byte> IBinaryTransformation<Vector<byte>>.Transform(Vector<byte> x, Vector<byte> y) { return Vector.BitwiseOr(x, y); } [return: System.Runtime.CompilerServices.NativeInteger] static unsafe UIntPtr IBinaryTransformation<UIntPtr>.Transform([System.Runtime.CompilerServices.NativeInteger] UIntPtr x, [System.Runtime.CompilerServices.NativeInteger] UIntPtr y) { return (UIntPtr)(void*)((long)(ulong)x | (long)(ulong)y); } } [StructLayout(LayoutKind.Sequential, Size = 1)] [RequiresPreviewFeatures] private readonly struct BitwiseXorTransformation : IBinaryTransformation<UIntPtr>, IBinaryTransformation<Vector<byte>> { static Vector<byte> IBinaryTransformation<Vector<byte>>.Transform(Vector<byte> x, Vector<byte> y) { return Vector.Xor(x, y); } [return: System.Runtime.CompilerServices.NativeInteger] static unsafe UIntPtr IBinaryTransformation<UIntPtr>.Transform([System.Runtime.CompilerServices.NativeInteger] UIntPtr x, [System.Runtime.CompilerServices.NativeInteger] UIntPtr y) { return (UIntPtr)(void*)((long)(ulong)x ^ (long)(ulong)y); } } [StructLayout(LayoutKind.Sequential, Size = 1)] [RequiresPreviewFeatures] private readonly struct BitwiseAndNotTransformation : IBinaryTransformation<UIntPtr>, IBinaryTransformation<Vector<byte>> { static Vector<byte> IBinaryTransformation<Vector<byte>>.Transform(Vector<byte> x, Vector<byte> y) { return Vector.AndNot(x, y); } [return: System.Runtime.CompilerServices.NativeInteger] static unsafe UIntPtr IBinaryTransformation<UIntPtr>.Transform([System.Runtime.CompilerServices.NativeInteger] UIntPtr x, [System.Runtime.CompilerServices.NativeInteger] UIntPtr y) { return (UIntPtr)(void*)((long)(ulong)x & (long)(IntPtr)(void*)(~(ulong)y)); } } [StructLayout(LayoutKind.Sequential, Size = 1)] [RequiresPreviewFeatures] private readonly struct OnesComplementTransformation : IUnaryTransformation<UIntPtr>, IUnaryTransformation<Vector<byte>> { static Vector<byte> IUnaryTransformation<Vector<byte>>.Transform(Vector<byte> value) { return Vector.OnesComplement(value); } [return: System.Runtime.CompilerServices.NativeInteger] static unsafe UIntPtr IUnaryTransformation<UIntPtr>.Transform([System.Runtime.CompilerServices.NativeInteger] UIntPtr value) { return (UIntPtr)(void*)(~(ulong)value); } } [RequiresPreviewFeatures] private interface IUnaryTransformation<[System.Runtime.CompilerServices.IsUnmanaged] T> where T : struct { T Transform(T value); } [RequiresPreviewFeatures] private interface IBinaryTransformation<[System.Runtime.CompilerServices.IsUnmanaged] T> where T : struct { T Transform(T x, T y); } [RequiresPreviewFeatures] private interface IEndiannessTransformation<[System.Runtime.CompilerServices.IsUnmanaged] T> : IUnaryTransformation<T> where T : struct { Vector128<byte> ReorderMask { get; } } [StructLayout(LayoutKind.Auto)] [RequiresPreviewFeatures] private readonly struct UInt16Transformation : IEndiannessTransformation<ushort>, IUnaryTransformation<ushort> { public Vector128<byte> ReorderMask { get; } public UInt16Transformation() { ReorderMask = Vector128.Create((byte)1, (byte)0, (byte)3, (byte)2, (byte)5, (byte)4, (byte)7, (byte)6, (byte)9, (byte)8, (byte)11, (byte)10, (byte)13, (byte)12, (byte)15, (byte)14); } static ushort IUnaryTransformation<ushort>.Transform(ushort value) { return BinaryPrimitives.ReverseEndianness(value); } } [StructLayout(LayoutKind.Auto)] [RequiresPreviewFeatures] private readonly struct UInt32Transformation : IEndiannessTransformation<uint>, IUnaryTransformation<uint> { public Vector128<byte> ReorderMask { get; } public UInt32Transformation() { ReorderMask = Vector128.Create((byte)3, (byte)2, (byte)1, (byte)0, (byte)7, (byte)6, (byte)5, (byte)4, (byte)11, (byte)10, (byte)9, (byte)8, (byte)15, (byte)14, (byte)13, (byte)12); } static uint IUnaryTransformation<uint>.Transform(uint value) { return BinaryPrimitives.ReverseEndianness(value); } } [StructLayout(LayoutKind.Auto)] [RequiresPreviewFeatures] private readonly struct UInt64Transformation : IEndiannessTransformation<ulong>, IUnaryTransformation<ulong> { public Vector128<byte> ReorderMask { get; } public UInt64Transformation() { ReorderMask = Vector128.Create((byte)7, (byte)6, (byte)5, (byte)4, (byte)3, (byte)2, (byte)1, (byte)0, (byte)15, (byte)14, (byte)13, (byte)12, (byte)11, (byte)10, (byte)9, (byte)8); } static ulong IUnaryTransformation<ulong>.Transform(ulong value) { return BinaryPrimitives.ReverseEndianness(value); } } public static void BitwiseAnd<[System.Runtime.CompilerServices.IsUnmanaged] T>(this ReadOnlySpan<T> x, Span<T> y) where T : struct { if (x.Length != y.Length) throw new ArgumentOutOfRangeException("x"); Transform<T, BitwiseAndTransformation>(x, y); } public static void AndNot<[System.Runtime.CompilerServices.IsUnmanaged] T>(this ReadOnlySpan<T> x, Span<T> y) where T : struct { if (x.Length != y.Length) throw new ArgumentOutOfRangeException("x"); Transform<T, BitwiseAndNotTransformation>(x, y); } public static void BitwiseOr<[System.Runtime.CompilerServices.IsUnmanaged] T>(this ReadOnlySpan<T> x, Span<T> y) where T : struct { if (x.Length != y.Length) throw new ArgumentOutOfRangeException("x"); Transform<T, BitwiseOrTransformation>(x, y); } public static void BitwiseXor<[System.Runtime.CompilerServices.IsUnmanaged] T>(this ReadOnlySpan<T> x, Span<T> y) where T : struct { if (x.Length != y.Length) throw new ArgumentOutOfRangeException("x"); Transform<T, BitwiseXorTransformation>(x, y); } public static void OnesComplement<[System.Runtime.CompilerServices.IsUnmanaged] T>(this Span<T> values) where T : struct { Transform<T, OnesComplementTransformation>(values); } [RequiresPreviewFeatures] private unsafe static void Transform<TTransformation>(ref byte x, int length) where TTransformation : struct, IUnaryTransformation<UIntPtr>, IUnaryTransformation<Vector<byte>> { if (Vector.IsHardwareAccelerated) { while (length >= Vector<byte>.Count) { Unsafe.WriteUnaligned<Vector<byte>>(value: ((IUnaryTransformation<Vector<byte>>)x).Transform(Unsafe.ReadUnaligned<Vector<byte>>(ref x)), destination: ref *(byte*)); ref x = ref Unsafe.Add(ref x, Vector<byte>.Count); length -= Vector<byte>.Count; } } while (length >= UIntPtr.Size) { Unsafe.WriteUnaligned<UIntPtr>(value: ((IUnaryTransformation<UIntPtr>)x).Transform(Unsafe.ReadUnaligned<UIntPtr>(ref x)), destination: ref *(byte*)); ref x = ref Unsafe.Add(ref x, UIntPtr.Size); length -= UIntPtr.Size; } while (length > 0) { byte num = (byte)(ulong)((IUnaryTransformation<UIntPtr>)x).Transform((UIntPtr)(void*)x); *(sbyte*)(long)(IntPtr)(void*) = (sbyte)num; ref x = ref Unsafe.Add(ref x, 1); length--; } } [RequiresPreviewFeatures] private unsafe static void Transform<[System.Runtime.CompilerServices.IsUnmanaged] T, TTransformation>(Span<T> values) where T : struct where TTransformation : struct, IUnaryTransformation<UIntPtr>, IUnaryTransformation<Vector<byte>> { int val = Array.get_MaxLength() / sizeof(T); while (!values.IsEmpty) { int num = Math.Min(val, values.Length); Transform<TTransformation>(ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(values)), num * sizeof(T)); values = values.Slice(num); } } [RequiresPreviewFeatures] private unsafe static void Transform<TTransformation>([In] ref byte x, ref byte y, int length) where TTransformation : struct, IBinaryTransformation<UIntPtr>, IBinaryTransformation<Vector<byte>> { if (Vector.IsHardwareAccelerated) { while (length >= Vector<byte>.Count) { Unsafe.WriteUnaligned<Vector<byte>>(value: ((IBinaryTransformation<Vector<byte>>)y).Transform(Unsafe.ReadUnaligned<Vector<byte>>(ref x), Unsafe.ReadUnaligned<Vector<byte>>(ref y)), destination: ref *(byte*)); ref x = ref Unsafe.Add(ref x, Vector<byte>.Count); ref y = ref Unsafe.Add(ref y, Vector<byte>.Count); length -= Vector<byte>.Count; } } while (length >= UIntPtr.Size) { Unsafe.WriteUnaligned<UIntPtr>(value: ((IBinaryTransformation<UIntPtr>)y).Transform(Unsafe.ReadUnaligned<UIntPtr>(ref x), Unsafe.ReadUnaligned<UIntPtr>(ref y)), destination: ref *(byte*)); ref x = ref Unsafe.Add(ref x, UIntPtr.Size); ref y = ref Unsafe.Add(ref y, UIntPtr.Size); length -= UIntPtr.Size; } while (length > 0) { byte num = (byte)(ulong)((IBinaryTransformation<UIntPtr>)y).Transform((UIntPtr)(void*)x, (UIntPtr)(void*)y); *(sbyte*)(long)(IntPtr)(void*) = (sbyte)num; ref x = ref Unsafe.Add(ref x, 1); ref y = ref Unsafe.Add(ref y, 1); length--; } } [RequiresPreviewFeatures] private unsafe static void Transform<[System.Runtime.CompilerServices.IsUnmanaged] T, TTransformation>(ReadOnlySpan<T> x, Span<T> y) where T : struct where TTransformation : struct, IBinaryTransformation<UIntPtr>, IBinaryTransformation<Vector<byte>> { int val = Array.get_MaxLength() / sizeof(T); while (!x.IsEmpty) { int num = Math.Min(val, x.Length); Transform<TTransformation>(ref Unsafe.As<T, byte>(ref Unsafe.AsRef(ref MemoryMarshal.GetReference(x))), ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(y)), num * sizeof(T)); x = x.Slice(num); y = y.Slice(num); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vector128<T> LoadVector128<[System.Runtime.CompilerServices.IsUnmanaged] T>(ref T input) where T : struct { return Unsafe.ReadUnaligned<Vector128<T>>(ref Unsafe.As<T, byte>(ref input)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vector128<T> LoadVector128<[System.Runtime.CompilerServices.IsUnmanaged] T>(ReadOnlySpan<T> input) where T : struct { return LoadVector128(ref MemoryMarshal.GetReference(input)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vector256<T> LoadVector256<[System.Runtime.CompilerServices.IsUnmanaged] T>(ref T input) where T : struct { return Unsafe.ReadUnaligned<Vector256<T>>(ref Unsafe.As<T, byte>(ref input)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vector256<T> LoadVector256<[System.Runtime.CompilerServices.IsUnmanaged] T>(ReadOnlySpan<T> input) where T : struct { return LoadVector256(ref MemoryMarshal.GetReference(input)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void StoreVector128<[System.Runtime.CompilerServices.IsUnmanaged] T>(Vector128<T> input, ref T output) where T : struct { Unsafe.WriteUnaligned(ref Unsafe.As<T, byte>(ref output), input); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void StoreVector128<[System.Runtime.CompilerServices.IsUnmanaged] T>(Vector128<T> input, Span<T> output) where T : struct { StoreVector128(input, ref MemoryMarshal.GetReference(output)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void StoreVector256<[System.Runtime.CompilerServices.IsUnmanaged] T>(Vector256<T> input, ref T output) where T : struct { Unsafe.WriteUnaligned(ref Unsafe.As<T, byte>(ref output), input); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void StoreVector256<[System.Runtime.CompilerServices.IsUnmanaged] T>(Vector256<T> input, Span<T> output) where T : struct { StoreVector256(input, ref MemoryMarshal.GetReference(output)); } [RequiresPreviewFeatures] private unsafe static void ReverseEndianness<[System.Runtime.CompilerServices.IsUnmanaged] T, TTransformation>(Span<T> buffer, TTransformation transformation) where T : struct where TTransformation : struct, IEndiannessTransformation<T> { if (Ssse3.IsSupported) { if (Avx2.IsSupported) { Vector256<byte> mask = Vector256.Create(((IEndiannessTransformation<T>)transformation).ReorderMask, ((IEndiannessTransformation<T>)transformation).ReorderMask); while (buffer.Length >= Vector256<T>.Count) { StoreVector256(Avx2.Shuffle(LoadVector256<T>(buffer).AsByte(), mask).As<byte, T>(), buffer); buffer = buffer.Slice(Vector256<T>.Count); } } while (buffer.Length >= Vector128<T>.Count) { StoreVector128(Ssse3.Shuffle(LoadVector128<T>(buffer).AsByte(), ((IEndiannessTransformation<T>)transformation).ReorderMask).As<byte, T>(), buffer); buffer = buffer.Slice(Vector128<T>.Count); } } Span<T> span = buffer; for (int i = 0; i < span.Length; i++) { ref T reference = ref span[i]; T val = ((IUnaryTransformation<T>)reference).Transform(reference); *(T*)(long)(IntPtr)(void*) = val; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] [RequiresPreviewFeatures] private unsafe static void ReverseEndianness<[System.Runtime.CompilerServices.IsUnmanaged] T, TTransformation>(Span<T> buffer) where T : struct where TTransformation : struct, IEndiannessTransformation<T> { switch (buffer.Length) { case 0: break; case 1: { ref T reference = ref buffer[0]; T val = ((IUnaryTransformation<T>)reference).Transform(reference); *(T*)(long)(IntPtr)(void*) = val; break; } default: ReverseEndianness(buffer, new TTransformation()); break; } } public static void ReverseEndianness(this Span<short> buffer) { ReverseEndianness<ushort, UInt16Transformation>(Intrinsics.ReinterpretCast<short, ushort>(buffer)); } [CLSCompliant(false)] public static void ReverseEndianness(this Span<ushort> buffer) { ReverseEndianness<ushort, UInt16Transformation>(buffer); } public static void ReverseEndianness(this Span<int> buffer) { ReverseEndianness<uint, UInt32Transformation>(Intrinsics.ReinterpretCast<int, uint>(buffer)); } [CLSCompliant(false)] public static void ReverseEndianness(this Span<uint> buffer) { ReverseEndianness<uint, UInt32Transformation>(buffer); } public static void ReverseEndianness(this Span<long> buffer) { ReverseEndianness<ulong, UInt64Transformation>(Intrinsics.ReinterpretCast<long, ulong>(buffer)); } [CLSCompliant(false)] public static void ReverseEndianness(this Span<ulong> buffer) { ReverseEndianness<ulong, UInt64Transformation>(buffer); } } }