Skip to content

Instantly share code, notes, and snippets.

@Wouterdek
Created June 2, 2021 08:55
Show Gist options
  • Save Wouterdek/2c011833b41e498d228a7328605957d2 to your computer and use it in GitHub Desktop.
Save Wouterdek/2c011833b41e498d228a7328605957d2 to your computer and use it in GitHub Desktop.
RefCountedFlags
using System;
/// <summary>
/// Provides a boolean value for each value in an enum,
/// but setting the same flag twice means the flags needs to be unset twice to be false
/// </summary>
/// <typeparam name="T">An enum type (optionally with [Flags]) backed by a 32bit int</typeparam>
public unsafe struct RefCountedFlags<T> where T : Enum //T must be backed by a 32bit int
{
fixed byte counts[32];
public void PushFlags(T val)
{
uint v = (uint)(object)val;
while (v > 0)
{
var idx = FlagToIndex(v);
counts[idx]++;
v &= ~((uint)1 << idx);
}
}
public void PopFlags(T val)
{
uint v = (uint)(object)val;
while (v > 0)
{
var idx = FlagToIndex(v);
counts[idx]--;
v &= ~((uint)1 << idx);
}
}
public bool HasFlag(T val)
{
return counts[FlagToIndex((uint)(object)val)] > 0;
}
private int FlagToIndex(uint v)
{
// Fancy method to find least significant 1 bit
// https://stackoverflow.com/a/757266/915418
// https://web.archive.org/web/20201106232756/http://supertech.csail.mit.edu/papers/debruijn.pdf
int[] MultiplyDeBruijnBitPosition =
{
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};
return MultiplyDeBruijnBitPosition[((uint)((v & -v) * 0x077CB531U)) >> 27];
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment