/ src / Ryujinx.Memory / Tracking / BitMap.cs
BitMap.cs
  1  using System.Runtime.CompilerServices;
  2  
  3  namespace Ryujinx.Memory.Tracking
  4  {
  5      /// <summary>
  6      /// A bitmap that can check or set large ranges of true/false values at once.
  7      /// </summary>
  8      readonly struct BitMap
  9      {
 10          public const int IntSize = 64;
 11  
 12          private const int IntShift = 6;
 13          private const int IntMask = IntSize - 1;
 14  
 15          /// <summary>
 16          /// Masks representing the bitmap. Least significant bit first, 64-bits per mask.
 17          /// </summary>
 18          public readonly long[] Masks;
 19  
 20          /// <summary>
 21          /// Create a new bitmap.
 22          /// </summary>
 23          /// <param name="count">The number of bits to reserve</param>
 24          public BitMap(int count)
 25          {
 26              Masks = new long[(count + IntMask) / IntSize];
 27          }
 28  
 29          /// <summary>
 30          /// Check if any bit in the bitmap is set.
 31          /// </summary>
 32          /// <returns>True if any bits are set, false otherwise</returns>
 33          public bool AnySet()
 34          {
 35              for (int i = 0; i < Masks.Length; i++)
 36              {
 37                  if (Masks[i] != 0)
 38                  {
 39                      return true;
 40                  }
 41              }
 42  
 43              return false;
 44          }
 45  
 46          /// <summary>
 47          /// Check if a bit in the bitmap is set.
 48          /// </summary>
 49          /// <param name="bit">The bit index to check</param>
 50          /// <returns>True if the bit is set, false otherwise</returns>
 51          [MethodImpl(MethodImplOptions.AggressiveInlining)]
 52          public bool IsSet(int bit)
 53          {
 54              int wordIndex = bit >> IntShift;
 55              int wordBit = bit & IntMask;
 56  
 57              long wordMask = 1L << wordBit;
 58  
 59              return (Masks[wordIndex] & wordMask) != 0;
 60          }
 61  
 62          /// <summary>
 63          /// Check if any bit in a range of bits in the bitmap are set. (inclusive)
 64          /// </summary>
 65          /// <param name="start">The first bit index to check</param>
 66          /// <param name="end">The last bit index to check</param>
 67          /// <returns>True if a bit is set, false otherwise</returns>
 68          public bool IsSet(int start, int end)
 69          {
 70              if (start == end)
 71              {
 72                  return IsSet(start);
 73              }
 74  
 75              int startIndex = start >> IntShift;
 76              int startBit = start & IntMask;
 77              long startMask = -1L << startBit;
 78  
 79              int endIndex = end >> IntShift;
 80              int endBit = end & IntMask;
 81              long endMask = (long)(ulong.MaxValue >> (IntMask - endBit));
 82  
 83              if (startIndex == endIndex)
 84              {
 85                  return (Masks[startIndex] & startMask & endMask) != 0;
 86              }
 87  
 88              if ((Masks[startIndex] & startMask) != 0)
 89              {
 90                  return true;
 91              }
 92  
 93              for (int i = startIndex + 1; i < endIndex; i++)
 94              {
 95                  if (Masks[i] != 0)
 96                  {
 97                      return true;
 98                  }
 99              }
100  
101              if ((Masks[endIndex] & endMask) != 0)
102              {
103                  return true;
104              }
105  
106              return false;
107          }
108  
109          /// <summary>
110          /// Set a bit at a specific index to 1.
111          /// </summary>
112          /// <param name="bit">The bit index to set</param>
113          /// <returns>True if the bit is set, false if it was already set</returns>
114          public bool Set(int bit)
115          {
116              int wordIndex = bit >> IntShift;
117              int wordBit = bit & IntMask;
118  
119              long wordMask = 1L << wordBit;
120  
121              if ((Masks[wordIndex] & wordMask) != 0)
122              {
123                  return false;
124              }
125  
126              Masks[wordIndex] |= wordMask;
127  
128              return true;
129          }
130  
131          /// <summary>
132          /// Set a range of bits in the bitmap to 1.
133          /// </summary>
134          /// <param name="start">The first bit index to set</param>
135          /// <param name="end">The last bit index to set</param>
136          public void SetRange(int start, int end)
137          {
138              if (start == end)
139              {
140                  Set(start);
141                  return;
142              }
143  
144              int startIndex = start >> IntShift;
145              int startBit = start & IntMask;
146              long startMask = -1L << startBit;
147  
148              int endIndex = end >> IntShift;
149              int endBit = end & IntMask;
150              long endMask = (long)(ulong.MaxValue >> (IntMask - endBit));
151  
152              if (startIndex == endIndex)
153              {
154                  Masks[startIndex] |= startMask & endMask;
155              }
156              else
157              {
158                  Masks[startIndex] |= startMask;
159  
160                  for (int i = startIndex + 1; i < endIndex; i++)
161                  {
162                      Masks[i] |= -1;
163                  }
164  
165                  Masks[endIndex] |= endMask;
166              }
167          }
168  
169          /// <summary>
170          /// Clear a bit at a specific index to 0.
171          /// </summary>
172          /// <param name="bit">The bit index to clear</param>
173          /// <returns>True if the bit was set, false if it was not</returns>
174          public bool Clear(int bit)
175          {
176              int wordIndex = bit >> IntShift;
177              int wordBit = bit & IntMask;
178  
179              long wordMask = 1L << wordBit;
180  
181              bool wasSet = (Masks[wordIndex] & wordMask) != 0;
182  
183              Masks[wordIndex] &= ~wordMask;
184  
185              return wasSet;
186          }
187  
188          /// <summary>
189          /// Clear the bitmap entirely, setting all bits to 0.
190          /// </summary>
191          public void Clear()
192          {
193              for (int i = 0; i < Masks.Length; i++)
194              {
195                  Masks[i] = 0;
196              }
197          }
198      }
199  }