Skip to content

Instantly share code, notes, and snippets.

@romain-grecourt
Created March 19, 2021 21:01
Show Gist options
  • Save romain-grecourt/34dceee216cb92b46f0fd2da59970d21 to your computer and use it in GitHub Desktop.
Save romain-grecourt/34dceee216cb92b46f0fd2da59970d21 to your computer and use it in GitHub Desktop.
Enum bitmagic

Enum ordinal as bit position

enum Modifier {
	DEFAULT, PRIVATE, PROTECTED, PUBLIC, STATIC, FINAL
}
DEFAULT     ordinal: 0  bitmask: 2^0 = (int) 1
PRIVATE     ordinal: 1  bitmask: 2^1 = (int) 2
PROTECTED   ordinal: 2  bitmask: 2^2 = (int) 4
PUBLIC      ordinal: 3  bitmask: 2^3 = (int) 8
STATIC      ordinal: 4  bitmask: 2^3 = (int) 16
FINAL       ordinal: 5  bitmask: 2^4 = (int) 32

Bit mask for a given position is done with a shift left.

1 << 0 = 1
1 << 1 = 2
1 << 2 = 4
1 << 3 = 8
1 << 4 = 16
1 << 5 = 32

I.e, bit mask for a given enum value is 1 << enum.ordinate().

Duplicates

Test if a bit is not set with (bitset & mask) == 0, then set the bit with bitset |= bitmask.

int bitset = 0;
for (Modifier modifier : modifiers) {
    int mask = 1 << modifier.ordinal();
    if ((bitset & mask) == 0) {
        bitset |= mask;
    } else {
        return false;
    }
}
return true;

Contains any

Accumulate all the bits for the expected values: bitset |= (1 << modifier.ordinal())

Loop over the actual values and test if a bit is set with: (bitset & (1 << modifier.ordinal())) == 0

int bitset = 0;
for (Modifier modifier : expected) bitset |= (1 << modifier.ordinal());
for (Modifier modifier : actual) {
    if ((bitset & (1 << modifier.ordinal())) == 0) {
        return false;
    }
}
return true;

Contains only one of

Compute a mask for the subset that is tested.

E.g.

DEFAULT, PRIVATE, PROTECTED, PUBLIC = 2^0 + 2^1 + 2^2 + 2^3 = 1 + 2 + 4 + 8 = 15

Accumulate a bitset for each enum values: bitset |= (1 << modifier.ordinal()).

Restrict the bitset to the subset: bitset & 15

Test if zero or one bit is set: (access & (access - 1)) == 0

int bitset = 0;
for (Modifier modifier : modifiers) {
    bitset |= (1 << modifier.ordinal());
    int access = bitset & 15;
    if ((access & (access - 1)) == 0) {
        // zero or one bit set
        continue;
    }
    return false;
}
return true;

Applications

This can be used for implementing a state machine.

The state or states are maintained in an AtomicInteger, each state and transition is a a bitmask.

AtomicInteger bitset; //...
bitset.getAndUpdate(v -> v < 0 ? v | mask : v);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment