Skip to content

Instantly share code, notes, and snippets.

@younisshah
Created December 25, 2019 09:40
Show Gist options
  • Save younisshah/780533c93bc25f7ff4b7eaaf01a1d0ea to your computer and use it in GitHub Desktop.
Save younisshah/780533c93bc25f7ff4b7eaaf01a1d0ea to your computer and use it in GitHub Desktop.
Intuitive explanation of bitmasks
package bits
import "fmt"
/*
* Check this (https://alemil.com/bitmask) for full article
*/
const (
CanRun = 1 << 0 // 1
CanBark = 1 << 1 // 2
HasTail = 1 << 2 // 4
CanJump = 1 << 3 // 8
CanFly = 1 << 4 // 16
IsCute = 1 << 5 // 32
IsPet = 1 << 6 // 64
)
// Bitmasks are a very useful way to compress multiple boolean flags in a single variable.
// It can reduce memory usage and operations on bits are basically as fast as they can get.
// In practice, any time you want to have multiple flags describing something in your application,
// a bitmask could be the right tool for the job.
func BitMask() {
// base animal
// 0 means that no properties has been assigned
// which translates to all boolean flags set to false
var noProperties uint32 = 0
fmt.Println("noProperties", noProperties)
// bitwise OR | all the properties for a dog
var dogProperties uint32 = CanRun | CanBark | HasTail | CanJump
fmt.Println("dogProperties", dogProperties) // prints 15
// bitwise OR | all the properties for a parrot
var parrotProperties uint32 = HasTail | CanFly | IsCute
fmt.Println("parrotProperties", parrotProperties) // prints 52
// if we wanna toggle a property using bitwise ^.
// it'll either remove or add it depending on the current state of the bitmask
parrotProperties ^= IsCute // we don't think parrot is cute anymore, we'll turn it OFF
fmt.Println("not cute parrotProperties", parrotProperties) // prints 20 (52 - 32)
// no parrots are cute
parrotProperties ^= IsCute // turn it ON
fmt.Println("cute parrotProperties", parrotProperties) // prints 52
// Turn off a flag no matter what the current state of the is
// bitwise AND & and bitwise NOT ^
// ^IsCute means every flag except IsCute is set to true
parrotProperties &^= IsCute
fmt.Println("not parrotProperties", parrotProperties) // prints 52
// How do we know which properties are set?
// Check if Dog has a tail
hasTail := (dogProperties & HasTail) == HasTail
// The above translates to:
// give me every mask that exists both to the left and to the right of the & ampersand character
// and compare == to see if what I need is the result.
fmt.Println("dog has a tail?", hasTail)
// remove dog's tail
dogProperties &^= HasTail
// Check again if Dog has a tail
hasTail = (dogProperties & HasTail) == HasTail
fmt.Println("dog has a tail?", hasTail)
// let's compare out dog and the parrot can see if anyone of them has a tail
anyoneHasTail := ((dogProperties | parrotProperties) & HasTail) == HasTail
fmt.Println("anyone has tail?", anyoneHasTail)
// or let's check if anyone is out pet
isMyPet := ((dogProperties | parrotProperties) & IsPet) == IsPet
fmt.Println("anyone is my pet?", isMyPet)
// also if we wanna know if EXACTLY on of the animals has a tail, but NOT both
exactlyOneTail := ((dogProperties ^ parrotProperties) & HasTail) == HasTail
fmt.Println("only one animal has tail?", exactlyOneTail)
// let's give back dog it's tail
dogProperties |= HasTail // toggle it's tail
fmt.Println("dog has a tail?", (dogProperties & HasTail) == HasTail)
// check if only one of them has a tail
exactlyOneTail = ((dogProperties ^ parrotProperties) & HasTail) == HasTail
fmt.Println("only one animal has tail?", exactlyOneTail) // false
// bit representation in memory
binary(noProperties)
// give it ability to run
noProperties |= CanRun
binary(noProperties) // 00000001: CanRun is second flag starting from the beginning (1 << 1)
// give it ability to bark
noProperties |= CanBark
binary(noProperties) // 00000011: CanRun is third flag starting from the beginning (1 << 2)
// make it cute
noProperties |= IsCute
binary(noProperties) // 00100011: IsCute is the 6th flag from the beginning. (1 << 5)
// bit shifting
binary(dogProperties)// 00001111
// shift by 1
// move all our flag forward.
// now the dog can't run, but it can fly
dogProperties <<= 1
binary(dogProperties)// 00011110:
// check if dog can run
fmt.Println("can dog run?:", (dogProperties & CanRun) == CanRun) // false
fmt.Println("can dog fly?:", (dogProperties & CanFly) == CanFly) // true
dogProperties >>= 2 // shift right by 2. one shift for giving dog ability to run and one more to take dog's ability to jump
binary(dogProperties)
fmt.Println("can dog jump?:", (dogProperties & CanJump) == CanJump)
}
func binary(x uint32) {
fmt.Printf("%08b\n", x)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment