forked from jasder/antlr
Updated BitSet implementation
This commit is contained in:
parent
4bee942e2f
commit
efa20b3fd2
|
@ -4,9 +4,10 @@
|
||||||
|
|
||||||
public class BitSet
|
public class BitSet
|
||||||
{
|
{
|
||||||
private static readonly uint[] EmptyBits = new uint[0];
|
private static readonly ulong[] EmptyBits = new ulong[0];
|
||||||
|
private const int BitsPerElement = 8 * sizeof(ulong);
|
||||||
|
|
||||||
private uint[] data = EmptyBits;
|
private ulong[] _data = EmptyBits;
|
||||||
|
|
||||||
public BitSet()
|
public BitSet()
|
||||||
{
|
{
|
||||||
|
@ -19,15 +20,93 @@
|
||||||
|
|
||||||
if (nbits > 0)
|
if (nbits > 0)
|
||||||
{
|
{
|
||||||
int length = (nbits + (8 * sizeof(uint)) - 1) / (8 * sizeof(uint));
|
int length = (nbits + BitsPerElement - 1) / BitsPerElement;
|
||||||
data = new uint[length];
|
_data = new ulong[length];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int GetBitCount(ulong[] value)
|
||||||
|
{
|
||||||
|
int data = 0;
|
||||||
|
uint size = (uint)value.Length / (sizeof(ulong) / sizeof(int));
|
||||||
|
const ulong m1 = 0x5555555555555555;
|
||||||
|
const ulong m2 = 0x3333333333333333;
|
||||||
|
const ulong m4 = 0x0F0F0F0F0F0F0F0F;
|
||||||
|
const ulong m8 = 0x00FF00FF00FF00FF;
|
||||||
|
const ulong m16 = 0x0000FFFF0000FFFF;
|
||||||
|
const ulong h01 = 0x0101010101010101;
|
||||||
|
|
||||||
|
uint bitCount = 0;
|
||||||
|
uint limit30 = size - size % 30;
|
||||||
|
|
||||||
|
// 64-bit tree merging (merging3)
|
||||||
|
for (uint i = 0; i < limit30; i += 30, data += 30)
|
||||||
|
{
|
||||||
|
ulong acc = 0;
|
||||||
|
for (uint j = 0; j < 30; j += 3)
|
||||||
|
{
|
||||||
|
ulong count1 = value[data + j];
|
||||||
|
ulong count2 = value[data + j + 1];
|
||||||
|
ulong half1 = value[data + j + 2];
|
||||||
|
ulong half2 = half1;
|
||||||
|
half1 &= m1;
|
||||||
|
half2 = (half2 >> 1) & m1;
|
||||||
|
count1 -= (count1 >> 1) & m1;
|
||||||
|
count2 -= (count2 >> 1) & m1;
|
||||||
|
count1 += half1;
|
||||||
|
count2 += half2;
|
||||||
|
count1 = (count1 & m2) + ((count1 >> 2) & m2);
|
||||||
|
count1 += (count2 & m2) + ((count2 >> 2) & m2);
|
||||||
|
acc += (count1 & m4) + ((count1 >> 4) & m4);
|
||||||
|
}
|
||||||
|
|
||||||
|
acc = (acc & m8) + ((acc >> 8) & m8);
|
||||||
|
acc = (acc + (acc >> 16)) & m16;
|
||||||
|
acc = acc + (acc >> 32);
|
||||||
|
bitCount += (uint)acc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// count the bits of the remaining bytes (MAX 29*8) using
|
||||||
|
// "Counting bits set, in parallel" from the "Bit Twiddling Hacks",
|
||||||
|
// the code uses wikipedia's 64-bit popcount_3() implementation:
|
||||||
|
// http://en.wikipedia.org/wiki/Hamming_weight#Efficient_implementation
|
||||||
|
for (uint i = 0; i < size - limit30; i++)
|
||||||
|
{
|
||||||
|
ulong x = value[data + i];
|
||||||
|
x = x - ((x >> 1) & m1);
|
||||||
|
x = (x & m2) + ((x >> 2) & m2);
|
||||||
|
x = (x + (x >> 4)) & m4;
|
||||||
|
bitCount += (uint)((x * h01) >> 56);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int)bitCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly int[] index64 =
|
||||||
|
{
|
||||||
|
0, 47, 1, 56, 48, 27, 2, 60,
|
||||||
|
57, 49, 41, 37, 28, 16, 3, 61,
|
||||||
|
54, 58, 35, 52, 50, 42, 21, 44,
|
||||||
|
38, 32, 29, 23, 17, 11, 4, 62,
|
||||||
|
46, 55, 26, 59, 40, 36, 15, 53,
|
||||||
|
34, 51, 20, 43, 31, 22, 10, 45,
|
||||||
|
25, 39, 14, 33, 19, 30, 9, 24,
|
||||||
|
13, 18, 8, 12, 7, 6, 5, 63
|
||||||
|
};
|
||||||
|
|
||||||
|
private static int BitScanForward(ulong value)
|
||||||
|
{
|
||||||
|
if (value == 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
const ulong debruijn64 = 0x03f79d71b4cb0a89;
|
||||||
|
return index64[((value ^ (value - 1)) * debruijn64) >> 58];
|
||||||
|
}
|
||||||
|
|
||||||
public BitSet Clone()
|
public BitSet Clone()
|
||||||
{
|
{
|
||||||
BitSet result = new BitSet();
|
BitSet result = new BitSet();
|
||||||
result.data = (uint[])data.Clone();
|
result._data = (ulong[])_data.Clone();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,11 +115,11 @@
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
throw new ArgumentOutOfRangeException("index");
|
throw new ArgumentOutOfRangeException("index");
|
||||||
|
|
||||||
int element = index / (8 * sizeof(uint));
|
int element = index / BitsPerElement;
|
||||||
if (element >= data.Length)
|
if (element >= _data.Length)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return (data[element] & (1U << (index % (8 * sizeof(uint))))) != 0;
|
return (_data[element] & (1U << (index % BitsPerElement))) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Set(int index)
|
public void Set(int index)
|
||||||
|
@ -48,11 +127,125 @@
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
throw new ArgumentOutOfRangeException("index");
|
throw new ArgumentOutOfRangeException("index");
|
||||||
|
|
||||||
int element = index / (8 * sizeof(uint));
|
int element = index / BitsPerElement;
|
||||||
if (element >= data.Length)
|
if (element >= _data.Length)
|
||||||
Array.Resize(ref data, Math.Max(data.Length * 2, element + 1));
|
Array.Resize(ref _data, Math.Max(_data.Length * 2, element + 1));
|
||||||
|
|
||||||
data[element] |= 1U << (index % (8 * sizeof(uint)));
|
_data[element] |= 1U << (index % BitsPerElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsEmpty()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _data.Length; i++)
|
||||||
|
{
|
||||||
|
if (_data[i] != 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Cardinality()
|
||||||
|
{
|
||||||
|
return GetBitCount(_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int NextSetBit(int fromIndex)
|
||||||
|
{
|
||||||
|
if (fromIndex < 0)
|
||||||
|
throw new ArgumentOutOfRangeException("fromIndex");
|
||||||
|
|
||||||
|
if (IsEmpty())
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int i = fromIndex / BitsPerElement;
|
||||||
|
if (i >= _data.Length)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
ulong current = _data[i] & ((1U << (fromIndex % BitsPerElement)) - 1);
|
||||||
|
|
||||||
|
for (; i < _data.Length; i++)
|
||||||
|
{
|
||||||
|
int bit = BitScanForward(current);
|
||||||
|
if (bit >= 0)
|
||||||
|
return bit + i * BitsPerElement;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
current = _data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void And(BitSet set)
|
||||||
|
{
|
||||||
|
if (set == null)
|
||||||
|
throw new ArgumentNullException("set");
|
||||||
|
|
||||||
|
int length = Math.Min(_data.Length, set._data.Length);
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
_data[i] &= set._data[i];
|
||||||
|
|
||||||
|
for (int i = length; i < _data.Length; i++)
|
||||||
|
_data[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Or(BitSet set)
|
||||||
|
{
|
||||||
|
if (set == null)
|
||||||
|
throw new ArgumentNullException("set");
|
||||||
|
|
||||||
|
if (set._data.Length > _data.Length)
|
||||||
|
Array.Resize(ref _data, set._data.Length);
|
||||||
|
|
||||||
|
for (int i = 0; i < set._data.Length; i++)
|
||||||
|
_data[i] |= set._data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
BitSet other = obj as BitSet;
|
||||||
|
if (other == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (IsEmpty())
|
||||||
|
return other.IsEmpty();
|
||||||
|
|
||||||
|
int minLength = Math.Min(_data.Length, other._data.Length);
|
||||||
|
for (int i = 0; i < minLength; i++)
|
||||||
|
{
|
||||||
|
if (_data[i] != other._data[i])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = minLength; i < _data.Length; i++)
|
||||||
|
{
|
||||||
|
if (_data[i] != 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = minLength; i < other._data.Length; i++)
|
||||||
|
{
|
||||||
|
if (other._data[i] != 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
ulong result = 1;
|
||||||
|
for (uint i = 0; i < _data.Length; i++)
|
||||||
|
{
|
||||||
|
if (_data[i] != 0)
|
||||||
|
{
|
||||||
|
result = result * 31 ^ i;
|
||||||
|
result = result * 31 ^ _data[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.GetHashCode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue