I was programming for 2 years before I ran into these and even then I used them without knowing what they actually did or how they did it. Tutorials on this subject aren’t always useful when thinking about applying bitwise calculations in real situations. This is the first time I’ve used them in my work so I thought a post describing the wonderful things they can do would be a good thing to do. So here we are.
Bitwise Operations for Setting Options
In this example I have a layout class that manages the layout for my GUI components. It aligns them relative to other components or a component’s parent.
The options:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
enum LayoutConstraint { LayoutConstraintNone = 0, // no constraints // alignToParent LayoutConstraintAlignParentTop = 1 << 0, LayoutConstraintAlignParentBottom = 1 << 1, LayoutConstraintAlignParentLeft = 1 << 2, LayoutConstraintAlignParentRight = 1 << 3, LayoutConstraintCenter = 1 << 4, LayoutConstraintHorizontalCenter = 1 << 5, LayoutConstraintVerticalCenter = 1 << 6, // layoutToView LayoutConstraintAbove = 1 << 8, LayoutConstraintBelow = 1 << 9, LayoutConstraintAlignToTopOf = 1 << 10, LayoutConstraintAlignToBottomOf = 1 << 11, LayoutConstraintLeftOf = 1 << 12, LayoutConstraintRightOf = 1 << 13, LayoutConstraintAlignToLeftOf = 1 << 14, LayoutConstraintAlignToRightOf = 1 << 15, // fitToParent LayoutConstraintParentWidth = 1 << 16, LayoutConstraintFillParentX = 1 << 17, LayoutConstraintParentHeight = 1 << 18, LayoutConstraintFillParentY = 1 << 19, LayoutConstraintAlignParentFlags = 0x000FF, LayoutConstraintAlignViewFlags = 0x0FF00, LayoutConstraintAlignViewXFlags = 0x0F000, LayoutConstraintAlignViewYFlags = 0x00F00, LayoutConstraintSizeParentFlags = 0xF0000, LayoutConstraintSizeParentXFlags = 0x30000, LayoutConstraintSizeParentYFlags = 0xC0000 }; |
New syntax: << simply means shift all numbers in a binary left.
For example
1 << 2 shifts 1 by 2 places. So in binary 0 0 1 becomes 1 0 0.
1 2 3 |
Statement Binary Decimal Hexadecimal 1 0 0 1 1 0x1 1 << 2 1 0 0 4 0x4 |
So the first 7 options look like this:
1 2 3 4 5 6 7 8 9 |
Option Statement Binary LayoutConstraintNone 0 0 0 0 0 0 0 0 0 LayoutConstraintAlignParentTop 1 << 0 0 0 0 0 0 0 0 1 LayoutConstraintAlignParentBottom 1 << 1 0 0 0 0 0 0 1 0 LayoutConstraintAlignParentLeft 1 << 2 0 0 0 0 0 1 0 0 LayoutConstraintAlignParentRight 1 << 3 0 0 0 0 1 0 0 0 LayoutConstraintCenter 1 << 4 0 0 0 1 0 0 0 0 LayoutConstraintHorizontalCenter 1 << 5 0 0 1 0 0 0 0 0 LayoutConstraintVerticalCenter 1 << 6 0 1 0 0 0 0 0 0 |
Setting Options
Imagine we have an unsigned integer containing 8 bits (uint8). This will be our ‘flag’. We will use this to store the options. How do you set an option? Use the ‘|’ operator.
‘|’ compares two binary numbers and if each corresponding bit is ‘1’ OR either bit is ‘1’ then it will return ‘1’, otherwise ‘0’ is returned.
So to set an option in our flag:
1 2 3 4 5 6 7 8 9 10 11 |
uint8 flag = 0; // no options are set flag = flag | LayoutConstraintAlignParentTop; // OR in shorthand flag |= LayoutConstraintAlignParentTop; // flag in binary: 0 0 0 0 0 0 0 1 //Add another option: flag |= LayoutConstraintAlignParentLeft; // flag in binary: 0 0 0 0 0 1 0 1 |
Checking an Option
Nice and easy so far. So how do we check if an option is set? The ‘&’ operator compares two binary numbers and if both corresponding bit is ‘1’ it will return ‘1’, otherwise ‘0’ is returned.
Check if the LayoutConstraintAlignParentBottom option is set:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// flag in binary: 0 0 0 0 0 1 0 1 int result = flag & LayoutConstraintAlignParentBottom; if(result > 0) { // check if option is set // IS set } else { // NOT set } // answer // 0 0 0 0 0 1 0 1 // & 0 0 0 0 0 0 1 0 // = 0 0 0 0 0 0 0 0 |
So the option isn’t set. How about LayoutConstraintAlignParentLeft?
1 2 3 4 5 |
int result = flag & LayoutConstraintAlignParentLeft; // 0 0 0 0 0 1 0 1 // & 0 0 0 0 0 1 0 0 // = 0 0 0 0 0 1 0 0 |
Yes, here you can see the option is set.
Removing an option
Removing is a little more tricky. Again we use the ‘&’ operator. Have you noticed when we check an option, it returns ONLY the option we asked for. This sounds like a good start but we want all the options EXCEPT the one we want to remove. The ‘~’ operator switches all the values in a binary.
1 2 |
// ~ 0 1 0 0 0 1 0 1 // = 1 0 1 1 1 0 1 0 |
So if we apply ‘~’ to the option we want to remove we can then compare it with our flag using the ‘&’ operator. This will remove that option from the flag.
1 2 3 4 5 6 7 8 9 |
uint8 switchedOption = ~ LayoutConstraintAlignParentTop; // ~ 0 0 0 0 0 0 0 1 // = 1 1 1 1 1 1 1 0 flag = switchedOption & flag; // 1 1 1 1 1 1 1 0 // & 0 0 0 0 0 1 0 1 // = 0 0 0 0 0 1 0 0 |
Notice how the correct option and only that option was removed. So a quicker way to write this:
1 |
flag & = ~ LayoutConstraintAlignParentTop; |
Multiple Options
Now on to some cool stuff. Sometimes many options need to be checked or set. Hexadecimal numbers are very useful here. Lets look at our group of options again.
When the first four values are set to our flag, it looks like this;
1 |
// flag: 0 0 0 0 1 1 1 1 |
If we want to check for ANY of the first four options we need compare this flag with each option. Here’s where hexadecimal numbers can come in handy. 0 0 0 0 1 1 1 1 == 0xF. So we can group these flags in another option. In the above example all of the alignToParent options are grouped in a single option (LayoutConstraintAlignParentFlags = 0xFF = 1 1 1 1 1 1 1 1).
So lets take a longer flag with 16 bits and see if any of the first 8 options are present.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// flag: 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 // compare int result = flag & LayoutConstraintAlignParentFlags; // 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 // 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 // 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 not this time // add a new option flag |= LayoutConstraintHorizontalCenter; // flag: 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 result = flag & LayoutConstraintAlignParentFlags; // 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 // 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 // 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 success! |
There we are! A few wonderful things you can do with bitwise calculations.
Be First to Comment