Let's say I have the following
int susan = 2; //0010 int bob = 4; //0100 int karen = 8; //1000
and I pass 10 (8 + 2) as a parameter to a method and I want to decode this to mean susan and karen
I know that 10 is 1010
but how can I do some logic to see if a specific bit is checked as in
if (condition_for_karen) // How to quickly check whether effective karen bit is 1
Right now all i can think of is to check whether the number i passed is
14 // 1110 12 // 1100 10 // 1010 8 // 1000
When I have a larger number of actual bits in my real world scenario, this seems impractical, what is a better way using a mask to just check whether or not I meet the condition for just karen?
I can think of shifting left then back then shifting right then back to clear bits other than the one I'm interested in, but this also seems overly complex.
Bit masking is simply the process of storing data truly as bits, as opposed to storing it as chars/ints/floats. It is incredibly useful for storing certain types of data compactly and efficiently. The idea for bit masking is based on boolean logic.
Bitmasks are used when you want to encode multiple layers of information in a single number. So (assuming unix file permissions) if you want to store 3 levels of access restriction (read, write, execute) you could check for each level by checking the corresponding bit.
In a bit mask, Bitwise AND can be used to make sure particular bits in the result value are set to 0. The trick is to put a 1 in the mask for any bit you do not want changed in the result, and a 0 in the mask for any bit that you want to make sure is a 0 in the result.
Bitmasks are a type of bit manipulation, usually performed using the bitwise AND operator to read or clear a specific number of bits. It can also refer to setting, clearing, and toggling individual bits in a bit field.
The traditional way to do this is to use the Flags
attribute on an enum
:
[Flags] public enum Names { None = 0, Susan = 1, Bob = 2, Karen = 4 }
Then you'd check for a particular name as follows:
Names names = Names.Susan | Names.Bob; // evaluates to true bool susanIsIncluded = (names & Names.Susan) != Names.None; // evaluates to false bool karenIsIncluded = (names & Names.Karen) != Names.None;
Logical bitwise combinations can be tough to remember, so I make life easier on myself with a FlagsHelper
class*:
// The casts to object in the below code are an unfortunate necessity due to // C#'s restriction against a where T : Enum constraint. (There are ways around // this, but they're outside the scope of this simple illustration.) public static class FlagsHelper { public static bool IsSet<T>(T flags, T flag) where T : struct { int flagsValue = (int)(object)flags; int flagValue = (int)(object)flag; return (flagsValue & flagValue) != 0; } public static void Set<T>(ref T flags, T flag) where T : struct { int flagsValue = (int)(object)flags; int flagValue = (int)(object)flag; flags = (T)(object)(flagsValue | flagValue); } public static void Unset<T>(ref T flags, T flag) where T : struct { int flagsValue = (int)(object)flags; int flagValue = (int)(object)flag; flags = (T)(object)(flagsValue & (~flagValue)); } }
This would allow me to rewrite the above code as:
Names names = Names.Susan | Names.Bob; bool susanIsIncluded = FlagsHelper.IsSet(names, Names.Susan); bool karenIsIncluded = FlagsHelper.IsSet(names, Names.Karen);
Note I could also add Karen
to the set by doing this:
FlagsHelper.Set(ref names, Names.Karen);
And I could remove Susan
in a similar way:
FlagsHelper.Unset(ref names, Names.Susan);
*As Porges pointed out, an equivalent of the IsSet
method above already exists in .NET 4.0: Enum.HasFlag
. The Set
and Unset
methods don't appear to have equivalents, though; so I'd still say this class has some merit.
Note: Using enums is just the conventional way of tackling this problem. You can totally translate all of the above code to use ints instead and it'll work just as well.
if ( ( param & karen ) == karen ) { // Do stuff }
The bitwise 'and' will mask out everything except the bit that "represents" Karen. As long as each person is represented by a single bit position, you could check multiple people with a simple:
if ( ( param & karen ) == karen ) { // Do Karen's stuff } if ( ( param & bob ) == bob ) // Do Bob's stuff }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With