namespace Ryujinx.Common.Collections { /// /// Represents a collection that can store 1 bit values. /// public struct BitMap { /// /// Size in bits of the integer used internally for the groups of bits. /// public const int IntSize = 64; private const int IntShift = 6; private const int IntMask = IntSize - 1; private readonly long[] _masks; /// /// Gets or sets the value of a bit. /// /// Bit to access /// Bit value public bool this[int bit] { get => IsSet(bit); set { if (value) { Set(bit); } else { Clear(bit); } } } /// /// Creates a new bitmap. /// /// Total number of bits public BitMap(int count) { _masks = new long[(count + IntMask) / IntSize]; } /// /// Checks if any bit is set. /// /// True if any bit is set, false otherwise public bool AnySet() { for (int i = 0; i < _masks.Length; i++) { if (_masks[i] != 0) { return true; } } return false; } /// /// Checks if a specific bit is set. /// /// Bit to be checked /// True if set, false otherwise public bool IsSet(int bit) { int wordIndex = bit >> IntShift; int wordBit = bit & IntMask; long wordMask = 1L << wordBit; return (_masks[wordIndex] & wordMask) != 0; } /// /// Checks if any bit inside a given range of bits is set. /// /// Start bit of the range /// End bit of the range (inclusive) /// True if any bit is set, false otherwise public bool IsSet(int start, int end) { if (start == end) { return IsSet(start); } int startIndex = start >> IntShift; int startBit = start & IntMask; long startMask = -1L << startBit; int endIndex = end >> IntShift; int endBit = end & IntMask; long endMask = (long)(ulong.MaxValue >> (IntMask - endBit)); if (startIndex == endIndex) { return (_masks[startIndex] & startMask & endMask) != 0; } if ((_masks[startIndex] & startMask) != 0) { return true; } for (int i = startIndex + 1; i < endIndex; i++) { if (_masks[i] != 0) { return true; } } if ((_masks[endIndex] & endMask) != 0) { return true; } return false; } /// /// Sets the value of a bit to 1. /// /// Bit to be set /// True if the bit was 0 and then changed to 1, false if it was already 1 public bool Set(int bit) { int wordIndex = bit >> IntShift; int wordBit = bit & IntMask; long wordMask = 1L << wordBit; if ((_masks[wordIndex] & wordMask) != 0) { return false; } _masks[wordIndex] |= wordMask; return true; } /// /// Sets a given range of bits to 1. /// /// Start bit of the range /// End bit of the range (inclusive) public void SetRange(int start, int end) { if (start == end) { Set(start); return; } int startIndex = start >> IntShift; int startBit = start & IntMask; long startMask = -1L << startBit; int endIndex = end >> IntShift; int endBit = end & IntMask; long endMask = (long)(ulong.MaxValue >> (IntMask - endBit)); if (startIndex == endIndex) { _masks[startIndex] |= startMask & endMask; } else { _masks[startIndex] |= startMask; for (int i = startIndex + 1; i < endIndex; i++) { _masks[i] |= -1; } _masks[endIndex] |= endMask; } } /// /// Sets a given bit to 0. /// /// Bit to be cleared public void Clear(int bit) { int wordIndex = bit >> IntShift; int wordBit = bit & IntMask; long wordMask = 1L << wordBit; _masks[wordIndex] &= ~wordMask; } /// /// Sets all bits to 0. /// public void Clear() { for (int i = 0; i < _masks.Length; i++) { _masks[i] = 0; } } /// /// Sets one or more groups of bits to 0. /// See for how many bits are inside each group. /// /// Start index of the group /// End index of the group (inclusive) public void ClearInt(int start, int end) { for (int i = start; i <= end; i++) { _masks[i] = 0; } } } }