explorers' club

explorations in dev, science, sci-fi, games, and other fun stuff!

using bitflags and bitwise math

1 Comment

[update 2014.07.08]

I’ve written a javascript NPM module for performing these operations – bitflag-utils

[note to self]

given the following:

const FLAG_A:uint = 1 << 0; // dec = 1, bit = 0001
const FLAG_B:uint = 1 << 1; // dec = 2, bit = 0010 
const FLAG_C:uint = 1 << 2; // dec = 4, bit = 0100
const FLAG_D:uint = 1 << 3; // dec = 8, bit = 1000 

var flags:uint;

so if flags = 0, then we have no flags set, however if flags >= 1 then we have some flags assigned.  This makes it quite easy to check by simply saying:

flags = 0;
trace( Boolean( flags )); // false

flags = FLAG_A | FLAG_C; //dec = 5, bit = 0101
trace( Boolean( flags )); // true

adding flags w/ bitwise OR

let’s do some adding of some values to our flags:

flags = 0;
flags = FLAG_A | FLAG_C | FLAG_D; //dec = 13, bit = 1101

this basically says in decimal type notation:

flags = FLAG_A + FLAG_C + FLAG_D;

And indeed you could use regular decimal operators and come to the same value, but where decimal operations fail is in being able to continually assign a flag of the same value multiple times as in this case:

//initialize the flags
var bitflag:uint = FLAG_A | FLAG_C | FLAG_D; //dec = 13, bit = 1101
var decflag:uint =  FLAG_A + FLAG_C + FLAG_D; //dec = 13, bit = 1101

Let’s assume that logic elsewhere isn’t aware of the initial value and decides to add an additional flag, in this case, one that was previously assigned.  Think of the invalidation mechanisms, setting one prop might call invalidateProps, and then subsequent props settings also calls invalidateProps… sorta analogous right?

bitflag = bitflag | FLAG_A; //dec = 13, bit = 1101

Note that the flag remains the same value.  This is due to the fact that the bitwise OR does not carry over like traditional addition.  In fact this could be viewed more along the lines of a logic operation for each radix.  Now let’s see if the same holds true for traditional decimal operations:

decflag = decflag + FLAG_A; //dec = 14, bit = 1110

Not only did the decimal operation fail us, it also set another flag for us unintentionally.  Note that 1110 is the same as:

FLAG_B | FLAG_C | FLAG_D; //dec = 14, bit = 1110

Ok so we’ve seen how the bitmath operations allow us to add flags without having to worry about the whole carry over issue.

Now let’s look at the Bitwise OR operation in more depth.  In logic, if A OR B then TRUE (forgive me, I have since forgotten the proper syntax for logic statements).  In the case of bitmath, for a given radix, if either one of them is a value of 1, then the radix for the output is 1.  The only time the radix to the output is 0 is if both values for that radix are zero.  A picture is worth a 1000 words so:

       0001 - FLAG_A
  (or) 0010 - FLAG_B
------------
       0011 - flags

let’s now show that adding FLAG_B again does nothing to the output:

       0011 - flags
  (or) 0010 - FLAG_B
------------
       0011 - flags

let’s try a more complex example:

       0001 - FLAG_A
  (or) 0010 - FLAG_B
  (or) 1000 - FLAG_D
------------
       1011 - flags

next up is what I’d call a HAS FLAG operation

check for a flag w/ bitwise AND

Bitwise OR operations are great for setting flags, but it doesn’t get you very far when you need to check your flags for a particular value.  Just like the OR operation, the AND operation is a logic operation.  If A AND B then TRUE, or in other words, for a given radix, if both values in a given radix are 1 then the output for that radix is 1, else it’s 0.  Another look at this is:

       0001
 (and) 0001
------------
       0001 - both were 1 so output to 1
       0001
 (and) 0000
------------
       0000 - the logical AND statement fails, thus 0 is returned

One thing to note is that the AND statement only evaluates for the 1s in the binary values (or at least how I understand it to operate).

So let’s apply this to our flags to see how we might be able to determine if a value is present in our flags var.  Let’s assume our flags have already been set to:

flags = FLAG_A | FLAG_D; //dec = 9, bit = 1001

Now we’re going to check to see if FLAG_C has been set.

var hasFlagC:Boolean = FLAG_C == ( flags & FLAG_C );

Let’s first examine the statement in the parenthesis:

flags & FLAG_C;
       1001 - flags
 (and) 0100 - FLAG_C
------------
       0000 - output

And then we evaluate the output against the flag we’re checking for:

0000 == 0100 = FALSE
or
output != FLAG_C

Ergo FLAG_C was not set.  So let’s try another test that we know should return true:

flags = FLAG_A | FLAG_D; //dec = 9, bit = 1001 (from before)
var hasFlagD:Boolean = FLAG_D == ( flags & FLAG_D );

Evaluate the parenthesis first:

flags & FLAG_D;
       1001 - flags
 (and) 1000 - FLAG_D
------------
       1000 - output

output == FLAG_D

Lastly there is the need to remove a flag

removing a flag w/ bitwise AND plus bitwise NOT

Obviously this post wouldn’t be complete without showing you how to remove a flag from a given bitflag.  This entails two types of bitwise operations.  One you are already familiar with: the bitwise AND.  The other is the bitwise NOT statement.  Like the above 2 logical operations the concept of the bitwise NOT is to return an inverse of the input:

1001 - input
NOT of input
0110

The common syntax is:

~input

So now we need to combine the AND and NOT operations to remove a flag.  Let’s dive in shall we?

       0000 - flags (starting fresh)
 (and) 0001 - FLAG_A
------------
       0001 - flags
 (and) 0010 - FLAG_B
------------
       0011 - flags

We’ve just added a few flags to our value.  Now let’s remove them and try to arrive at our initial state of 0.

       0011 - flags
 (and) 1110 - ~FLAG_A
------------
       0010 - flags (see how the AND statement preserve FLAG_B?, now let's remove B)
 (and) 1101 - ~FLAG_B
------------
       0000 - flags (back to default state of no flags set)

Now I will show you that whole process in actionscript:

const FLAG_A:uint = 1 << 0; // dec = 1, bit = 0001
const FLAG_B:uint = 1 << 1; // dec = 2, bit = 0010 
const FLAG_C:uint = 1 << 2; // dec = 4, bit = 0100
const FLAG_D:uint = 1 << 3; // dec = 8, bit = 1000 

var flags:uint;
//adding A, you can also say flags |= FLAG_A; 
flags = flags | FLAG_A;

//add flag b, this time using the shorthand
flags |= FLAG_B;

//now to remove A
flags = flags & ~FLAG_A;

//remove B using shorthand
flags &= ~FLAG_B;

trace(flags.toString()); // 0

and the surprise is…

Adobe made a nifty little utility class just for these types of operations.  Check it out:

mx.utils.BitFlagUtil;

It’s an excluded class so you will need to import & instantiate manually, THEN code hints will appear.  Here is the documentation for it:

link

One thought on “using bitflags and bitwise math

  1. Pingback: JS: bitflag-utils | explorers' club

Leave a comment