I created a little function that returns the elementary values from a flagged enum. By "elementary" I mean the values that are powers of 2, excluding any combined enum values. I was a bit surprised I couldn't find a buit-in method for this in .Net (or I missed it).
Let's take this flagged enum:
[Flags]
public enum WeekDay
{
Monday = 1 << 0,
Tuesday = 1 << 1,
Wednesday = 1 << 2,
Thursday = 1 << 3,
Friday = 1 << 4,
Saturday = 1 << 5,
Sunday = 1 << 6,
WeekendDay = Saturday | Sunday,
BusinessDay = Monday | Tuesday | Wednesday | Thursday | Friday
}
Since the binary representation of its values looks as follows...
1
10
100
1000
10000
100000
1000000
1100000
11111
...I came up with this function to extract the elementary values:
public IEnumerable<TEnum> GetElementaryValues<TEnum>()
where TEnum: Enum
{
return Enum.GetValues(typeof(TEnum))
.Cast<TEnum>()
.Where(v =>
{
var intValue = Convert.ToInt64(v);
var binary = Convert.ToString(intValue, 2);
return !binary.Skip(1).Any(c => c == '1');
});
}
Which basically says: return each value that hasn't got a 1
beyond its first character.
Doest this look OK? Can it be improved? My feeling is that it's a lot of expensive code for such a simple task.
1 Answer 1
The way to test for a power of two, where x is an unsigned integer type is
( x != 0 ) && ( ( x & ( x - 1 ) ) == 0 )
To understand why this works, it's fairly easy to see that if x is a power of two, then x & (x -1 ) is zero.
If x is not a power of two, then only the bits up to the first non-zero bit are changed when you subtract one, and that is not the most significant bit, so the most significant bit is not cleared, and so x & (x - 1 ) is non-zero, as required.
Zero is a special case - it's not a power of two, so an extra test is needed, also ( x - 1 ) overflows if x is zero.
-
\$\begingroup\$ I knew "something" with bits should be possible, but didn't figure out this one. Perfect, thanks! Excluding
0
is in line with flagged enum best practices, so that's OK. \$\endgroup\$Gert Arnold– Gert Arnold2019年03月13日 13:17:47 +00:00Commented Mar 13, 2019 at 13:17