Bitmasks
Bitmasks, and the bitwise operators, are something I've known about/can recognise, but had never actually needed to use them. The first time was when using Windows C++ APIs, and I tripped up over myself a few times trying to use it... So, here's what I wish I read at the start.
tldr
- Add flags using OR
|:flags |= BORDER_LEFTflags |= BORDER_LEFT | BORDER_RIGHT
- Remove flags using AND
&and NOT~:flags &= ~BORDER_LEFTflags &= ~(BORDER_LEFT | BORDER_RIGHT)
- Toggle flags using XOR
^:flags ^= BORDER_LEFTflags ^= BORDER_LEFT | BORDER_RIGHT
- Check any flags using AND
&:flags & BORDER_LEFTflags & (BORDER_LEFT | BORDER_RIGHT)- e.g.
if (flags & BORDER_LEFT) { ... }if (flags & (BORDER_LEFT | BORDER_RIGHT) != 0) { ... }
- the result of the AND is the same as the flag if it's present, or 0 if it's not
- Check all flags using AND
&and equality==:flags & BORDER_LEFT == BORDER_LEFTflags & (BORDER_LEFT | BORDER_RIGHT) == (BORDER_LEFT | BORDER_RIGHT)- e.g.
toCheck = BORDER_LEFT | BORDER_RIGHTif (flags & toCheck == toCheck) { ... }
Flags
You'll often see bitmasks used for "flags", for example:
BORDER_LEFT = 0b0001 // 0b is the prefix for a binary number
BORDER_RIGHT = 0b0010
BORDER_TOP = 0b0100
BORDER_BOTTOM = 0b1000
OR |
The | operator sets a bit to 1 if either of the bits in that position are 1. We can use this to combine flags together:
BORDER_VERTICAL = BORDER_TOP | BORDER_BOTTOM
// 0100
// | 1000
// = 1100
BORDER_HORIZONTAL = BORDER_LEFT | BORDER_RIGHT
// 0001
// | 0010
// = 0011
BORDER_ALL = BORDER_VERTICAL | BORDER_HORIZONTAL
// 1100
// | 0011
// = 1111
myBorders = BORDER_HORIZONTAL | BORDER_BOTTOM
// 0011
// | 1000
// = 1011
AND &
The & operator sets a bit to 1 if both of the bits in that position are 1. We can use this to check a flag:
myBorders = BORDER_TOP | BORDER_HORIZONTAL
// 0111
hasTopBorder = myBorders & BORDER_TOP
// 0111
// & 0100
// = 0100
hasBottomBorder = myBorders & BORDER_BOTTOM
// 0111
// & 1000
// = 0000
NOT ~
The ~ operator inverts the bits in a number. Anything which was 0 is now 1, and anything which was 1 is now 0.
BORDER_BOTTOM
// 1000
~BORDER_BOTTOM
// 0111
~~BORDER_BOTTOM
// 1000
We can use this, alongside the & operator to remove a flag:
flags = BORDER_TOP | BORDER_LEFT | BORDER_RIGHT
// 0111
flagsToRemove = BORDER_TOP
// 0100
flags &= ~flagsToRemove
// 0111
// & 1011 <-- NOT of 0100
// = 0011
XOR ^
The ^ operator sets a bit to 1 if the bits in that position are different. We can use this to toggle a flag:
flags = BORDER_BOTTOM | BORDER_LEFT | BORDER_RIGHT
// 1000
// | 0001
// | 0010
// = 1011
flags ^= BORDER_LEFT
// 1011
// ^ 0001
// = 1010
flags ^= BORDER_LEFT
// 1010
// ^ 0001
// = 1011
Prefer videos?
Check out this video by The Cherno on YouTube: