Ryujinx/ARMeilleure/Common/BitMap.cs
LDj3SNuD dc0adb533d
PPTC & Pool Enhancements. (#1968)
* PPTC & Pool Enhancements.

* Avoid buffer allocations in CodeGenContext.GetCode(). Avoid stream allocations in PTC.PtcInfo.

Refactoring/nits.

* Use XXHash128, for Ptc.Load & Ptc.Save, x10 faster than Md5.

* Why not a nice Span.

* Added a simple PtcFormatter library for deserialization/serialization, which does not require reflection, in use at PtcJumpTable and PtcProfiler; improves maintainability and simplicity/readability of affected code.

* Nits.

* Revert #1987.

* Revert "Revert #1987."

This reverts commit 998be765cf.
2021-02-22 03:23:48 +01:00

207 lines
4.7 KiB
C#

using System.Collections;
using System.Collections.Generic;
using System.Numerics;
namespace ARMeilleure.Common
{
class BitMap : IEnumerator<int>, IEnumerable<int>
{
private const int IntSize = 64;
private const int IntMask = IntSize - 1;
private readonly List<long> _masks;
private int _enumIndex;
private long _enumMask;
private int _enumBit;
public int Current => _enumIndex * IntSize + _enumBit;
object IEnumerator.Current => Current;
public BitMap()
{
_masks = new List<long>(0);
}
public BitMap(int initialCapacity)
{
int count = (initialCapacity + IntMask) / IntSize;
_masks = new List<long>(count);
while (count-- > 0)
{
_masks.Add(0);
}
}
public BitMap Reset(int initialCapacity)
{
int count = (initialCapacity + IntMask) / IntSize;
if (count > _masks.Capacity)
{
_masks.Capacity = count;
}
_masks.Clear();
while (count-- > 0)
{
_masks.Add(0);
}
return this;
}
public bool Set(int bit)
{
EnsureCapacity(bit + 1);
int wordIndex = bit / IntSize;
int wordBit = bit & IntMask;
long wordMask = 1L << wordBit;
if ((_masks[wordIndex] & wordMask) != 0)
{
return false;
}
_masks[wordIndex] |= wordMask;
return true;
}
public void Clear(int bit)
{
EnsureCapacity(bit + 1);
int wordIndex = bit / IntSize;
int wordBit = bit & IntMask;
long wordMask = 1L << wordBit;
_masks[wordIndex] &= ~wordMask;
}
public bool IsSet(int bit)
{
EnsureCapacity(bit + 1);
int wordIndex = bit / IntSize;
int wordBit = bit & IntMask;
return (_masks[wordIndex] & (1L << wordBit)) != 0;
}
public int FindFirstUnset()
{
for (int index = 0; index < _masks.Count; index++)
{
long mask = _masks[index];
if (mask != -1L)
{
return BitOperations.TrailingZeroCount(~mask) + index * IntSize;
}
}
return _masks.Count * IntSize;
}
public bool Set(BitMap map)
{
EnsureCapacity(map._masks.Count * IntSize);
bool modified = false;
for (int index = 0; index < _masks.Count; index++)
{
long newValue = _masks[index] | map._masks[index];
if (_masks[index] != newValue)
{
_masks[index] = newValue;
modified = true;
}
}
return modified;
}
public bool Clear(BitMap map)
{
EnsureCapacity(map._masks.Count * IntSize);
bool modified = false;
for (int index = 0; index < _masks.Count; index++)
{
long newValue = _masks[index] & ~map._masks[index];
if (_masks[index] != newValue)
{
_masks[index] = newValue;
modified = true;
}
}
return modified;
}
#region IEnumerable<long> Methods
// Note: The bit enumerator is embedded in this class to avoid creating garbage when enumerating.
private void EnsureCapacity(int size)
{
while (_masks.Count * IntSize < size)
{
_masks.Add(0);
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerator<int> GetEnumerator()
{
Reset();
return this;
}
public bool MoveNext()
{
if (_enumMask != 0)
{
_enumMask &= ~(1L << _enumBit);
}
while (_enumMask == 0)
{
if (++_enumIndex >= _masks.Count)
{
return false;
}
_enumMask = _masks[_enumIndex];
}
_enumBit = BitOperations.TrailingZeroCount(_enumMask);
return true;
}
public void Reset()
{
_enumIndex = -1;
_enumMask = 0;
_enumBit = 0;
}
public void Dispose() { }
#endregion
}
}