Skip to content

Instantly share code, notes, and snippets.

@nilpunch
Last active March 25, 2026 09:40
Show Gist options
  • Select an option

  • Save nilpunch/b217f56ffdb8182fee93f183be6ca0ef to your computer and use it in GitHub Desktop.

Select an option

Save nilpunch/b217f56ffdb8182fee93f183be6ca0ef to your computer and use it in GitHub Desktop.
BitSet iteration
public class BitSet
{
public ulong[] LowBitSet = Array.Empty<ulong>();
public ulong[] HighBitSet = Array.Empty<ulong>();
public void Add(int id)
{
int lowIndex = id >> 6;
int highIndex = id >> 12;
if (highIndex >= HighBitSet.Length)
{
Array.Resize(ref HighBitSet, (highIndex + 1) << 2);
Array.Resize(ref LowBitSet, HighBitSet.Length << 6);
}
ulong lowMask = 1UL << (id & 63);
ulong highMask = 1UL << (lowIndex & 63);
if (LowBitSet[lowIndex] == 0UL)
{
HighBitSet[highIndex] |= highMask;
}
LowBitSet[lowIndex] |= lowMask;
}
public void Remove(int id)
{
int lowIndex = id >> 6;
int highIndex = id >> 12;
if (lowIndex >= LowBitSet.Length)
{
return;
}
ulong lowMask = 1UL << (id & 63);
ulong highMask = 1UL << (lowIndex & 63);
LowBitSet[lowIndex] &= ~lowMask;
if (LowBitSet[lowIndex] == 0UL)
{
HighBitSet[highIndex] &= ~highMask;
}
}
public bool Has(int id)
{
int lowIndex = id >> 6;
if (lowIndex >= LowBitSet.Length)
{
return false;
}
ulong lowMask = 1UL << (id & 63);
return (LowBitSet[lowIndex] & lowMask) != 0UL;
}
}
public struct Query
{
public static readonly byte[] DeBruijn =
{
0, 1, 17, 2, 18, 50, 3, 57, 47, 19, 22, 51, 29, 4, 33, 58,
15, 48, 20, 27, 25, 23, 52, 41, 54, 30, 38, 5, 43, 34, 59, 8,
63, 16, 49, 56, 46, 21, 28, 32, 14, 26, 24, 40, 53, 37, 42, 7,
62, 55, 45, 31, 13, 39, 36, 6, 61, 44, 12, 35, 60, 11, 10, 9,
};
public BitSet Bitset1 { get; }
public BitSet Bitset2 { get; }
public BitSet Bitset3 { get; }
public BitSet Bitset4 { get; }
public delegate void Iterator(int id);
public Query(BitSet bitset1, BitSet bitset2, BitSet bitset3, BitSet bitset4)
{
Bitset1 = bitset1;
Bitset2 = bitset2;
Bitset3 = bitset3;
Bitset4 = bitset4;
}
public void For(Iterator iterator)
{
int minHighBitSetLength =
Math.Min(Bitset1.HighBitSet.Length,
Math.Min(Bitset2.HighBitSet.Length,
Math.Min(Bitset3.HighBitSet.Length, Bitset4.HighBitSet.Length)));
byte[] deBruijn = DeBruijn;
for (var highIndex = 0; highIndex < minHighBitSetLength; highIndex++)
{
ulong highMask = Bitset1.HighBitSet[highIndex]
& Bitset2.HighBitSet[highIndex]
& Bitset3.HighBitSet[highIndex]
& Bitset4.HighBitSet[highIndex];
int lowOffset = highIndex << 6;
while (highMask != 0)
{
ulong highBit = highMask & (ulong) -(long) highMask;
byte highBitIndex = deBruijn[(uint) ((highBit * 0x37E84A99DAE458FUL) >> 58)];
int lowIndex = lowOffset + highBitIndex;
do
{
ulong lowMask = Bitset1.LowBitSet[lowIndex]
& Bitset2.LowBitSet[lowIndex]
& Bitset3.LowBitSet[lowIndex]
& Bitset4.LowBitSet[lowIndex];
int idOffset = lowIndex << 6;
do
{
ulong lowBit = lowMask & (ulong) -(long) lowMask;
byte lowBitIndex = deBruijn[(uint) ((lowBit * 0x37E84A99DAE458FUL) >> 58)];
int id = idOffset + lowBitIndex;
do
{
iterator.Invoke(id);
lowBit <<= 1;
id++;
} while ((lowMask & lowBit) != 0);
lowMask &= ~(lowBit - 1);
} while (lowMask != 0);
highBit <<= 1;
lowIndex++;
} while ((highMask & highBit) != 0);
highMask &= ~(highBit - 1);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment