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.

ABA|B
000
011
101
111

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.

ABA&B
000
010
100
111

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.

ABA^B
000
011
101
110

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 1010or10.

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.

Toby Chambers © 2024