/ src / Ryujinx.Graphics.Vulkan / BitMapStruct.cs
BitMapStruct.cs
  1  using Ryujinx.Common.Memory;
  2  using System;
  3  using System.Numerics;
  4  
  5  namespace Ryujinx.Graphics.Vulkan
  6  {
  7      interface IBitMapListener
  8      {
  9          void BitMapSignal(int index, int count);
 10      }
 11  
 12      struct BitMapStruct<T> where T : IArray<long>
 13      {
 14          public const int IntSize = 64;
 15  
 16          private const int IntShift = 6;
 17          private const int IntMask = IntSize - 1;
 18  
 19          private T _masks;
 20  
 21          public BitMapStruct()
 22          {
 23              _masks = default;
 24          }
 25  
 26          public bool BecomesUnsetFrom(in BitMapStruct<T> from, ref BitMapStruct<T> into)
 27          {
 28              bool result = false;
 29  
 30              int masks = _masks.Length;
 31              for (int i = 0; i < masks; i++)
 32              {
 33                  long fromMask = from._masks[i];
 34                  long unsetMask = (~fromMask) & (fromMask ^ _masks[i]);
 35                  into._masks[i] = unsetMask;
 36  
 37                  result |= unsetMask != 0;
 38              }
 39  
 40              return result;
 41          }
 42  
 43          public void SetAndSignalUnset<T2>(in BitMapStruct<T> from, ref T2 listener) where T2 : struct, IBitMapListener
 44          {
 45              BitMapStruct<T> result = new();
 46  
 47              if (BecomesUnsetFrom(from, ref result))
 48              {
 49                  // Iterate the set bits in the result, and signal them.
 50  
 51                  int offset = 0;
 52                  int masks = _masks.Length;
 53                  ref T resultMasks = ref result._masks;
 54                  for (int i = 0; i < masks; i++)
 55                  {
 56                      long value = resultMasks[i];
 57                      while (value != 0)
 58                      {
 59                          int bit = BitOperations.TrailingZeroCount((ulong)value);
 60  
 61                          listener.BitMapSignal(offset + bit, 1);
 62  
 63                          value &= ~(1L << bit);
 64                      }
 65  
 66                      offset += IntSize;
 67                  }
 68              }
 69  
 70              _masks = from._masks;
 71          }
 72  
 73          public void SignalSet(Action<int, int> action)
 74          {
 75              // Iterate the set bits in the result, and signal them.
 76  
 77              int offset = 0;
 78              int masks = _masks.Length;
 79              for (int i = 0; i < masks; i++)
 80              {
 81                  long value = _masks[i];
 82                  while (value != 0)
 83                  {
 84                      int bit = BitOperations.TrailingZeroCount((ulong)value);
 85  
 86                      action(offset + bit, 1);
 87  
 88                      value &= ~(1L << bit);
 89                  }
 90  
 91                  offset += IntSize;
 92              }
 93          }
 94  
 95          public bool AnySet()
 96          {
 97              for (int i = 0; i < _masks.Length; i++)
 98              {
 99                  if (_masks[i] != 0)
100                  {
101                      return true;
102                  }
103              }
104  
105              return false;
106          }
107  
108          public bool IsSet(int bit)
109          {
110              int wordIndex = bit >> IntShift;
111              int wordBit = bit & IntMask;
112  
113              long wordMask = 1L << wordBit;
114  
115              return (_masks[wordIndex] & wordMask) != 0;
116          }
117  
118          public bool IsSet(int start, int end)
119          {
120              if (start == end)
121              {
122                  return IsSet(start);
123              }
124  
125              int startIndex = start >> IntShift;
126              int startBit = start & IntMask;
127              long startMask = -1L << startBit;
128  
129              int endIndex = end >> IntShift;
130              int endBit = end & IntMask;
131              long endMask = (long)(ulong.MaxValue >> (IntMask - endBit));
132  
133              if (startIndex == endIndex)
134              {
135                  return (_masks[startIndex] & startMask & endMask) != 0;
136              }
137  
138              if ((_masks[startIndex] & startMask) != 0)
139              {
140                  return true;
141              }
142  
143              for (int i = startIndex + 1; i < endIndex; i++)
144              {
145                  if (_masks[i] != 0)
146                  {
147                      return true;
148                  }
149              }
150  
151              if ((_masks[endIndex] & endMask) != 0)
152              {
153                  return true;
154              }
155  
156              return false;
157          }
158  
159          public bool Set(int bit)
160          {
161              int wordIndex = bit >> IntShift;
162              int wordBit = bit & IntMask;
163  
164              long wordMask = 1L << wordBit;
165  
166              if ((_masks[wordIndex] & wordMask) != 0)
167              {
168                  return false;
169              }
170  
171              _masks[wordIndex] |= wordMask;
172  
173              return true;
174          }
175  
176          public void Set(int bit, bool value)
177          {
178              if (value)
179              {
180                  Set(bit);
181              }
182              else
183              {
184                  Clear(bit);
185              }
186          }
187  
188          public void SetRange(int start, int end)
189          {
190              if (start == end)
191              {
192                  Set(start);
193                  return;
194              }
195  
196              int startIndex = start >> IntShift;
197              int startBit = start & IntMask;
198              long startMask = -1L << startBit;
199  
200              int endIndex = end >> IntShift;
201              int endBit = end & IntMask;
202              long endMask = (long)(ulong.MaxValue >> (IntMask - endBit));
203  
204              if (startIndex == endIndex)
205              {
206                  _masks[startIndex] |= startMask & endMask;
207              }
208              else
209              {
210                  _masks[startIndex] |= startMask;
211  
212                  for (int i = startIndex + 1; i < endIndex; i++)
213                  {
214                      _masks[i] |= -1L;
215                  }
216  
217                  _masks[endIndex] |= endMask;
218              }
219          }
220  
221          public BitMapStruct<T> Union(BitMapStruct<T> other)
222          {
223              var result = new BitMapStruct<T>();
224  
225              ref var masks = ref _masks;
226              ref var otherMasks = ref other._masks;
227              ref var newMasks = ref result._masks;
228  
229              for (int i = 0; i < masks.Length; i++)
230              {
231                  newMasks[i] = masks[i] | otherMasks[i];
232              }
233  
234              return result;
235          }
236  
237          public void Clear(int bit)
238          {
239              int wordIndex = bit >> IntShift;
240              int wordBit = bit & IntMask;
241  
242              long wordMask = 1L << wordBit;
243  
244              _masks[wordIndex] &= ~wordMask;
245          }
246  
247          public void Clear()
248          {
249              for (int i = 0; i < _masks.Length; i++)
250              {
251                  _masks[i] = 0;
252              }
253          }
254  
255          public void ClearInt(int start, int end)
256          {
257              for (int i = start; i <= end; i++)
258              {
259                  _masks[i] = 0;
260              }
261          }
262      }
263  }