Last active
January 5, 2024 13:28
-
-
Save DCFApixels/4a5caa28b1bec86559dd5250240dcbc2 to your computer and use it in GitHub Desktop.
C# Utility methods for working with bits.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.Runtime.CompilerServices; | |
using System.Text.RegularExpressions; | |
using static DCFApixels.BitsUtility; | |
namespace DCFApixels | |
{ | |
public unsafe static class BitsUtility | |
{ | |
private const char DEFAULT_SEPARATOR = '_'; | |
private const int BYTE_BITS = 8; | |
#region CountBits | |
public static unsafe int CountBits8<T>(T bits) where T : unmanaged | |
{ | |
return CountBits((uint)*(byte*)&bits); | |
} | |
public static unsafe int CountBits16<T>(T bits) where T : unmanaged | |
{ | |
return CountBits((uint)*(ushort*)&bits); | |
} | |
public static unsafe int CountBits32<T>(T bits) where T : unmanaged | |
{ | |
return CountBits(*(uint*)&bits); | |
} | |
public static unsafe int CountBits(float bits) | |
{ | |
return CountBits32(bits); | |
} | |
public static unsafe int CountBits(int bits) | |
{ | |
return CountBits((uint)bits); | |
} | |
public static unsafe int CountBits(uint bits) | |
{ | |
bits = bits - ((bits >> 1) & 0x55555555); | |
bits = (bits & 0x33333333) + ((bits >> 2) & 0x33333333); | |
return (int)(((bits + (bits >> 4) & 0xF0F0F0F) * 0x1010101) >> 24); | |
} | |
public static unsafe int CountBits64<T>(T bits) where T : unmanaged | |
{ | |
return CountBits(*(ulong*)&bits); | |
} | |
public static unsafe int CountBits(double bits) | |
{ | |
return CountBits64(bits); | |
} | |
public static unsafe int CountBits(long bits) | |
{ | |
return CountBits((ulong)bits); | |
} | |
public static unsafe int CountBits(ulong bits) | |
{ | |
bits = bits - ((bits >> 1) & 0x55555555_55555555); | |
bits = (bits & 0x33333333_33333333) + ((bits >> 2) & 0x33333333_33333333); | |
return (int)(((bits + (bits >> 4) & 0x0F0F0F0F_0F0F0F0F) * 0x01010101_01010101) >> (24 + 32)); | |
} | |
#endregion | |
#region GetHighBitNumber | |
public static unsafe int GetHighBitNumber8<T>(T bits) where T : unmanaged | |
{ | |
return GetHighBitNumber(*(byte*)&bits); | |
} | |
public static int GetHighBitNumber(sbyte bits) | |
{ | |
return GetHighBitNumber((byte)bits); | |
} | |
public static int GetHighBitNumber(byte bits) | |
{ | |
if (bits == 0) | |
{ | |
return -1; | |
} | |
int bit = 0; | |
if ((bits & 0xF0) != 0) | |
{ | |
bits >>= 4; | |
bit |= 4; | |
} | |
if ((bits & 0xC) != 0) | |
{ | |
bits >>= 2; | |
bit |= 2; | |
} | |
if ((bits & 0x2) != 0) | |
{ | |
bit |= 1; | |
} | |
return bit; | |
} | |
public static unsafe int GetHighBitNumber16<T>(T bits) where T : unmanaged | |
{ | |
return GetHighBitNumber(*(ushort*)&bits); | |
} | |
public static int GetHighBitNumber(short bits) | |
{ | |
return GetHighBitNumber((ushort)bits); | |
} | |
public static int GetHighBitNumber(ushort bits) | |
{ | |
if (bits == 0) | |
{ | |
return -1; | |
} | |
int bit = 0; | |
if ((bits & 0xFF00) != 0) | |
{ | |
bits >>= 8; | |
bit |= 8; | |
} | |
if ((bits & 0xF0) != 0) | |
{ | |
bits >>= 4; | |
bit |= 4; | |
} | |
if ((bits & 0xC) != 0) | |
{ | |
bits >>= 2; | |
bit |= 2; | |
} | |
if ((bits & 0x2) != 0) | |
{ | |
bit |= 1; | |
} | |
return bit; | |
} | |
public static unsafe int GetHighBitNumber32<T>(T bits) where T : unmanaged | |
{ | |
return GetHighBitNumber(*(uint*)&bits); | |
} | |
public static int GetHighBitNumber(float bits) | |
{ | |
return GetHighBitNumber(*(uint*)&bits); | |
} | |
public static int GetHighBitNumber(int bits) | |
{ | |
return GetHighBitNumber((uint)bits); | |
} | |
public static int GetHighBitNumber(uint bits) | |
{ | |
if (bits == 0) | |
{ | |
return -1; | |
} | |
int bit = 0; | |
if ((bits & 0xFFFF0000) != 0) | |
{ | |
bits >>= 16; | |
bit |= 16; | |
} | |
if ((bits & 0xFF00) != 0) | |
{ | |
bits >>= 8; | |
bit |= 8; | |
} | |
if ((bits & 0xF0) != 0) | |
{ | |
bits >>= 4; | |
bit |= 4; | |
} | |
if ((bits & 0xC) != 0) | |
{ | |
bits >>= 2; | |
bit |= 2; | |
} | |
if ((bits & 0x2) != 0) | |
{ | |
bit |= 1; | |
} | |
return bit; | |
} | |
public static unsafe int GetHighBitNumber64<T>(T bits) where T : unmanaged | |
{ | |
return GetHighBitNumber(*(ulong*)&bits); | |
} | |
public static int GetHighBitNumber(double bits) | |
{ | |
return GetHighBitNumber(*(ulong*)&bits); | |
} | |
public static int GetHighBitNumber(long bits) | |
{ | |
return GetHighBitNumber((ulong)bits); | |
} | |
public static int GetHighBitNumber(ulong bits) | |
{ | |
if (bits == 0) | |
{ | |
return -1; | |
} | |
int bit = 0; | |
if ((bits & 0xFFFFFFFF00000000) != 0) | |
{ | |
bits >>= 32; | |
bit |= 32; | |
} | |
if ((bits & 0xFFFF0000) != 0) | |
{ | |
bits >>= 16; | |
bit |= 16; | |
} | |
if ((bits & 0xFF00) != 0) | |
{ | |
bits >>= 8; | |
bit |= 8; | |
} | |
if ((bits & 0xF0) != 0) | |
{ | |
bits >>= 4; | |
bit |= 4; | |
} | |
if ((bits & 0xC) != 0) | |
{ | |
bits >>= 2; | |
bit |= 2; | |
} | |
if ((bits & 0x2) != 0) | |
{ | |
bit |= 1; | |
} | |
return bit; | |
} | |
#endregion | |
#region GetBitNumbers | |
public static unsafe int[] GetBitNumbers32<T>(T bits) where T : unmanaged | |
{ | |
return GetBitNumbers(*(uint*)&bits); | |
} | |
public static unsafe int[] GetBitNumbers(float bits) | |
{ | |
return GetBitNumbers(*(uint*)&bits); | |
} | |
public static int[] GetBitNumbers(int bits) | |
{ | |
return GetBitNumbers((uint)bits); | |
} | |
public static int[] GetBitNumbers(uint bits) | |
{ | |
int[] result = new int[CountBits(bits)]; | |
for (int i = 0; i < result.Length; i++) | |
{ | |
int number = GetHighBitNumber(bits); | |
result[i] = number; | |
bits ^= 1u << number; | |
} | |
return result; | |
} | |
public static unsafe int GetBitNumbersNoAlloc32<T>(T bits, ref int[] numbers) where T : unmanaged | |
{ | |
return GetBitNumbersNoAlloc(*(uint*)&bits, ref numbers); | |
} | |
public static unsafe int GetBitNumbersNoAlloc(float bits, ref int[] numbers) | |
{ | |
return GetBitNumbersNoAlloc(*(uint*)&bits, ref numbers); | |
} | |
public static int GetBitNumbersNoAlloc(int bits, ref int[] numbers) | |
{ | |
return GetBitNumbersNoAlloc((uint)bits, ref numbers); | |
} | |
public static int GetBitNumbersNoAlloc(uint bits, ref int[] numbers) | |
{ | |
int iMax = CountBits(bits); | |
if (iMax >= numbers.Length) | |
Array.Resize(ref numbers, iMax); | |
for (int i = 0; i < iMax; i++) | |
{ | |
int number = GetHighBitNumber(bits); | |
numbers[i] = number; | |
bits ^= 1u << number; | |
} | |
return iMax; | |
} | |
public static unsafe void GetBitNumbersNoAlloc32<T>(T bits, List<int> numbers) where T : unmanaged | |
{ | |
GetBitNumbersNoAlloc(*(uint*)&bits, numbers); | |
} | |
public static unsafe void GetBitNumbersNoAlloc(float bits, List<int> numbers) | |
{ | |
GetBitNumbersNoAlloc(*(uint*)&bits, numbers); | |
} | |
public static void GetBitNumbersNoAlloc(int bits, List<int> numbers) | |
{ | |
GetBitNumbersNoAlloc((uint)bits, numbers); | |
} | |
public static void GetBitNumbersNoAlloc(uint bits, List<int> numbers) | |
{ | |
numbers.Clear(); | |
int iMax = CountBits(bits); | |
for (int i = 0; i < iMax; i++) | |
{ | |
int number = GetHighBitNumber(bits); | |
numbers[i] = number; | |
bits ^= 1u << number; | |
} | |
} | |
public static unsafe int[] GetBitNumbers64<T>(T bits) where T : unmanaged | |
{ | |
return GetBitNumbers(*(ulong*)&bits); | |
} | |
public static unsafe int[] GetBitNumbers(double bits) | |
{ | |
return GetBitNumbers(*(ulong*)&bits); | |
} | |
public static int[] GetBitNumbers(long bits) | |
{ | |
return GetBitNumbers((ulong)bits); | |
} | |
public static int[] GetBitNumbers(ulong bits) | |
{ | |
int[] result = new int[CountBits(bits)]; | |
for (int i = 0; i < result.Length; i++) | |
{ | |
int number = GetHighBitNumber(bits); | |
result[i] = number; | |
bits ^= 1LU << number; | |
} | |
return result; | |
} | |
public static unsafe int GetBitNumbersNoAlloc64<T>(T bits, ref int[] numbers) where T : unmanaged | |
{ | |
return GetBitNumbersNoAlloc(*(ulong*)&bits, ref numbers); | |
} | |
public static unsafe int GetBitNumbersNoAlloc(double bits, ref int[] numbers) | |
{ | |
return GetBitNumbersNoAlloc(*(ulong*)&bits, ref numbers); | |
} | |
public static int GetBitNumbersNoAlloc(long bits, ref int[] numbers) | |
{ | |
return GetBitNumbersNoAlloc((ulong)bits, ref numbers); | |
} | |
public static int GetBitNumbersNoAlloc(ulong bits, ref int[] numbers) | |
{ | |
int iMax = CountBits(bits); | |
if (iMax >= numbers.Length) | |
Array.Resize(ref numbers, iMax); | |
for (int i = 0; i < iMax; i++) | |
{ | |
int number = GetHighBitNumber(bits); | |
numbers[i] = number; | |
bits ^= 1u << number; | |
} | |
return iMax; | |
} | |
public static unsafe void GetBitNumbersNoAlloc64<T>(T bits, List<int> numbers) where T : unmanaged | |
{ | |
GetBitNumbersNoAlloc(*(ulong*)&bits, numbers); | |
} | |
public static unsafe void GetBitNumbersNoAlloc(double bits, List<int> numbers) | |
{ | |
GetBitNumbersNoAlloc(*(ulong*)&bits, numbers); | |
} | |
public static void GetBitNumbersNoAlloc(long bits, List<int> numbers) | |
{ | |
GetBitNumbersNoAlloc((ulong)bits, numbers); | |
} | |
public static void GetBitNumbersNoAlloc(ulong bits, List<int> numbers) | |
{ | |
numbers.Clear(); | |
int iMax = CountBits(bits); | |
for (int i = 0; i < iMax; i++) | |
{ | |
int number = GetHighBitNumber(bits); | |
numbers[i] = number; | |
bits ^= 1u << number; | |
} | |
} | |
#endregion | |
#region ToBitsString | |
public static string ToBitsString<T>(T value, bool withSeparator) where T : unmanaged | |
{ | |
return ToBitsStringInaternal(value, withSeparator ? BYTE_BITS : 0, DEFAULT_SEPARATOR); | |
} | |
public static string ToBitsString<T>(T value, int separateRange) where T : unmanaged | |
{ | |
return ToBitsStringInaternal(value, separateRange, DEFAULT_SEPARATOR); | |
} | |
public static string ToBitsString<T>(T value, char separator = DEFAULT_SEPARATOR, int separateRange = BYTE_BITS) where T : unmanaged | |
{ | |
return ToBitsStringInaternal(value, separateRange, separator); | |
} | |
private static unsafe string ToBitsStringInaternal<T>(T value, int separateRange, char separator) where T : unmanaged | |
{ | |
int size = sizeof(T); | |
int length = size * BYTE_BITS; | |
//byte* bytes = stackalloc byte[size / BYTE_BITS]; | |
byte* bytes = (byte*)&value; | |
char* str = stackalloc char[length]; | |
for (int i = 0; i < length; i++) | |
str[length - i - 1] = (bytes[i / BYTE_BITS] & 1 << (i % BYTE_BITS)) > 0 ? '1' : '0'; | |
if (separateRange > 0) | |
return Regex.Replace(new string(str, 0, length), ".{" + separateRange + "}", "$0" + separator + ""); | |
else | |
return new string(str, 0, length); | |
} | |
#endregion | |
#region ParceBitString | |
public static ulong ToULong(string bitsString) | |
{ | |
const int BIT_SIZE = 64; | |
ulong result = 0; | |
int stringMouse = 0; | |
for (int i = 0; i < BIT_SIZE && stringMouse < bitsString.Length; i++, stringMouse++) | |
{ | |
char chr = bitsString[stringMouse]; | |
if (chr == '1') | |
{ | |
result |= (ulong)1 << (BIT_SIZE - i - 1); | |
continue; | |
} | |
if (chr != '0') | |
{ | |
i--; | |
continue; | |
} | |
} | |
return result; | |
} | |
public static uint ToUInt(string bitsString) | |
{ | |
const int BIT_SIZE = 32; | |
uint result = 0; | |
int stringMouse = 0; | |
for (int i = 0; i < BIT_SIZE && stringMouse < bitsString.Length; i++, stringMouse++) | |
{ | |
char chr = bitsString[stringMouse]; | |
if (chr == '1') | |
{ | |
result |= (uint)1 << (BIT_SIZE - i - 1); | |
continue; | |
} | |
if (chr != '0') | |
{ | |
i--; | |
continue; | |
} | |
} | |
return result; | |
} | |
public static ushort ToUShort(string bitsString) | |
{ | |
const int BIT_SIZE = 16; | |
ushort result = 0; | |
int stringMouse = 0; | |
for (int i = 0; i < BIT_SIZE && stringMouse < bitsString.Length; i++, stringMouse++) | |
{ | |
char chr = bitsString[stringMouse]; | |
if (chr == '1') | |
{ | |
result |= (ushort)(1 << (BIT_SIZE - i - 1)); | |
continue; | |
} | |
if (chr != '0') | |
{ | |
i--; | |
continue; | |
} | |
} | |
return result; | |
} | |
public static byte ToByte(string bitsString) | |
{ | |
const int BIT_SIZE = 8; | |
byte result = 0; | |
int stringMouse = 0; | |
for (int i = 0; i < BIT_SIZE && stringMouse < bitsString.Length; i++, stringMouse++) | |
{ | |
char chr = bitsString[stringMouse]; | |
if (chr == '1') | |
{ | |
result |= (byte)(1 << (BIT_SIZE - i - 1)); | |
continue; | |
} | |
if (chr != '0') | |
{ | |
i--; | |
continue; | |
} | |
} | |
return result; | |
} | |
public static bool ToBool(string bitsString) | |
{ | |
byte result = ToByte(bitsString); | |
return *(bool*)&result; | |
} | |
public static short ToShort(string bitsString) => (short)ToUShort(bitsString); | |
public static int ToInt(string bitsString) => (int)ToUInt(bitsString); | |
public static long ToLong(string bitsString) => (long)ToULong(bitsString); | |
#endregion | |
#region XorShift | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static int NextXorShiftState(int state) | |
{ | |
unchecked { return (state << 13) ^ (state >> 17) ^ (state << 5); }; | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static uint NextXorShiftState(uint state) | |
{ | |
unchecked { return (state << 13) ^ (state >> 17) ^ (state << 5); }; | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static long NextXorShiftState(long state) | |
{ | |
const long m = 0x2545F491_4F6CDD1D; | |
unchecked { return ((state >> 13) ^ (state << 25) ^ (state >> 27)) * m; }; | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static ulong NextXorShiftState(ulong state) | |
{ | |
const ulong m = 0x2545F491_4F6CDD1D; | |
unchecked { return ((state >> 13) ^ (state << 25) ^ (state >> 27)) * m; }; | |
} | |
#endregion | |
#region Q32/64/s31/s63 To Float/Double | |
///<summary>Fast operation: float result = (float)value / int.MaxValue.</summary> | |
///<returns>-1.0f < x < 1.0f</returns> | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static unsafe float Qs31ToFloat(int value) | |
{ | |
unchecked | |
{ | |
if (value < 0) | |
{ | |
uint bits = (((uint)value ^ uint.MaxValue) >> 8) | 0xBF80_0000; | |
return (*(float*)&bits) + 1f; | |
} | |
else | |
{ | |
uint bits = (((uint)value) >> 8) | 0x3F80_0000; | |
return (*(float*)&bits) - 1f; | |
} | |
} | |
} | |
///<summary>Fast operation: float result = (float)value / uint.MaxValue.</summary> | |
///<returns>0.0f <= x < 1.0f</returns> | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static unsafe float Q32ToFloat(uint value) | |
{ | |
unchecked | |
{ | |
uint bits = (value >> 9) | 0x3F80_0000; | |
return (*(float*)&bits) - 1f; | |
} | |
} | |
///<summary>Fast operation: double result = (double)value / long.MaxValue.</summary> | |
///<returns>-1.0d < x < 1.0d</returns> | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static unsafe double Qs63ToDouble(long value) | |
{ | |
unchecked | |
{ | |
if (value < 0) | |
{ | |
ulong bits = (((ulong)value ^ long.MaxValue) >> 11) | 0xBFF0_0000_0000_0000; | |
return (*(double*)&bits) + 1d; | |
} | |
else | |
{ | |
ulong bits = (((ulong)value) >> 11) | 0x3FF0_0000_0000_0000; | |
return (*(double*)&bits) - 1d; | |
} | |
} | |
} | |
///<summary>Fast operation: double result = (double)value / ulong.MaxValue.</summary> | |
///<returns>0.0d <= x < 1.0d</returns> | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static unsafe double Q64ToDouble(ulong value) | |
{ | |
unchecked | |
{ | |
ulong bits = (value >> 12) | 0x3FF0_0000_0000_0000; | |
return (*(double*)&bits) - 1d; | |
} | |
} | |
#endregion | |
#region Other | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static TEnum AllFlags<TEnum>() where TEnum : unmanaged, Enum | |
{ | |
return EnumCache<TEnum>.allFlags; | |
} | |
private static class EnumCache<TEnum> where TEnum : unmanaged, Enum | |
{ | |
public readonly static TEnum empty; | |
public readonly static TEnum allFlags; | |
public readonly static int valuesCount; | |
public readonly static int size; | |
static EnumCache() | |
{ | |
Array values = Enum.GetValues(typeof(TEnum)); | |
size = sizeof(TEnum); | |
long result = 0; | |
valuesCount = values.Length; | |
for (int i = 0; i < valuesCount; i++) | |
{ | |
result |= (long)values.GetValue(i); | |
} | |
ulong emptyBits = 0; | |
allFlags = *(TEnum*)&result; | |
empty = *(TEnum*)&emptyBits; | |
return; | |
} | |
} | |
#endregion | |
} | |
#region FindBitsResult removed | |
/* | |
public unsafe struct FindBitsResult8 : IEnumerable<byte> | |
{ | |
private fixed byte _numbers[8]; | |
public readonly byte Count; | |
public int this[int index] | |
{ | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
get => _numbers[index]; | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public FindBitsResult8(uint bits) | |
{ | |
unchecked | |
{ | |
Count = (byte)CountBits(bits); | |
for (int i = 0; i < Count; i++) | |
{ | |
int number = GetHighBitNumber(bits); | |
_numbers[i] = (byte)number; | |
bits ^= 1u << number; | |
} | |
} | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
private static ReadOnlySpan<byte> CreateSpanInternal(FindBitsResult8 a) | |
{ | |
return new ReadOnlySpan<byte>(a._numbers, a.Count); | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public ReadOnlySpan<byte> ToSpan() | |
{ | |
return CreateSpanInternal(this); | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
private static FindBitsResultEnumerator GetEnumeratorInternal(FindBitsResult8 a) | |
{ | |
return new FindBitsResultEnumerator(a._numbers, a.Count); | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public FindBitsResultEnumerator GetEnumerator() | |
{ | |
return GetEnumeratorInternal(this); | |
} | |
IEnumerator<byte> IEnumerable<byte>.GetEnumerator() => GetEnumerator(); | |
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); | |
} | |
public unsafe struct FindBitsResult16 : IEnumerable<byte> | |
{ | |
private fixed byte _numbers[16]; | |
public readonly byte Count; | |
public int this[int index] | |
{ | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
get => _numbers[index]; | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public FindBitsResult16(uint bits) | |
{ | |
unchecked | |
{ | |
Count = (byte)CountBits(bits); | |
for (int i = 0; i < Count; i++) | |
{ | |
int number = GetHighBitNumber(bits); | |
_numbers[i] = (byte)number; | |
bits ^= 1u << number; | |
} | |
} | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
private static ReadOnlySpan<byte> CreateSpanInternal(FindBitsResult16 a) | |
{ | |
return new ReadOnlySpan<byte>(a._numbers, a.Count); | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public ReadOnlySpan<byte> ToSpan() | |
{ | |
return CreateSpanInternal(this); | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
private static FindBitsResultEnumerator GetEnumeratorInternal(FindBitsResult16 a) | |
{ | |
return new FindBitsResultEnumerator(a._numbers, a.Count); | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public FindBitsResultEnumerator GetEnumerator() | |
{ | |
return GetEnumeratorInternal(this); | |
} | |
IEnumerator<byte> IEnumerable<byte>.GetEnumerator() => GetEnumerator(); | |
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); | |
} | |
public unsafe struct FindBitsResult32 : IEnumerable<byte> | |
{ | |
public fixed byte _numbers[32]; | |
public readonly byte Count; | |
public int this[int index] | |
{ | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
get => _numbers[index]; | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public FindBitsResult32(uint bits) | |
{ | |
unchecked | |
{ | |
Count = (byte)CountBits(bits); | |
for (int i = 0; i < Count; i++) | |
{ | |
int number = GetHighBitNumber(bits); | |
_numbers[i] = (byte)number; | |
bits ^= 1u << number; | |
} | |
} | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
private static ReadOnlySpan<byte> CreateSpanInternal(FindBitsResult32 a) | |
{ | |
return new ReadOnlySpan<byte>(a._numbers, a.Count); | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public ReadOnlySpan<byte> ToSpan() | |
{ | |
return CreateSpanInternal(this); | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
private static FindBitsResultEnumerator GetEnumeratorInternal(FindBitsResult32 a) | |
{ | |
return new FindBitsResultEnumerator(a._numbers, a.Count); | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public FindBitsResultEnumerator GetEnumerator() | |
{ | |
return GetEnumeratorInternal(this); | |
} | |
IEnumerator<byte> IEnumerable<byte>.GetEnumerator() => GetEnumerator(); | |
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); | |
} | |
public unsafe struct FindBitsResult64 : IEnumerable<byte> | |
{ | |
private fixed byte _numbers[64]; | |
public readonly byte Count; | |
public int this[int index] | |
{ | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
get => _numbers[index]; | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public FindBitsResult64(ulong bits) | |
{ | |
unchecked | |
{ | |
Count = (byte)CountBits(bits); | |
for (int i = 0; i < Count; i++) | |
{ | |
int number = GetHighBitNumber(bits); | |
_numbers[i] = (byte)number; | |
bits ^= 1u << number; | |
} | |
} | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
private static ReadOnlySpan<byte> CreateSpanInternal(FindBitsResult64 a) | |
{ | |
return new ReadOnlySpan<byte>(a._numbers, a.Count); | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public ReadOnlySpan<byte> ToSpan() | |
{ | |
return CreateSpanInternal(this); | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
private static FindBitsResultEnumerator GetEnumeratorInternal(FindBitsResult64 a) | |
{ | |
return new FindBitsResultEnumerator(a._numbers, a.Count); | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public FindBitsResultEnumerator GetEnumerator() | |
{ | |
return GetEnumeratorInternal(this); | |
} | |
IEnumerator<byte> IEnumerable<byte>.GetEnumerator() => GetEnumerator(); | |
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); | |
} | |
public unsafe struct FindBitsResultEnumerator : IEnumerator<byte> | |
{ | |
private byte* _numbers; | |
private byte _count; | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public FindBitsResultEnumerator(byte* numbers, byte count) | |
{ | |
_numbers = numbers; | |
_count = count; | |
} | |
public byte Current | |
{ | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
get | |
{ | |
return *_numbers; | |
} | |
} | |
object IEnumerator.Current => Current; | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public bool MoveNext() | |
{ | |
return _count-- > 0; | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public void Dispose() { } | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public void Reset() { } | |
} | |
*/ | |
#endregion | |
#region FindBitsIterator | |
public struct FindBitsIterator8 : IEnumerable<int> | |
{ | |
private Enumerator _enumerator; | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public FindBitsIterator8(sbyte bits) | |
{ | |
_enumerator = new Enumerator((byte)bits); | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public FindBitsIterator8(byte bits) | |
{ | |
_enumerator = new Enumerator(bits); | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public Enumerator GetEnumerator() | |
{ | |
return _enumerator; | |
} | |
IEnumerator<int> IEnumerable<int>.GetEnumerator() => GetEnumerator(); | |
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); | |
public struct Enumerator : IEnumerator<int> | |
{ | |
private uint _bits; | |
private int _count; | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public Enumerator(byte bits) | |
{ | |
_count = CountBits(bits); | |
_bits = bits; | |
} | |
public int Current | |
{ | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
get | |
{ | |
int number = GetHighBitNumber((byte)_bits); | |
_bits ^= 1u << number; | |
return number; | |
} | |
} | |
object IEnumerator.Current => Current; | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public bool MoveNext() | |
{ | |
return _count-- > 0; | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
void IDisposable.Dispose() { } | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
void IEnumerator.Reset() { } | |
} | |
} | |
public struct FindBitsIterator16 : IEnumerable<int> | |
{ | |
private Enumerator _enumerator; | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public FindBitsIterator16(short bits) | |
{ | |
_enumerator = new Enumerator((ushort)bits); | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public FindBitsIterator16(ushort bits) | |
{ | |
_enumerator = new Enumerator(bits); | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public Enumerator GetEnumerator() | |
{ | |
return _enumerator; | |
} | |
IEnumerator<int> IEnumerable<int>.GetEnumerator() => GetEnumerator(); | |
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); | |
public struct Enumerator : IEnumerator<int> | |
{ | |
private uint _bits; | |
private int _count; | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public Enumerator(ushort bits) | |
{ | |
_count = CountBits(bits); | |
_bits = bits; | |
} | |
public int Current | |
{ | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
get { | |
int number = GetHighBitNumber((ushort)_bits); | |
_bits ^= 1u << number; | |
return number; | |
} | |
} | |
object IEnumerator.Current => Current; | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public bool MoveNext() | |
{ | |
return _count-- > 0; | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
void IDisposable.Dispose() { } | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
void IEnumerator.Reset() { } | |
} | |
} | |
public struct FindBitsIterator32 : IEnumerable<int> | |
{ | |
private Enumerator _enumerator; | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public FindBitsIterator32(int bits) | |
{ | |
_enumerator = new Enumerator((uint)bits); | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public FindBitsIterator32(uint bits) | |
{ | |
_enumerator = new Enumerator(bits); | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public Enumerator GetEnumerator() | |
{ | |
return _enumerator; | |
} | |
IEnumerator<int> IEnumerable<int>.GetEnumerator() => GetEnumerator(); | |
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); | |
public struct Enumerator : IEnumerator<int> | |
{ | |
private uint _bits; | |
private int _count; | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public Enumerator(uint bits) | |
{ | |
_count = CountBits(bits); | |
_bits = bits; | |
} | |
public int Current | |
{ | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
get | |
{ | |
int number = GetHighBitNumber(_bits); | |
_bits ^= 1u << number; | |
return number; | |
} | |
} | |
object IEnumerator.Current => Current; | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public bool MoveNext() | |
{ | |
return _count-- > 0; | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
void IDisposable.Dispose() { } | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
void IEnumerator.Reset() { } | |
} | |
} | |
public struct FindBitsIterator64 : IEnumerable<int> | |
{ | |
private Enumerator _enumerator; | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public FindBitsIterator64(long bits) | |
{ | |
_enumerator = new Enumerator((ulong)bits); | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public FindBitsIterator64(ulong bits) | |
{ | |
_enumerator = new Enumerator(bits); | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public Enumerator GetEnumerator() | |
{ | |
return _enumerator; | |
} | |
IEnumerator<int> IEnumerable<int>.GetEnumerator() => GetEnumerator(); | |
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); | |
public struct Enumerator : IEnumerator<int> | |
{ | |
private ulong _bits; | |
private int _count; | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public Enumerator(ulong bits) | |
{ | |
_count = CountBits(bits); | |
_bits = bits; | |
} | |
public int Current | |
{ | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
get | |
{ | |
int number = GetHighBitNumber(_bits); | |
_bits ^= 1u << number; | |
return number; | |
} | |
} | |
object IEnumerator.Current => Current; | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public bool MoveNext() | |
{ | |
return _count-- > 0; | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
void IDisposable.Dispose() { } | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
void IEnumerator.Reset() { } | |
} | |
} | |
#endregion | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment