using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Text.RegularExpressions; using static DCFApixels.DragonECS.Internal.BitsUtility; namespace DCFApixels.DragonECS.Internal { internal unsafe static class BitsUtility { private const char DEFAULT_SEPARATOR = '_'; private const int BYTE_BITS = 8; #region CountBits public static unsafe int CountBits8(T bits) where T : unmanaged { return CountBits((uint)*(byte*)&bits); } public static unsafe int CountBits16(T bits) where T : unmanaged { return CountBits((uint)*(ushort*)&bits); } public static unsafe int CountBits32(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 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 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 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 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 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 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 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 bits, List numbers) where T : unmanaged { GetBitNumbersNoAlloc(*(uint*)&bits, numbers); } public static unsafe void GetBitNumbersNoAlloc(float bits, List numbers) { GetBitNumbersNoAlloc(*(uint*)&bits, numbers); } public static void GetBitNumbersNoAlloc(int bits, List numbers) { GetBitNumbersNoAlloc((uint)bits, numbers); } public static void GetBitNumbersNoAlloc(uint bits, List 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 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 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 bits, List numbers) where T : unmanaged { GetBitNumbersNoAlloc(*(ulong*)&bits, numbers); } public static unsafe void GetBitNumbersNoAlloc(double bits, List numbers) { GetBitNumbersNoAlloc(*(ulong*)&bits, numbers); } public static void GetBitNumbersNoAlloc(long bits, List numbers) { GetBitNumbersNoAlloc((ulong)bits, numbers); } public static void GetBitNumbersNoAlloc(ulong bits, List 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 value, bool withSeparator) where T : unmanaged { return ToBitsStringInaternal(value, withSeparator ? BYTE_BITS : 0, DEFAULT_SEPARATOR); } public static string ToBitsString(T value, int separateRange) where T : unmanaged { return ToBitsStringInaternal(value, separateRange, DEFAULT_SEPARATOR); } public static string ToBitsString(T value, char separator = DEFAULT_SEPARATOR, int separateRange = BYTE_BITS) where T : unmanaged { return ToBitsStringInaternal(value, separateRange, separator); } private static unsafe string ToBitsStringInaternal(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 ///Fast operation: float result = (float)value / int.MaxValue. ///-1.0f < x < 1.0f [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; } } } ///Fast operation: float result = (float)value / uint.MaxValue. ///0.0f <= x < 1.0f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe float Q32ToFloat(uint value) { unchecked { uint bits = (value >> 9) | 0x3F80_0000; return (*(float*)&bits) - 1f; } } ///Fast operation: double result = (double)value / long.MaxValue. ///-1.0d < x < 1.0d [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; } } } ///Fast operation: double result = (double)value / ulong.MaxValue. ///0.0d <= x < 1.0d [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() where TEnum : unmanaged, Enum { return EnumCache.allFlags; } private static class EnumCache 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 { 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 CreateSpanInternal(FindBitsResult8 a) { return new ReadOnlySpan(a._numbers, a.Count); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ReadOnlySpan 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 IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } public unsafe struct FindBitsResult16 : IEnumerable { 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 CreateSpanInternal(FindBitsResult16 a) { return new ReadOnlySpan(a._numbers, a.Count); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ReadOnlySpan 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 IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } public unsafe struct FindBitsResult32 : IEnumerable { 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 CreateSpanInternal(FindBitsResult32 a) { return new ReadOnlySpan(a._numbers, a.Count); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ReadOnlySpan 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 IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } public unsafe struct FindBitsResult64 : IEnumerable { 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 CreateSpanInternal(FindBitsResult64 a) { return new ReadOnlySpan(a._numbers, a.Count); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ReadOnlySpan 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 IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } public unsafe struct FindBitsResultEnumerator : IEnumerator { 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 { 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 IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public struct Enumerator : IEnumerator { 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 { 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 IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public struct Enumerator : IEnumerator { 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 { 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 IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public struct Enumerator : IEnumerator { 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 { 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 IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public struct Enumerator : IEnumerator { 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 }