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_LEFT
flags |= BORDER_LEFT | BORDER_RIGHT
- Remove flags using AND
&
and NOT~
:flags &= ~BORDER_LEFT
flags &= ~(BORDER_LEFT | BORDER_RIGHT)
- Toggle flags using XOR
^
:flags ^= BORDER_LEFT
flags ^= BORDER_LEFT | BORDER_RIGHT
- Check any flags using AND
&
:flags & BORDER_LEFT
flags & (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_LEFT
flags & (BORDER_LEFT | BORDER_RIGHT) == (BORDER_LEFT | BORDER_RIGHT)
- e.g.
toCheck = BORDER_LEFT | BORDER_RIGHT
if (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: