Bit Flags in Go

Sometimes options can be expressed using so called bit flags. When using bit flags, each bit of a given byte is considered on its own to determine if a specific option is set.

For example we might have a unsigned integer variable to define the combination of the 3 colors: red, blue and green.

The 0b prefix indicates that this is the binary representation of a number.

var rgb uint8 = 0 b 0 0 0
                      └─ red
                     └─── green
                    └───── blue

Each color occupies on bit in the integer variable or bit field. Above, all bits are set to 0, so we consider the respective colors to be unset.

Now we can use bitwise operators to manipulate individual bits of the rgb variable.

In order to make it easier to manipulate the bits, we create a constant bit mask for each color.

const (
  red   uint8 = 0b001
  green uint8 = 0b010
  blue  uint8 = 0b100
)

Set a bit

If we want to turn on a particular color, we use the bitwise OR operator. This will leave every bit in rgb untouched except for the red one. The red bit is set set since the OR will set it if it is set in rgb or red.

rgb = rgb|red // 001

Unset a bit

If we want to turn of a particular bit, we use the bitwise AND NOT (&^). The XOR (^) operator inverts the value of red. So every bit except for the red one is turn on. Thus, when using te inverted value with the AND (&) operator, the result is that every bit in rgb that was already turned on, remains turned on, except for the red one. The red bit is always turned of because is is 0 in the inverted value.

rgb = rgb & ^red // 000

Toggle a bit

If we want to toggle a bit, we use the bitwise XOR (^). In below example we are toggling the green bit of the rgb variable. This works because every bit except for the green one is unset in our green const. Meaning all bits of rgb except for the green one remain the same. The green one will be set or unset depending on its current value. If its already set, XOR will unset it because both rgb and green have it set. If its not set XOR will set it because the it is set in the green variable but not in rgb.

rgb = rgb^green // 010

Check wether a bit is set or unset

If we want to check if a particular bit is set, we use the bitwise AND (&) operator, and check if the result is greater than 0.

Because every bit except for the red bit is 0 in our variable red, the result of using the AND (&) operator is that every bit except for red is turned to 0. The red bit itself will only be 1 if it was already 1 in the rgb variable. So we know if the result is 0, red is not 1 in the rgb variable.

isRed := rgb&red > 0 // true

Iota

Instead of defining each variable manually as uint8 and assigning a value to it, we can make use if iota. First we declare a unit8 type called rgb. Then we use iota in combination with left shift (<<) to define each color bit flag.

The value of iota is the ordinal position of the const declaration, starting at 0. Therefore, in the below example, we set the first const declaration, red, to 0b001 and shift its position by iota which is 0. So effectively we don't shift at all. On the next declaration, green, we shift 0b001 by 1 resulting in or 0b10. This pattern repeats until the end of the const block.

const (
 red    rgb = 0b001 << iota // 0b1<<0 = 0b001
 green                      // 0b1<<1 = 0b010
 blue                       // 0b1<<2 = 0b100
)

iota is a predeclared identifier representing the untyped integer ordinal number of the current const specification in a (usually parenthesized) const declaration. It is zero-indexed.

Short Hand Assignment

Go supports shorthand assignment using bitwise operators.

For example, instead of:

rgb = rgb|red|blue

We can write:

rgb |= red|blue

Example

const (
 red byte = 1 << iota
 green
 blue
)

func configureLighting(flags byte) {
 if flags&red > 0 {
  // turn on red lights
 }
 if flags&green > 0 {
  // turn on green lights
 }
 if flags&blue > 0 {
  // turn on blue lights
 }
}

func main() {
 configureLighting(red | blue)
}

Bitwise Operators

Below is an overview of the bitwise operators in go.

&    bitwise AND            integers
|    bitwise OR             integers
^    bitwise XOR            integers
&^   bit clear (AND NOT)    integers
<<   left shift             integer << integer >= 0
>>   right shift            integer >> integer >= 0