Bitwise Flags
Read Time:5 minutes
After discovering bitwise flags I've become amazed by their wide-reaching uses and implementations. I first came across bitwise flags when working with the Discord API, where they are used for denoting and storing a user's permissions - indeed this is quite a common usecase. However, I've since realised they have even further-reaching uses, such as storing states and truthy/falsy information about a user.
Bit Operators
It's important to have an understanding of the key operators when working with bitwise flags - because these flags operate on the bit level, and thus you need to know how to manipulate the bits.
OR
Operator
The OR
operator will return a 1 if at least one of the input bits is 1. In my examples below, this operator will be represented by an |
symbol.
A | B | A|B |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 1 |
For example: 5 | 1
written in binary is 0101 | 0001
, and thus the result is 0101
or 5
, because only the 2nd and 4th bit have '1's'.
AND
Operator
The AND
operator will return a 1 if both of the input bits are 1. In my examples below, this operator will be represented by an &
symbol.
A | B | A&B |
---|---|---|
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
For example: 5 & 1
written in binary is 0101 & 0001
, and thus the result is 0001
or 1
, because the last bit is the only shared '1'.
XOR
Operator
The XOR
operator will return a 1 if only one of the input bits is 1. In my examples below, this operator will be represented by an ^
symbol.
A | B | A^B |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
For example: 5 ^ 1
written in binary is 0101 ^ 0001
, and thus the result is 0100
or 4
, because the 2nd bit is the only non-shared 1.
NOT
Operator
The NOT
operator will invert the value of all input bits. In my examples below, this operator will be represented by an ~
symbol.
For example: ~5
written in binary is ~0101
, and thus the result is 1010
or10
.
Left Shift
Operator
The Left Shift
operator will push zeros in from the right, with the leftmost bits falling off the value. In my examples below, this operator will be represented by an <<
symbol.
For example: 5 << 1
written in binary is 0101 << 0001
, which results in 1010
, which is equal to 10
.
Right Shift
Operator
The Right Shift
operator will push zeros in from the left, with the rightmost bits falling off the value. In my examples below, this operator will be represented by an >>
symbol.
For example: 5 >> 1
written in binary is 0101 >> 0001
, which results in 0010
, which is equal to 2
.
What Are Bitwise Flags - And How do I Use Them?
Bitwise flags are an efficient method of storing multiple ON/OFF values in the same value - removing the need for storing several values in a database. For example, what may previously be stored as:
To create these flags, we use the left shift operator
const user = {
name: 'Toby Chambers',
flags: {
ACCESS1 = true,
ACCESS2 = false,
ACCESS3 = true,
}
}
Could instead be represented as:
const {
ADMINISTRATOR = 1 << 0, // (1)
EMAIL_VERIFIED = 1 << 1, // (2)
PHONE_VERIFIED = 1 << 2, // (4)
}
const user = {
name: 'Toby Chambers',
flags: 4
}
Checking if a Flag Exists
Bitwise flags allow us to easily check if a flag exists, by simply checking if a user's 'flag value' includes that flag bit, for example:
const ADMINISTRATOR = 1 << 0, // (1)
EMAIL_VERIFIED = 1 << 1, // (2)
PHONE_VERIFIED = 1 << 2; // (4)
const user = {
name: 'Toby Chambers',
flags: 3,
};
const hasAdministratorFlag = (ADMINISTRATOR & user.flags) === ADMINISTRATOR ? true : false;
const hasEmailVerifiedFlag = (EMAIL_VERIFIED & user.flags) === EMAIL_VERIFIED ? true : false;
const hasPhoneVerifiedFlag = (PHONE_VERIFIED & user.flags) === PHONE_VERIFIED ? true : false;
In this example, hasAdministratorFlag
and hasEmailVerifiedFlag
would be true.
Creating a Flags value
Creating / updating the flags value that stores the bitwise flags is very simple. We can do this by simply adding the relevant bits that are associated with the flag(s) we'd like to add.
In my example, this can be done like so:
user.flags = user.flags | ADMINISTRATOR;
Or, if we'd like to add multiple flags:
user.flags = user.flags | ADMINISTRATOR | EMAIL_VERIFIED | PHONE_VERIFIED;
Advantages of Using Bitwise Flags
- Reduced read/write operations in a database, as less data needs to be fetched. This is because the flags can be stored as a single value.
- Simple to add new flags, as this doesn't require the editing of schemas.
Disadvantages of Using Bitwise Flags
- Requires more processing on the client, as the flags must be extracted from the flag code.
Conclusion
Bitwise flags are a versatile tool that I hope to make use of in my future projects - including implementing them into Fawkes.js for more than just interacting with the Discord API, and instead providing users with this data. Whilst I initially found them somewhat confusing, due to my lack of experience working with base-2, and on a bit level, the experience of using them has helped further my knowledge in these areas.