Created
June 2, 2021 08:55
-
-
Save Wouterdek/2c011833b41e498d228a7328605957d2 to your computer and use it in GitHub Desktop.
RefCountedFlags
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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