Bit Flag Enums

Java enums are nice, but how can you use them as them as bit flags? In many other programming languages this is perfectly simple.

The Problem

As already told in this post about the values() flaw in Java enums I’m a big fan of the rich enums Java provides while other languages just have enums which are basically constant named integers.

Why use enums for integer constants at all?

In my viewer project I use a lot of enums to represent internally used integer values to make the life of programmers who use my code a bit easier. Basically I could just add integer constants for given values instead of enums, but then there is always the problem for a user which constants she should use for a given setter method. This could be documented (who reads that?). Having enums introduces type safety and the possible values are inherently documented. Of course the enum should be documented, but this only happens once and not in each case it is used as a parameter or return value.

Think about

/** Unspecified line join style. */
public static final int JOIN_STYLE_NONE = 0;
/** Round line join style. */
public static final int JOIN_STYLE_ROUND = 1;
/** Angle line join style. */
public static final int JOIN_STYLE_ANGLE = 2;
/** Flat join style. */
public static final int JOIN_STYLE_FLAT = 3;
// [...]
/**
 *  Set the line join style.
 *  @param style the join style for lines, one of
 *               <ul>
 *                 <li>{@link #JOIN_STYLE_NONE}</li>
 *                 <li>{@link #JOIN_STYLE_ROUND}</li>
 *                 <li>{@link #JOIN_STYLE_ANGLE}</li>
 *                 <li>{@link #JOIN_STYLE_FLAT}</li>
 *               </ul>
 */
public void setJoinStyle(int style)
{
  switch (style) {
  case JOIN_STYLE_NONE:
  case JOIN_STYLE_ROUND:
  case JOIN_STYLE_ANGLE:
  case JOIN_STYLE_FLAT:
    this.joinStyle = style;
    break;
  default:
    throw new IllegalArgumentException("Incorrect join style: "+style);
  }
}

/**
 *  Get the line join style.
 *  @preturn the join style for lines, one of
 *               <ul>
 *                 <li>{@link #JOIN_STYLE_NONE}</li>
 *                 <li>{@link #JOIN_STYLE_ROUND}</li>
 *                 <li>{@link #JOIN_STYLE_ANGLE}</li>
 *                 <li>{@link #JOIN_STYLE_FLAT}</li>
 *               </ul>
 */
public int getJoinStyle()
{
  return joinStyle; 
}

versus

/** Line join style. */
public enum JoinStyle
{
  /** No specific style. */
  None,
  /** Round join. */
  Round,
  /** Angle join. */
  Angle,
  /** Flat join. */
  Flat;
}
// [...]
/**
 *  Set the line join style.
 *  @param style the join style for lines
 */
public void setJoinStyle(@NotNull JoinStyle style)
{
  this.joinStyle = style;
}

/**
 *  Get the line join style.
 *  @return the join style for lines
 */
@NotNull
public JoinStyle getJoinStyle()
{
  return joinStyle;
}

I hope you agree that the second solution is much preferable for several reasons.

Bit Flags enter the game

But coming from ancient times of programming the formats displayed in my viewer also use a lot of bit flags. For languages using the constant named integer enums I frowned upon above this is no problem. Mostly they can directly mix integers and enums using all operators (especially binary or, and, not and xor), or they need a bit of casting or annotating (like the [Flags] annotation in C#).

Java has nothing in that direction, so bad luck. Or a lot of work.

My Solution

Prepare for a long journey, this is not getting easy.

Design Goals

Immutablility

Nowadays I usually start my designs with immutable classes. Obviously this includes interface which just provide no methods for change. Immutable classes have several advantages:

  1. They are inherently thread-safe.
  2. You can easily define constants.
  3. You can cache values.

Of course there is one obvious disadvantage: you cannot change an object of an immutable class. So if you want a change, you’ll have to create a changed copy. So for larger objects which often change immutability can lead to performance problems because of the heavy copying involved.

Performance

Integers bit flags operations are very fast, as they usually can be performed directly on the processor. Anything based on enums will obviously be much slower, but I wanted the costs to be low.

Same is true for memory. Any bit flags field in my classes will use a pointer, and an object it is pointing to. Compare that to the byte which can already handle 8 bit flags.

Ease of Use

This includes that like in the enums code example above each method should make clear what it accepts without additional documentation (although the user has to grok the bit flag enum concept once).

Slow Start

Although it isn’t obvious when using integers the bit flag concept combines two different kind of objects: a bit flag representing a single bit and bit mask representing an array of these flags.

Bit masks are used as arrays of boolean values which usually have the length of 8 (a byte bit mask), 16 (a short bit mask), 32 (an int bit mask), or 64 (a long bit mask). Of course usually not all possible entries are used, and using BitSet much larger arrays could be created.

A bit flag is just the index of one bit in a mask.

At first we’ll keep to the low level of bit flags and masks, and marry them with the enums later.

BitFlag

Let’s start with the bit flag. This has to be an interface, because each enum bit flag object will have to implement it as we cannot introduce a base class for enums. For the very same reason this interface should be as simple as possible. We’ll just move the real work to the mask for which we currently just know the type BitMask as a placeholder.

/**
 * A single bit flag.
 */
public interface BitFlag
{
  /**
   * Is this flag set in the given mask?
   * @param mask bit mask
   * @return {@code true}: if the flag is set<br/>
   *         {@code false}: if the flag is not set
   */
  boolean isSetIn(@NotNull BitMask mask);

  /**
   * Set this flag in the given bit mask.
   * @param mask bit mask
   * @return new bit mask where this flag is set
   */
  @NotNull
  BitMask setIn(@NotNull BitMask mask);

  /**
   * Clear this flag in the given bit mask.
   * @param mask bit mask
   * @return new bit mask where this flag is cleared
   */
  @NotNull
  BitMask clearIn(@NotNull BitMask mask);
}

That’s nearly as easy as could be:

  • check whether the bit flag is set
  • set the bit flag
  • clear the bit flag

The last two methods could be joined into one setter with an additional boolean parameter telling whether to set or to clear the flag, but I found the above slightly preferable.

SimpleBitFlag

A basic implementation of this interface is done in class SimpleBitFlag:

/**
 * A simple bit flag implementation.
 *
 * For efficiency reasons this class is not constructable,
 * as the {@link SimpleBitFlag#get(int)} factory methods instead.
 *
 * This class is immutable.
 *
 * @author <a href="mailto:rammi@caff.de">Rammi</a>
 */
public final class SimpleBitFlag
        implements BitFlag
{
  private static final SimpleBitFlag[] STANDARD_FLAGS = new SimpleBitFlag[64];
  static {
    for (int p = 0;  p < STANDARD_FLAGS.length;  ++p) {
      STANDARD_FLAGS[p] = new SimpleBitFlag(p);
    }
  }

  private final int bitPosition;

  /**
   * Constructor.
   * @param bitPosition  bit flag position, non-negative
   */
  private SimpleBitFlag(int bitPosition)
  {
    if (bitPosition < 0) {
      throw new IllegalArgumentException("pos has to be non-negative!");
    }
    this.bitPosition = bitPosition;
  }

  /**
   * Is this flag set in the given mask?
   *
   * @param mask bit mask
   * @return {@code true}: if the flag is set<br/>
   * {@code false}: if the flag is not set
   */
  @Override
  public boolean isSetIn(@NotNull BitMask mask)
  {
    return mask.isSet(bitPosition);
  }

  /**
   * Set this flag in the given bit mask.
   *
   * @param mask bit mask
   * @return new bit mask where this flag is set
   */
  @NotNull
  @Override
  public BitMask setIn(@NotNull BitMask mask)
  {
    return mask.set(bitPosition);
  }

  /**
   * Clear this flag in the given bit mask.
   *
   * @param mask bit mask
   * @return new bit mask where this flag is cleared
   */
  @NotNull
  @Override
  public BitMask clearIn(@NotNull BitMask mask)
  {
    return mask.clear(bitPosition);
  }

  /**
   * Convert this flag into a bit mask.
   *
   * @return bit mask
   */
  @NotNull
  public BitMask toBitMask()
  {
    if (bitPosition < BitMask16.BIT_COUNT) {
      return setIn(BitMask16.ZERO);
    }
    if (bitPosition < BitMask32.BIT_COUNT) {
      return setIn(BitMask32.ZERO);
    }
    if (bitPosition < BitMask64.BIT_COUNT) {
      return setIn(BitMask64.ZERO);
    }
    return setIn(new BitSetBitMask(bitPosition + 1));
  }

  /**
   * Convert this flog into an integer bit mask.
   * @return integer bit mask, possibly {@code 0} if this flag is outside of 32 bit range range
   */
  public int toInt()
  {
    if (bitPosition < 32) {
      return 0x01 << bitPosition;
    }
    return 0;
  }

  /**
   * Convert this flog into a long bit mask.
   * @return long bit mask, possibly {@code 0} if this flag is outside of 64 bit range
   */
  public long toLong()
  {
    if (bitPosition < 64) {
      return 0x01L << bitPosition;
    }
    return 0;
  }

  /**
   * Get the bit position associated with this flag.
   * @return bit position
   */
  public int getBitPosition()
  {
    return bitPosition;
  }

  /**
   * Get the simple bit flag for which the given index is set.
   * @param index bit flag index
   * @return simple bit flag which has the given bit index set
   */
  @NotNull
  public static SimpleBitFlag get(int index)
  {
    if (index < 0  ||  index >= STANDARD_FLAGS.length) {
      return new SimpleBitFlag(index);
    }
    return STANDARD_FLAGS[index];
  }
}

This already uses some of methods of the yet unknown BitMask interface, and is based on the fact that a bit flag is just a position in a bit mask, This position is stored in field bitPosition. Because we know that the bit masks we’ll handle have restricted length, we can construct all BitFlag objects we are expecting directly as constants. Being constants, the class has to be final and immutable (it cannot be changed which we enforced by making the only field final, too).

As everything is constant, there is no constructor but a static factory method get(int), which usually returns the appropriate constant BitFlag from the STANDARD_FLAGS array. So the only expected memory necessary to keep all bit flags in standard situation is just this 64 objects constructed once during class load. That is nice and efficient.

BitMask

As mentioned before the bit mask interface is the work horse, so it is a bit more complex. I decided for the following, which I’ll introduce step by step:

/**
 * A set of bit flags.
 *
 * @author <a href="mailto:rammi@caff.de">Rammi</a>
 */
public interface BitMask
{
  /**
   * Is the flag at the given position set?
   * @param pos position (non-negative)
   * @return {@code true}: the flag is set<br/>
   *         {@code false}: the flag is not set
   */
  boolean isSet(int pos);

  /**
   * Set the flag at the given position.
   * @param pos position
   * @return bit mask where the flag at the given position is set
   */
  @NotNull
  BitMask set(int pos);

  /**
   * Clear the flag at the given position.
   * @param pos position
   * @return bit mask where the flag at the given position is cleared
   */
  @NotNull
  BitMask clear(int pos);

These 3 methods correspond directly to the methods in the BitFlag interface. Immutability of classes implementing this interface is kept in mind, so the changing methods return a new BitMask instead of setting or clearing the bit directly.

  /**
   * Get the number of possible bits used in this flag.
   * @return bit count
   */
  int getBitCount();

In some cases the size of the bit mask is of interest, and that’s getBitCount() good for.

  /**
   * Get the number of bits set in this flag.
   * @return set bit count
   */
  int getCardinality();

  /**
   * Is no flag set?
   * @return {@code true}: if no flag in this bit mask is set<br/>
   *         {@code false}: if any flag in this bit mask is set
   */
  boolean isEmpty();

The numbers of set bits can come in handy some times, e.g. when we want to convert a BitMask into an array of BitFlags. isEmpty() is the same as a cardinatity of 0, but can be faster calculated. Consider a bitmask of 137: you can easily tell that this is non-empty, but how many bits are set is a bit more complex to tell.

  /**
   * Flip the flag at the given position.
   * @param pos position
   * @return bit mask where the flag at the given position is flipped
   */
  @NotNull
  BitMask flip(int pos);

The method flip() is a convenience method which in my code is not used.

  /**
   * Get the inverse of this bit mask.
   * @return inverse bit mask
   */
  @NotNull
  BitMask not();

  /**
   * Get the result of a logical <b>and</b> of this bit mask and another.
   * @param other other bit mask
   * @return resulting bit mask
   */
  @NotNull
  BitMask and(@NotNull BitMask other);

  /**
   * Get the result of a logical <b>and</b> of this bit mask and the inverse of another.
   * @param other other bit mask
   * @return resulting bit mask
   */
  @NotNull
  BitMask andNot(@NotNull BitMask other);

  /**
   * Get the result of a logical <b>or</b> of this bit mask and another.
   * @param other other bit mask
   * @return resulting bit mask
   */
  @NotNull
  BitMask or(@NotNull BitMask other);

  /**
   * Get the result of a logical <b>xor</b> (exclusive or) of this bit mask and another.
   * @param other other bit mask
   * @return resulting bit mask
   */
  @NotNull
  BitMask xor(@NotNull BitMask other);

The above methods allow to do the operations which are expected to be possible with bit masks. Although some of them just seem to be for convenience as they could be expressed by combining others, they are for efficiency to avoid calculations of intermediate BitMask objects.

  /**
   * Convert this bit mask into a bit set.
   * @return bit set
   */
  @NotNull
  BitSet toBitSet();

  /**
   * Get the lower 32 bits of this mask.
   * @return lower 32 bits as an int
   */
  int low32();

  /**
   * Get the lower 64 bits of this mask.
   * @return lower 64 bits
   */
  long low64();
}

Finally we provide some cast methods allowing to handle the bit mask as a standard BitSet (this should always work), as a long (only keeping all information when the length of the mask is less than 64) or as an int (good for less than 32 bits). There is no comparable method for short or byte, as these methods allow lost of information we can easily use (short)mask.low32() to get a short if required.

BitMask Implementations

Basically all we need for implementing the BitMask interface would be a class which wraps or extends a standard BitSet. But that would be inefficient as we expect to have lots of BitMasks. When each has its individual BitSet this would use a lot of memory. This is one of the rare cases where we’ll sacrifice the DRY Principle and allow for some code duplication.

For fallback we’ll indeed implement a BitMask based on BitSet. But we’ll also add BitMasks based on the primitive types short (BitMask16), int (BitMask32) and long (BitMask64). These 3 will have a lot of code duplication, so there’s no byte based BitMask to avoid another duplication without much expected effect. Bit masks with 8 bits are not used by my formats, but if you need one it’s added easily enough, which is the result of designing with interfaces.

BitSetBitMask

This is the fallback if someone really decides to use more than 64 bits in her mask. We have to keep in mind that BitSet is mutable, so it never might appear on the outside of this class. As planned BitSetBitMask itself is made immutable.

/**
 * A bit set based bit mask.
 * This allows for arbitrary sized bit counts.
 * This class is immutable.
 *
 * @author <a href="mailto:rammi@caff.de">Rammi</a>
 */
public final class BitSetBitMask
        implements BitMask
{
  /** Bit set bit mask with no bits set. */
  public static final BitSetBitMask ZERO = new BitSetBitMask(new BitSet());

Being immutable allows us to provide useful constants.

  @NotNull
  private final BitSet bitSet;

  /**
   * Optimized internal constructor.
   * @param doClone clone parameter?
   * @param bitSet   flags to use
   */
  private BitSetBitMask(boolean doClone,
                        @NotNull BitSet bitSet)
  {
    this.bitSet = doClone
            ? (BitSet)bitSet.clone()
            : bitSet;
  }

In some cases the bitSet comes from the outside and needs cloning (or someone could keep a reference to it, allowing changes), in other cases it’s from inside and can be kept.

  /**
   * Constructor.
   * @param bitSet flags on which this mask is based
   */
  public BitSetBitMask(@NotNull BitSet bitSet)
  {
    this(true, bitSet);
  }

  /**
   * Constructor.
   * This creates a bit mask with a capacity for the given number of flags.
   * @param flagCount flag count
   */
  public BitSetBitMask(int flagCount)
  {
    this(false, new BitSet(flagCount));
  }

Construction is either done from a BitSet, or just from the maximum number of bits. As we don’t expect to use this class at all, there are not other convenience constructors.

  /**
   * Is the flag at the given position set?
   *
   * @param pos position (non-negative)
   * @return {@code true}: the flag is set<br/>
   * {@code false}: the flag is not set
   */
  @Override
  public boolean isSet(int pos)
  {
    return bitSet.get(pos);
  }

  /**
   * Set the flag at the given position.
   *
   * @param pos position
   * @return bit mask where the flag at the given position is set
   */
  @NotNull
  @Override
  public BitMask set(int pos)
  {
    if (isSet(pos)) {
      return this;
    }
    BitSet newFlags = (BitSet)bitSet.clone();
    newFlags.set(pos);
    return new BitSetBitMask(false, newFlags);
  }

  /**
   * Clear the flag at the given position.
   *
   * @param pos position
   * @return bit mask where the flag at the given position is cleared
   */
  @NotNull
  @Override
  public BitMask clear(int pos)
  {
    if (!isSet(pos)) {
      return this;
    }
    BitSet newFlags = (BitSet)bitSet.clone();
    newFlags.set(pos);
    return new BitSetBitMask(false, newFlags);
  }

The set() and clear() methods hurt a bit, because a (possibly large) BitSet is cloned. But being immutable allows to return this when nothing is changed.

  /**
   * Get the number of possible bits used in this flag.
   *
   * @return bit count
   */
  @Override
  public int getBitCount()
  {
    return bitSet.size();
  }

  /**
   * Get the number of bits set in this flag.
   *
   * @return set bit count
   */
  @Override
  public int getCardinality()
  {
    return bitSet.cardinality();
  }

  /**
   * Is no flag set?
   *
   * @return {@code true}: if no flag in this bit mask is set<br/>
   * {@code false}: if any flag in this bit mask is set
   */
  @Override
  public boolean isEmpty()
  {
    return bitSet.isEmpty();
  }

  /**
   * Flip the flag at the given position.
   *
   * @param pos position
   * @return bit mask where the flag at the given position is flipped
   */
  @NotNull
  @Override
  public BitMask flip(int pos)
  {
    BitSet newFlags = (BitSet)bitSet.clone();
    newFlags.flip(pos);
    return new BitSetBitMask(false, newFlags);
  }

  /**
   * Get the inverse of this bit mask.
   *
   * @return inverse bit mask
   */
  @NotNull
  @Override
  public BitMask not()
  {
    BitSet newFlags = (BitSet)bitSet.clone();
    newFlags.flip(0, newFlags.length());
    return new BitSetBitMask(false, newFlags);
  }

  /**
   * Get the result of a logical <b>and</b> of this bit mask and another.
   *
   * @param other other bit mask
   * @return resulting bit mask
   */
  @NotNull
  @Override
  public BitMask and(@NotNull BitMask other)
  {
    BitSet newFlags = (BitSet)bitSet.clone();
    newFlags.and(other.toBitSet());
    return new BitSetBitMask(false, newFlags);
  }

  /**
   * Get the result of a logical <b>and</b> of this bit mask and the inverse of another.
   *
   * @param other other bit mask
   * @return resulting bit mask
   */
  @NotNull
  @Override
  public BitMask andNot(@NotNull BitMask other)
  {
    BitSet newFlags = (BitSet)bitSet.clone();
    newFlags.andNot(other.toBitSet());
    return new BitSetBitMask(false, newFlags);
  }

  /**
   * Get the result of a logical <b>or</b> of this bit mask and another.
   *
   * @param other other bit mask
   * @return resulting bit mask
   */
  @NotNull
  @Override
  public BitMask or(@NotNull BitMask other)
  {
    BitSet newFlags = (BitSet)bitSet.clone();
    newFlags.or(other.toBitSet());
    return new BitSetBitMask(false, newFlags);
  }

  /**
   * Get the result of a logical <b>xor</b> (exclusive or) of this bit mask and another.
   *
   * @param other other bit mask
   * @return resulting bit mask
   */
  @NotNull
  @Override
  public BitMask xor(@NotNull BitMask other)
  {
    BitSet newFlags = (BitSet)bitSet.clone();
    newFlags.xor(other.toBitSet());
    return new BitSetBitMask(false, newFlags);
  }

  /**
   * Convert this bit mask into a bit set.
   *
   * @return bit set
   */
  @NotNull
  @Override
  public BitSet toBitSet()
  {
    return (BitSet)bitSet.clone();
  }

  /**
   * Get the lower 32 bits of this mask.
   *
   * @return lower 32 bits as an int
   */
  @Override
  public int low32()
  {
    return (int)low64();
  }

  /**
   * Get the lower 64 bits of this mask.
   *
   * @return lower 64 bits
   */
  @Override
  public long low64()
  {
    return getBitCount() > 0
            ? bitSet.toLongArray()[0]
            : 0L;
  }

The above is straight forward and should be clear without comments.

  @Override
  public boolean equals(Object o)
  {
    if (this == o) {
      return true;
    }
    if (o == null || !(o instanceof BitMask)) {
      return false;
    }

    return BitMaskUtil.areEqual(this, (BitMask)o);
  }

  @Override
  public int hashCode()
  {
    int hash = 0;
    for (long v : bitSet.toLongArray()) {
      hash ^= BitMaskUtil.getHash64(v);
    }
    return hash;
  }

We want to be able to check bit masks in general, so comparing and hashing is externalized in order to allow for handling all BitMasks the same and not duplicate code.

  /**
   * Returns a string representation of the object. In general, the
   * {@code toString} method returns a string that
   * "textually represents" this object. The result should
   * be a concise but informative representation that is easy for a
   * person to read.
   * It is recommended that all subclasses override this method.
   * <p/>
   * The {@code toString} method for class {@code Object}
   * returns a string consisting of the name of the class of which the
   * object is an instance, the at-sign character `{@code @}', and
   * the unsigned hexadecimal representation of the hash code of the
   * object. In other words, this method returns a string equal to the
   * value of:
   * <blockquote>
   * <pre>
   * getClass().getName() + '@' + Integer.toHexString(hashCode())
   * </pre></blockquote>
   *
   * @return a string representation of the object.
   */
  @Override
  public String toString()
  {
    return String.format("<%s>", bitSet);
  }
}
BitMask16

BitMask16, BitMask32 and BitMask64 are quite similar, so we just show the first one here.

/**
 * A bit mask for 16 bit flags.
 *
 * Please note that this class will not handle more than
 * 16 bits. Setting any higher bits will have no result.
 *
 * This class is immutable.
 *
 * @author <a href="mailto:rammi@caff.de">Rammi</a>
 */
public final class BitMask16
        implements BitMask
{
  /** The number of bits in this class. */
  public static final int BIT_COUNT = 16;

  /** The zero bit mask. This has all 16 flags unset. */
  public static final BitMask16 ZERO = new BitMask16(0);
  /** Mask for the bits in this mask. */
  private static final int MASK = 0xFFFF;
  /** The bit mask where all 16 bits are set. */
  public static final BitMask16 ALL_SET = new BitMask16(MASK);

Again we can provide some useful constants. BIT_COUNT and ZERO indeed were already used in method toBitMask() of SimpleBitFlag.

  private final short flags;

  /**
   * Constructor.
   * @param flags bit mask, only the 16 low order bits are used
   */
  public BitMask16(int flags)
  {
    this.flags = (short)(flags & MASK);
  }

int is used for convenience, otherwise each constructor call with a constant value would need a caset.

  /**
   * Is the flag at the given position set?
   *
   * @param pos position (non-negative)
   * @return {@code true}: the flag is set<br/>
   * {@code false}: the flag is not set
   */
  @Override
  public boolean isSet(int pos)
  {
    if (pos < 0) {
      throw new IllegalArgumentException("pos needs to be non-negative!");
    }
    return pos < BIT_COUNT && (flags >>> pos & 0x01) != 0;
  }

  /**
   * Set the flag at the given position.
   *
   * @param pos position (non-negative)
   * @return bit mask where the flag at the given position is set
   */
  @NotNull
  @Override
  public BitMask set(int pos)
  {
    if (pos < 0) {
      throw new IllegalArgumentException("pos needs to be non-negative!");
    }
    if (isSet(pos) || pos >= BIT_COUNT) {
      return this;
    }
    return new BitMask16(flags | (0x0001 << pos));
  }

  /**
   * Clear the flag at the given position.
   *
   * @param pos position
   * @return bit mask where the flag at the given position is cleared
   */
  @NotNull
  @Override
  public BitMask clear(int pos)
  {
    if (pos < 0) {
      throw new IllegalArgumentException("pos needs to be non-negative!");
    }
    if (!isSet(pos) || pos >= BIT_COUNT) {
      return this;
    }
    return new BitMask16(flags & ~(0x0001 << pos));
  }

The class is expected to be included in a library used by others, so we explicitly raise an exception for ‘pos < 0’. In local code an assert would be more efficient, but only if assertions are enabled.

  /**
   * Get the number of possible bits used in this flag.
   *
   * @return bit count
   */
  @Override
  public int getBitCount()
  {
    return BIT_COUNT;
  }

  /**
   * Get the number of bits set in this flag.
   *
   * @return set bit count
   */
  @Override
  public int getCardinality()
  {
    return Integer.bitCount(flags & MASK);
  }

  /**
   * Is no flag set?
   *
   * @return {@code true}: if no flag in this bit mask is set<br/>
   *         {@code false}: if any flag in this bit mask is set
   */
  @Override
  public boolean isEmpty()
  {
    return (flags & MASK) == 0;
  }

  /**
   * Flip the flag at the given position.
   *
   * @param pos position
   * @return bit mask where the flag at the given position is flipped
   */
  @NotNull
  @Override
  public BitMask flip(int pos)
  {
    if (pos < 0) {
      throw new IllegalArgumentException("pos needs to be non-negative!");
    }
    if (pos >= BIT_COUNT) {
      return this;
    }
    return new BitMask16(flags ^ ~(0x0001 << pos));
  }

  /**
   * Get the inverse of this bit mask.
   *
   * @return inverse bit mask
   */
  @NotNull
  @Override
  public BitMask not()
  {
    return new BitMask16(~flags);
  }

  /**
   * Get the result of a logical <b>and</b> of this bit mask and another.
   *
   * @param other other bit mask
   * @return resulting bit mask
   */
  @NotNull
  @Override
  public BitMask and(@NotNull BitMask other)
  {
    if (other.getBitCount() > BIT_COUNT) {
      return other.and(this);
    }
    int combined = flags & other.low32();
    if (combined == flags) {
      return this;
    }
    return new BitMask16(combined);
  }

  /**
   * Get the result of a logical <b>and</b> of this bit mask and the inverse of another.
   *
   * @param other other bit mask
   * @return resulting bit mask
   */
  @NotNull
  @Override
  public BitMask andNot(@NotNull BitMask other)
  {
    if (other.getBitCount() > BIT_COUNT) {
      return other.not().and(this);
    }
    int combined = flags | ~other.low32();
    if (combined == flags) {
      return this;
    }
    return new BitMask16(combined);
  }

  /**
   * Get the result of a logical <b>or</b> of this bit mask and another.
   *
   * @param other other bit mask
   * @return resulting bit mask
   */
  @NotNull
  @Override
  public BitMask or(@NotNull BitMask other)
  {
    if (other.getBitCount() > BIT_COUNT) {
      return other.or(this);
    }
    int combined = flags | other.low32();
    if (combined == flags) {
      return this;
    }
    return new BitMask16(combined);
  }

  /**
   * Get the result of a logical <b>xor</b> (exclusive or) of this bit mask and another.
   *
   * @param other other bit mask
   * @return resulting bit mask
   */
  @NotNull
  @Override
  public BitMask xor(@NotNull BitMask other)
  {
    if (other.getBitCount() > BIT_COUNT) {
      return other.xor(this);
    }
    int combined = flags ^ other.low32();
    if (combined == flags) {
      return this;
    }
    return new BitMask16(combined);
  }

All bit mask combination methods possibly forward the operation to the other operand if it is larger (has more bits). Thus no information gets lost.

  /**
   * Convert this bit mask into a bit set.
   *
   * @return bit set
   */
  @NotNull
  @Override
  public BitSet toBitSet()
  {
    return BitSet.valueOf(new long[] { low64() });
  }

  /**
   * Get the lower 32 bits of this mask.
   *
   * @return lower 32 bits as an int
   */
  @Override
  public int low32()
  {
    return flags & MASK;
  }

  /**
   * Get the lower 64 bits of this mask.
   *
   * @return lower 64 bits
   */
  @Override
  public long low64()
  {
    return flags & MASK;
  }

  @Override
  public boolean equals(Object o)
  {
    if (this == o) {
      return true;
    }
    if (o == null || !(o instanceof BitMask)) {
      return false;
    }

    return BitMaskUtil.areEqual(this, (BitMask)o);
  }

  @Override
  public int hashCode()
  {
    return BitMaskUtil.getHash64(low64());
  }

  /**
   * Returns a string representation of the object. In general, the
   * {@code toString} method returns a string that
   * "textually represents" this object. The result should
   * be a concise but informative representation that is easy for a
   * person to read.
   * It is recommended that all subclasses override this method.
   * <p/>
   * The {@code toString} method for class {@code Object}
   * returns a string consisting of the name of the class of which the
   * object is an instance, the at-sign character `{@code @}', and
   * the unsigned hexadecimal representation of the hash code of the
   * object. In other words, this method returns a string equal to the
   * value of:
   * <blockquote>
   * <pre>
   * getClass().getName() + '@' + Integer.toHexString(hashCode())
   * </pre></blockquote>
   *
   * @return a string representation of the object.
   */
  @Override
  public String toString()
  {
    return String.format("<%02x>", flags);
  }
}

Marrying Enums

After some work we can now handle bit flags and bit masks and combine them.

We have obeyed our design goal of immutability. The performance goal is not missed that much, as in typical situations all we have are 64 SimpleBitFlags which are passed around, and BitMask16 or BitMask32 which are just immutable wrappers around short or int like java.lang.Short and java.lang.Integer.

We can even make an enum implement BitFlag, forward that internally to a SimpleBitFlag.

Here’s an example:

/** Associativity flags. */
public enum AssociativityFlags
        implements BitFlag
{
  /** First point is referenced. */
  FirstPointReference(0),
  /** Second point is referenced. */
  SecondPointReference(1),
  /** Third point is referenced. */
  ThirdPointReference(2),
  /** Fourth point is referenced. */
  FourthPointReference(3);

  @NotNull
  private final BitFlag flag;

  /**
   * Constructor.
   * @param bit  represented bit id
   */
  AssociativityFlags(int bit)
  {
    flag = SimpleBitFlag.get(bit);
  }

  /**
   * Is this flag set in the given mask?
   *
   * @param mask bit mask
   * @return {@code true}: if the flag is set<br/>
   * {@code false}: if the flag is not set
   */
  @Override
  public boolean isSetIn(@NotNull BitMask mask)
  {
    return flag.isSetIn(mask);
  }

  /**
   * Set this flag in the given bit mask.
   *
   * @param mask bit mask
   * @return new bit mask where this flag is set
   */
  @NotNull
  @Override
  public BitMask setIn(@NotNull BitMask mask)
  {
    return flag.setIn(mask);
  }

  /**
   * Clear this flag in the given bit mask.
   *
   * @param mask bit mask
   * @return new bit mask where this flag is cleared
   */
  @NotNull
  @Override
  public BitMask clearIn(@NotNull BitMask mask)
  {
    return flag.clearIn(mask);
  }

For a given reason this is not yet the whole implementation.

The reason is ease of use. We have our enums, but we use BitMask16 or BitMask32 for the bit mask values. There is no way to differ from a bitmask using the above AssociativityFlags to a bit mask using something else. So if a method returns a BitMask we have no way to know which kind of flags it contains or allows. So we have the same situation which we had with using simple integers, but with much more effort. Time for a final step: we need a BitMask which knows the kind of enum bit flag it is handling.

We’ll call that one EnumBitMask, but before we introduce it we’ll finish the AssociativityFlags.

  /** Cached values. */
  private static final AssociativityFlags[] VALUES = values();


  /** Bit mask where not flag is set. */
  public static final EnumBitMask<AssociativityFlags> NONE = EnumBitMask.NONE32.cast(AssociativityFlags.class);

  /**
   * Get the enum bit mask associated with the given internal value.
   * @param internalValue internal value
   * @return associated bit mask
   */
  @NotNull
  public static EnumBitMask<AssociativityFlags> fromInternal(int internalValue)
  {
    return EnumBitMask.get32(internalValue, AssociativityFlags.class);
  }

  /**
   * Get the flags which are set in the given mask.
   * @param mask mask to check
   * @return set flags
   */
  @NotNull
  public static List<AssociativityFlags> getAllSetFrom(@NotNull EnumBitMask<AssociativityFlags> mask)
  {
    return mask.getAllSet(VALUES);
  }
}

(Check here why the VALUES constant appears.)

Obviously the EnumBitMask has to be a generic class, otherwise we’d have to implenent a specialized class for each enum. For the understanding it is good to know that the flags represented by AssociativityFlags are stored with 32 bit internally. That’s the reason for the 32 appearing twice.

The NONE constant represents the special value where no flag is set. We’ll learn later that the cast() is just used to fool the compiler, it will always return the same object.

The method fromInternal() is used to convert an internal integer value into our typed `EnumBitMask representiaton.

Of course adding all this stuff to each bit flag enum is tedious error-prone work. Luckily modern IDEs like IntelliJ IDEA which I am using allow to create templates. So I added templates for Enum BitFlag 16 and Enum BitFlag 32. The first looks like

#parse("File Header.java")
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end

import de.caff.annotation.NotNull;
import de.caff.util.*;

#parse("Class Comment.java")
public enum ${NAME}
      implements BitFlag 
{
  ;
  
  /** Enum bit of this flags where no flag is set. */
  @NotNull
  public static final EnumBitMask<${NAME}> NONE = EnumBitMask.NONE16.cast(${NAME}.class);
  
  /** Wrapped real bit flag. */
  @NotNull
  private final BitFlag flag;

  /**
   * Constructor.
   * @param flagIndex index of flag
   */
  ${NAME}(int flagIndex)
  {
    flag = SimpleBitFlag.get(flagIndex);
  }
 
  /**
   * Is this flag set in the given mask?
   *
   * @param mask bit mask
   * @return {@code true}: if the flag is set<br/>
   * {@code false}: if the flag is not set
   */
  @Override
  public boolean isSetIn(@NotNull BitMask mask)
  {
    return flag.isSetIn(mask);
  }

  /**
   * Set this flag in the given bit mask.
   *
   * @param mask bit mask
   * @return new bit mask where this flag is set
   */
  @NotNull
  @Override
  public BitMask setIn(@NotNull BitMask mask)
  {
    return flag.setIn(mask);
  }

  /**
   * Clear this flag in the given bit mask.
   *
   * @param mask bit mask
   * @return new bit mask where this flag is cleared
   */
  @NotNull
  @Override
  public BitMask clearIn(@NotNull BitMask mask)
  {
    return flag.clearIn(mask);
  }

  /**
   * Get the enum bit mask associated with a given internal value.
   * @param internalValue internal value (only the lower 16 bits are used)
   * @return associated bit mask
   */
  @NotNull
  public static EnumBitMask<${NAME}> fromInternal(int internalValue)
  {
    return EnumBitMask.get16(internalValue, ${NAME}.class);
  }
}

This keeps care of most of the boilerplate code. The parts included by #parse are already shown here.

The EnumBitMask class

The EnumBitMask will forward all oerations to a simple BitMask, which allows it to be ignorant of the width (16bit, 32bit etc.).

/**
 * Type safe bit flags.
 * This class is immutable.
 *
 * @author <a href="mailto:rammi@caff.de">Rammi</a>
 * @param <E> the enum bit flag type for which this mask is valid
 */
public final class EnumBitMask<E extends Enum<E> & BitFlag>
{
  /** Key mask for excluded keys in 32bit cache. */
  private static final int EXCLUDE_MASK32 = 0xFFFFFFFF << Utility.getIntParameter("ebm.mask32.shift",
                                                                                  16);
  /** The underlying simple bit mask. */
  @NotNull
  private final BitMask bitMask;

  /**
   * Constructor.
   * @param bitMask initial flags
   */
  public EnumBitMask(@NotNull BitMask bitMask)
  {
    this.bitMask = bitMask;
  }

  /**
   * Get the underlying bit mask,
   * @return bit mask
   */
  @NotNull
  public BitMask getBitMask()
  {
    return bitMask;
  }

The basic methods (checking a flag, setting it or clearing it) are just forwarded to the wrapped BitMask. Because we have just this one class, it’s also useful to add a bunch of convenience methods. Because of the immutablility changes will always create a new EnumBitMask, so we check whether changes really do happen and return this otherwise.

  /**
   * Is the given flag set?
   * @param flag flag to check
   * @return {@code true}: the flag is set<br/>
   *         {@code false}: the flag is not set
   */
  public boolean isSet(@NotNull E flag)
  {
    return flag.isSetIn(bitMask);
  }

  /**
   * Is any flag in both this and the other bit mask set?
   * @param other other bit mask
   * @return {@code true}: if any bit is set in both masks<br/>
   *         {@code false}: if no bit is set in both masks
   */
  public boolean isSetAny(@NotNull EnumBitMask<E> other)
  {
    return !other.getBitMask().and(getBitMask()).isEmpty();
  }

  /**
   * Are all flags from the other bit mask set?
   * @param other other bit mask
   * @return {@code true}: if any bit is set in both masks<br/>
   *         {@code false}: if no bit is set in both masks
   */
  public boolean isSetAll(@NotNull EnumBitMask<E> other)
  {
    final BitMask combined = other.getBitMask().and(getBitMask());
    return BitMaskUtil.areEqual(combined, bitMask);
  }

  /**
   * Is any flag from the given sequence set?
   * @param flags flags to check
   * @return {@code true}: if any bit flag is set in this masks<br/>
   *         {@code false}: if no bit flag is set in this masks
   */
  @SafeVarargs
  public final boolean isSetAny(E... flags)
  {
    for (E flag : flags) {
      if (isSet(flag)) {
        return true;
      }
    }
    return false;
  }

  /**
   * Is any flag from the given collection set?
   * @param flags flags to check
   * @return {@code true}: if any bit flag is set in this masks<br/>
   *         {@code false}: if no bit flag is set in this masks
   */
  public boolean isSetAny(@NotNull Collection<E> flags)
  {
    for (E flag : flags) {
      if (isSet(flag)) {
        return true;
      }
    }
    return false;
  }

  /**
   * Are all flags from the given sequence set?
   * @param flags flags to check
   * @return {@code true}: if every bit flag is set in this masks<br/>
   *         {@code false}: if any bit flag is not set in this masks
   */
  @SafeVarargs
  public final boolean isSetAll(E... flags)
  {
    for (E flag : flags) {
      if (!isSet(flag)) {
        return false;
      }
    }
    return true;
  }

  /**
   * Are all flags from the given collection set?
   * @param flags flags to check
   * @return {@code true}: if every bit flag is set in this masks<br/>
   *         {@code false}: if any bit flag is not set in this masks
   */
  public boolean isSetAll(@NotNull Collection<E> flags)
  {
    for (E flag : flags) {
      if (!isSet(flag)) {
        return false;
      }
    }
    return true;
  }

  /**
   * Get a bit mask where all flags are set which are set in this or in another one.
   * @param other other bit mask defining the flags which are set
   * @return this bit mask, but with set flags
   * @see #and(EnumBitMask)
   * @see #clear(EnumBitMask)
   */
  public EnumBitMask<E> or(@NotNull EnumBitMask<E> other)
  {
    final BitMask combined = bitMask.or(other.getBitMask());
    return combined.equals(bitMask)
            ? this
            : new EnumBitMask<E>(combined);
  }

  /**
   * Get a bit mask where all flags are set which are set in this and in another one.
   * @param other other bit mask defining the flags which are set
   * @return this bit mask, but with set flags
   * @see #or(EnumBitMask)
   * @see #clear(EnumBitMask)
   */
  public EnumBitMask<E> and(@NotNull EnumBitMask<E> other)
  {
    final BitMask combined = bitMask.and(other.getBitMask());
    return combined.equals(bitMask)
            ? this
            : new EnumBitMask<E>(combined);
  }

  /**
   * Set the given flag.
   * @param flag flag to set
   * @return bit mask where the given flag is set
   */
  @NotNull
  public EnumBitMask<E> set(@NotNull E flag)
  {
    if (isSet(flag)) {
      return this;
    }
    return new EnumBitMask<>(flag.setIn(bitMask));
  }

  /**
   * Set or clear the given flag.
   * @param flag  flag to change
   * @param onOff {@code true}: set the flag<br/>
   *              {@code false}: clear the flag
   * @return bit mask with flag change appropriately
   */
  public EnumBitMask<E> setTo(@NotNull E flag, boolean onOff)
  {
    return onOff
            ? set(flag)
            : clear(flag);
  }

  /**
   * Set all given flags.
   * @param flags flags to set
   * @return bit mask, where the flags of this mask and the given flags are set
   */
  @SafeVarargs
  @NotNull
  public final EnumBitMask<E> setAll(@NotNull E... flags)
  {
    BitMask combined = bitMask;
    for (E flag : flags) {
      combined = flag.setIn(combined);
    }
    return combined.equals(bitMask)
            ? this
            : new EnumBitMask<E>(combined);
  }

  /**
   * Clear the given flag.
   * @param flag flag to clear
   * @return bit flags where the given flag is cleared
   */
  @NotNull
  public EnumBitMask<E> clear(@NotNull E flag)
  {
    if (!isSet(flag)) {
      return this;
    }
    return new EnumBitMask<>(flag.clearIn(bitMask));
  }

  /**
   * Get a bit mask where all flags are cleared which are set in another one.
   * @param other other bit mask defining the flags which are cleared
   * @return this bit mask, but with cleared flags
   * @see #and(EnumBitMask)
   * @see #or(EnumBitMask)
   */
  public EnumBitMask<E> clear(@NotNull EnumBitMask<E> other)
  {
    final BitMask combined = getBitMask().andNot(other.getBitMask());
    return combined.equals(bitMask)
            ? this
            : new EnumBitMask<E>(combined);
  }

  /**
   * Clear all given flags.
   * @param flags flags to clear
   * @return bit mask, with the flags of this mask where all given flags are cleared
   */
  @SafeVarargs
  @NotNull
  public final EnumBitMask<E> clearAll(@NotNull E... flags)
  {
    BitMask combined = bitMask;
    for (E flag : flags) {
      combined = flag.clearIn(combined);
    }
    return combined.equals(bitMask)
            ? this
            : new EnumBitMask<E>(combined);
  }

  /**
   * Flip the given flag.
   * @param flag flag to flip
   * @return bit flags where the given flag is inverted
   */
  @NotNull
  public EnumBitMask<E> flip(@NotNull E flag)
  {
    return isSet(flag)
            ? new EnumBitMask<E>(flag.clearIn(bitMask))
            : new EnumBitMask<E>(flag.setIn(bitMask));
  }

  /**
   * Flip all given flags.
   * @param flags flags to flip
   * @return bit mask, with the flags of this mask where all given flags are flipped
   */
  @SafeVarargs
  @NotNull
  public final EnumBitMask<E> flipAll(@NotNull E... flags)
  {
    BitMask combined = bitMask;
    for (E flag : flags) {
      if (flag.isSetIn(combined)) {
        combined = flag.clearIn(combined);
      }
      else {
        combined = flag.setIn(combined);
      }
    }
    return new EnumBitMask<E>(combined);
  }

  /**
   * Get a list of all flags which are set in this mask.
   * @param flags flags to check
   * @return a list of all checked flags which are set in this mask
   */
  @NotNull
  @SafeVarargs
  public final List<E> getAllSet(E... flags)
  {
    final List<E> result = new ArrayList<>(flags.length);
    for (E f : flags) {
      if (isSet(f)) {
        result.add(f);
      }
    }
    return result;
  }

  /**
   * Get a list of all flags which are set in this mask.
   * @param flags flags to check
   * @return ma list of all checked flags which are set in this maks
   */
  @NotNull
  public List<E> getAllSet(@NotNull Iterable<E> flags)
  {
    final List<E> result = new LinkedList<>();
    for (E f : flags) {
      if (isSet(f)) {
        result.add(f);
      }
    }
    return result;
  }

  /**
   * Get a list of all flags which are not set in this mask.
   * @param flags flags to check
   * @return a list of all checked flags which are not set in this mask
   */
  @NotNull
  @SafeVarargs
  public final List<E> getAllCleared(E... flags)
  {
    final List<E> result = new ArrayList<>(flags.length);
    for (E f : flags) {
      if (!isSet(f)) {
        result.add(f);
      }
    }
    return result;
  }

  /**
   * Get a list of all flags which are not set in this mask.
   * @param flags flags to check
   * @return ma list of all checked flags which are not set in this maks
   */
  @NotNull
  public List<E> getAllCleared(@NotNull Iterable<E> flags)
  {
    final List<E> result = new LinkedList<>();
    for (E f : flags) {
      if (!isSet(f)) {
        result.add(f);
      }
    }
    return result;
  }

  /**
   * Is no flag set?
   * @return {@code true}: if no flag in this bit mask is set<br/>
   *         {@code false}: if any flag in this bit mask is set
   */
  public boolean isEmpty()
  {
    return bitMask.isEmpty();
  }

As generics work in Java, an EnumBitMask object is completely ignorant of the enum value it represents. Therefore we can easily cast an EnumBitNask for one enum type to another one using the same object. So the next method basically does nothing and is only necessary to keep the compiler happy.

  /**
   * Cast this enum bit mask to one using a different kind of bit flags.
   * @param enumClass new enum bit flag class
   * @param <F> type of enum bit flag class
   * @return enum bit mask with same bit flags, but different enum flag type
   */
  @SuppressWarnings("unchecked")
  public <F extends Enum<F> & BitFlag> EnumBitMask<F> cast(@NotNull Class<F> enumClass)
  {
    // no need to create a new object, as this class is immutable,
    // and the casting is only necessary to keep the compiler happy
    return (EnumBitMask<F>)this;
  }

To avoid creating EnumBitMask objects representing the same value we cache already created values. The unique() methods return the cached values with the same flags set.

  /**
   * Get the unique object representing the given 16bit flags.
   * This is an optimization which shares all enum bit masks with 16 bits.
   * @return unique bitmask object representing the same flags as this one
   */
  @SuppressWarnings("unchecked")
  public EnumBitMask<E> unique16()
  {
    // cast is okay because all 16bit flag classes share the same underlying objects
    return getCachedEnumBitMask16(this);
  }

  /**
   * Get the unique object representing the given 32bit flags.
   * This is an optimization which shares many enum bit masks with 32 bits.
   * @return unique bitmask object representing the same flags as this one
   */
  @SuppressWarnings("unchecked")
  public EnumBitMask<E> unique32()
  {
    // cast is okay because all 16bit flag classes share the same underlying objects
    return getCachedEnumBitMask32(this);
  }

  /**
   * Convert a flag to a generic bit mask.
   *
   * This internally uses a bit set bit mask, which allows for all possible flags.
   * @param flag flag to convert
   * @param <F>  type of bit flag
   * @return bit mask where bit flag is set
   */
  public static <F extends Enum<F> & BitFlag> EnumBitMask<F> toMask(@NotNull F flag)
  {
    return new EnumBitMask<F>(flag.setIn(BitSetBitMask.ZERO));
  }

  /**
   * Convert a flag to a 16 bit bit mask.
   *
   * @param flag flag to convert
   * @param <F>  type of bit flag
   * @return bit mask where bit flag is set
   */
  public static <F extends Enum<F> & BitFlag> EnumBitMask<F> toMask16(@NotNull F flag)
  {
    return new EnumBitMask<F>(flag.setIn(BitMask16.ZERO)).unique16();
  }

  /**
   * Convert a flag to a 32 bit bit mask.
   *
   * @param flag flag to convert
   * @param <F>  type of bit flag
   * @return bit mask where bit flag is set
   */
  public static <F extends Enum<F> & BitFlag> EnumBitMask<F> toMask32(@NotNull F flag)
  {
    return new EnumBitMask<F>(flag.setIn(BitMask32.ZERO)).unique32();
  }

  /**
   * Convert a flag to a 64 bit bit mask.
   *
   * @param flag flag to convert
   * @param <F>  type of bit flag
   * @return bit mask where bit flag is set
   */
  public static <F extends Enum<F> & BitFlag> EnumBitMask<F> toMask64(@NotNull F flag)
  {
    return new EnumBitMask<F>(flag.setIn(BitMask64.ZERO));
  }

  /**
   * Divide a bit mask into a set of flags.
   * Only valid bits (i.e. bits which have a flag counterpart) will be considered.
   * @param mask bit mask
   * @param enumClass class of the enum flags in this mask, necessary to overcome
   *                  the shortcomings of Java generics
   * @param <F> type of bit flag
   * @return set of bit flags which are set in the given mask
   * @see #combine(Collection)
   * @see #combine16(Collection)
   * @see #combine32(Collection)
   * @see #combine64(Collection)
   */
  public static <F extends Enum<F> & BitFlag> Set<F> toFlags(@NotNull EnumBitMask<F> mask,
                                                             @NotNull Class<F> enumClass)
  {
    Set<F> result = EnumSet.noneOf(enumClass);
    for (F flag : enumClass.getEnumConstants()) {
      if (mask.isSet(flag)) {
        result.add(flag);
      }
    }
    return result;
  }

  /**
   * Combine some flags into a bit mask.
   * @param zero     zero bit mask fitting for the given type
   * @param bitFlags bit flags to combine
   * @param <F> enum flag type
   * @return combined mask
   */
  private static <F extends Enum<F> & BitFlag> EnumBitMask<F> combine(@NotNull BitMask zero,
                                                                      F[] bitFlags)
  {
    EnumBitMask<F> mask = new EnumBitMask<>(zero);
    for (F f  : bitFlags) {
      mask = mask.set(f);
    }
    return mask;
  }

  /**
   * Combine some flags into a bit mask.
   * @param zero     zero bit mask fitting for the given type
   * @param bitFlags bit flags to combine
   * @param <F> enum flag type
   * @return combined mask
   */
  private static <F extends Enum<F> & BitFlag> EnumBitMask<F> combine(@NotNull BitMask zero,
                                                                      @NotNull Collection<F> bitFlags)
  {
    EnumBitMask<F> mask = new EnumBitMask<>(zero);
    for (F f  : bitFlags) {
      mask = mask.set(f);
    }
    return mask;
  }

  /**
   * Combine bit flags using at maximum 16 bits into a bit mask.
   * @param bitFlags bit flags
   * @param <F>      bit flag type
   * @return bit mask
   * @see #get16(Enum[])
   */
  @SafeVarargs
  @SuppressWarnings("varargs")
  public static <F extends Enum<F> & BitFlag> EnumBitMask<F> combine16(F ... bitFlags)
  {
    return combine(BitMask16.ZERO, bitFlags);
  }

  /**
   * Combine bit flags using at maximum 16 bits into a bit mask.
   * @param bitFlags bit flags to combine
   * @param <F>      bit flag type
   * @return bit mask
   */
  public static <F extends Enum<F> & BitFlag> EnumBitMask<F> combine16(@NotNull Collection<F> bitFlags)
  {
    return combine(BitMask16.ZERO, bitFlags);
  }

  /**
   * Combine bit flags using at maximum 32 bits into a bit mask.
   * @param bitFlags bit flags
   * @param <F>      bit flag type
   * @return bit mask
   * @see #get32(Enum[])
   */
  @SafeVarargs
  @SuppressWarnings("varargs")
  public static <F extends Enum<F> & BitFlag> EnumBitMask<F> combine32(F ... bitFlags)
  {
    return combine(BitMask32.ZERO, bitFlags);
  }

  /**
   * Combine bit flags using at maximum 32 bits into a bit mask.
   * @param bitFlags bit flags to combine
   * @param <F>      bit flag type
   * @return bit mask
   */
  public static <F extends Enum<F> & BitFlag> EnumBitMask<F> combine32(@NotNull Collection<F> bitFlags)
  {
    return combine(BitMask32.ZERO, bitFlags);
  }

  /**
   * Combine bit flags using at maximum 64 bits into a bit mask.
   * @param bitFlags bit flags
   * @param <F>      bit flag type
   * @return bit mask
   */
  @SafeVarargs
  @SuppressWarnings("varargs")
  public static <F extends Enum<F> & BitFlag> EnumBitMask<F> combine64(F ... bitFlags)
  {
    return combine(BitMask64.ZERO, bitFlags);
  }

  /**
   * Combine bit flags using at maximum 64 bits into a bit mask.
   * @param bitFlags bit flags
   * @param <F>      bit flag type
   * @return bit mask
   */
  public static <F extends Enum<F> & BitFlag> EnumBitMask<F> combine64(@NotNull Collection<F> bitFlags)
  {
    return combine(BitMask64.ZERO, bitFlags);
  }

  /**
   * Combine bit flags using an arbitrary number of bits into a bit mask.
   * @param bitFlags bit flags
   * @param <F>      bit flag type
   * @return bit mask
   */
  @SafeVarargs
  @SuppressWarnings("varargs")
  public static <F extends Enum<F> & BitFlag> EnumBitMask<F> combine(F ... bitFlags)
  {
    return combine(BitSetBitMask.ZERO, bitFlags);
  }

  /**
   * Combine bit flags using an arbitrary number of bits into a bit mask.
   * @param bitFlags bit flags to combine
   * @param <F>      bit flag type
   * @return bit mask
   */
  public static <F extends Enum<F> & BitFlag> EnumBitMask<F> combine(@NotNull Collection<F> bitFlags)
  {
    return combine(BitSetBitMask.ZERO, bitFlags);
  }

  @Override
  @SuppressWarnings("unchecked")
  public boolean equals(Object o)
  {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }

    EnumBitMask<E> that = (EnumBitMask<E>)o;

    return bitMask.equals(that.bitMask);

  }

  @Override
  public int hashCode()
  {
    return bitMask.hashCode();
  }

  /**
   * Get a string representation.
   * @return string representiation
   */
  public String toString()
  {
    return bitMask.toString();
  }

As said earlier, theEnumBitMask object is completely ignorant of the enum it represents. In the following we create a useless class used as the enum in our constant or cached values. We’ll potentially cache all 65536 16bit values, although experience shows that most bit flags use only the lower bits. For 32bit values we will restrict ourselves to some lower bits, and accept that bit masks which high bits set don’t share their values. This is a tradeoff, and it depends on the usage whether caching or duplicating is better. The Java property "ebm.mask32.shift" allows to override the default using only the lower 16 bit. Long enum values are currently not cached, because in my scenario thay don’t appear.

  /** Have an enum for fooling the compiler. */
  private enum Potёmkin
    implements BitFlag
  {
    ;

    /**
     * Is this flag set in the given mask?
     *
     * @param mask bit mask
     * @return {@code true}: if the flag is set<br/>
     * {@code false}: if the flag is not set
     */
    @Override
    public boolean isSetIn(@NotNull BitMask mask)
    {
      return false;
    }

    /**
     * Set this flag in the given bit mask.
     *
     * @param mask bit mask
     * @return new bit mask where this flag is set
     */
    @NotNull
    @Override
    public BitMask setIn(@NotNull BitMask mask)
    {
      return mask;
    }

    /**
     * Clear this flag in the given bit mask.
     *
     * @param mask bit mask
     * @return new bit mask where this flag is cleared
     */
    @NotNull
    @Override
    public BitMask clearIn(@NotNull BitMask mask)
    {
      return mask;
    }
  }

  /** 16 bit mask with no flag set. */
  public static final EnumBitMask<?> NONE16 = new EnumBitMask<Potёmkin>(BitMask16.ZERO);
  /** 32 bit mask with no flag set. */
  public static final EnumBitMask<?> NONE32 = new EnumBitMask<Potёmkin>(BitMask32.ZERO);
  /** 64 bit mask with no flag set. */
  public static final EnumBitMask<?> NONE64 = new EnumBitMask<Potёmkin>(BitMask64.ZERO);

  /** Cached values using 16bit masks. */
  private static final Map<Short, EnumBitMask<?>> CACHE16 = new HashMap<>();
  static {
    CACHE16.put((short)0, NONE16);
    CACHE16.put((short)-1, new EnumBitMask<>(new BitMask16(-1)));
    /** Insert common values for and operation. */
    for (int shift = 1;  shift < 16;  ++shift) {
      final int value = (1 << shift) - 1;
      CACHE16.put((short)value, new EnumBitMask<>(new BitMask16(value)));
    }
  }

  /**
   * Get a cached 16bit mask for the given value.
   *
   * This is an optimization reducing created bit masks.
   *
   * @param <T> enum type
   * @param value value (an int only for convenience, only the low 16bits are used)
   * @param type  enum type of returned
   * @return matching bit mask
   */
  @NotNull
  public static <T extends Enum<T> & BitFlag> EnumBitMask<T> get16(int value, @NotNull Class<T> type)
  {
    final Short key = (short)value;
    synchronized (CACHE16) {
      EnumBitMask<?> mask = CACHE16.get(key);
      if (mask == null) {
        mask = new EnumBitMask<T>(new BitMask16(value));
        CACHE16.put(key, mask);
      }
      return mask.cast(type);
    }
  }

  /**
   * Get a cached 16bit mask for a combination of flags.
   *
   * This is an optimization reducing created bit masks.
   *
   * @param <T> enum type
   * @param flags flags to combine
   * @return matching bit mask
   */
  @SafeVarargs
  @NotNull
  @SuppressWarnings({"unchecked", "varargs"})
  public static <T extends Enum<T> & BitFlag> EnumBitMask<T> get16(T ... flags)
  {
    final EnumBitMask<T> mask = combine16(flags);
    return getCachedEnumBitMask16(mask);
  }

  /**
   * Get the cached value with the same settings as a given 16 bit mask.
   * @param mask bit mask using 16 bits
   * @param <T> bit flag type
   * @return cached mask
   */
  @NotNull
  @SuppressWarnings("unchecked")
  private static <T extends Enum<T> & BitFlag> EnumBitMask<T> getCachedEnumBitMask16(@NotNull EnumBitMask<T> mask)
  {
    final Short key = (short)mask.getBitMask().low32();
    synchronized (CACHE16) {
      final EnumBitMask<?> cachedMask = CACHE16.get(key);
      if (cachedMask == null) {
        CACHE16.put(key, mask);
        return mask;
      }
      // all enum bit masks with the same width and value are internally equal
      return (EnumBitMask<T>)cachedMask;
    }
  }

  /**
   * Get a cached 16bit mask for a combination of flags.
   *
   * This is an optimization reducing created bit masks.
   *
   * @param <T> enum type
   * @param mask  basic mask
   * @param flags flags to combine with mask
   * @return combined bit mask
   */
  @SafeVarargs
  @NotNull
  @SuppressWarnings("unchecked")
  public static <T extends Enum<T> & BitFlag> EnumBitMask<T> get16(@NotNull EnumBitMask<T> mask,
                                                                   T ... flags)
  {
    for (T flag : flags) {
      mask = mask.set(flag);
    }
    return getCachedEnumBitMask16(mask);
  }

  /** Cached values using 32bit masks. */
  private static final Map<Integer, EnumBitMask<?>> CACHE32 = new HashMap<>();
  static {
    CACHE32.put(0, NONE32);
    CACHE32.put(-1, new EnumBitMask<>(new BitMask32(-1)));
    /** Insert common values for and operation. */
    for (int shift = 1;  shift < 32;  ++shift) {
      final int value = (1 << shift) - 1;
      CACHE32.put(value, new EnumBitMask<>(new BitMask32(value)));
    }
  }

  /**
   * Get a cached 32bit mask for the given value.
   *
   * This is an optimization reducing created bit masks.
   *
   * @param <T> enum type
   * @param value value
   * @param type  enum type of returned
   * @return matching bit mask
   */
  @NotNull
  public static <T extends Enum<T> & BitFlag> EnumBitMask<T> get32(@NotNull Integer value, @NotNull Class<T> type)
  {
    synchronized (CACHE32) {
      EnumBitMask<?> mask = CACHE32.get(value);
      if (mask == null) {
        mask = new EnumBitMask<T>(new BitMask32(value));
        if ((value & EXCLUDE_MASK32) == 0) {
          CACHE32.put(value, mask);
        }
      }
      return mask.cast(type);
    }
  }

  /**
   * Get a cached 32bit mask for a combination of flags.
   *
   * This is an optimization reducing created bit masks.
   *
   * @param <T> enum type
   * @param flags flags to combine
   * @return matching bit mask
   */
  @SafeVarargs
  @NotNull
  @SuppressWarnings("varargs")
  public static <T extends Enum<T> & BitFlag> EnumBitMask<T> get32(T ... flags)
  {
    final EnumBitMask<T> mask = combine32(flags);
    return getCachedEnumBitMask32(mask);
  }

  /**
   * Get the cached value with the same settings as a given 16 bit mask.
   * @param mask bit mask using 16 bits
   * @param <T> bit flag type
   * @return cached mask
   */
  @NotNull
  @SuppressWarnings("unchecked")
  private static <T extends Enum<T> & BitFlag> EnumBitMask<T> getCachedEnumBitMask32(EnumBitMask<T> mask)
  {
    final Integer key = mask.getBitMask().low32();
    synchronized (CACHE32) {
      final EnumBitMask<?> cachedMask = CACHE32.get(key);
      if (cachedMask == null) {
        if ((key & EXCLUDE_MASK32) == 0) {
          CACHE32.put(key, mask);
        }
        return mask;
      }
      return (EnumBitMask<T>)cachedMask;
    }
  }

  /**
   * Get a cached 32bit mask for a combination of flags.
   *
   * This is an optimization reducing created bit masks.
   *
   * @param <T> enum type
   * @param mask  basic mask
   * @param flags flags to combine with mask
   * @return combined bit mask
   */
  @SafeVarargs
  @NotNull
  @SuppressWarnings("unchecked")
  public static <T extends Enum<T> & BitFlag> EnumBitMask<T> get32(@NotNull EnumBitMask<T> mask,
                                                                   T ... flags)
  {
    for (T flag : flags) {
      mask = mask.set(flag);
    }
    return getCachedEnumBitMask32(mask);
  }
}

Conclusion

That’s it. A lot of work, but now we can define and use enum bit flags in a typesafe way, although that’s still a bit of work, too. The inherent documentation and the typesafety is worth the effort in my feeling.

/** Old style */
public class Attribute
{
  /** Attribute flag: Attribute is invisible. */
  public static final int ATTRIBUTE_FLAG_INVISIBLE = 1;
  /** Attribute flag: Attribute is fixed. */
  public static final int ATTRIBUTE_FLAG_FIXED = 2;
  /** Attribute flag: Attribute should be checked during insertion. */
  public static final int ATTRIBUTE_FLAG_CHECK = 4;
  /** Attribute flag: Attribute is predefined. */
  public static final int ATTRIBUTE_FLAG_PREDEFINED = 8;

  private int attributeFlags;

  /**
   * Get the attribute flags.
   * @return combination of {@link #ATTRIBUTE_FLAG_INVISIBLE},
   *                        {@link #ATTRIBUTE_FLAG_FIXED},
   *                        {@link #ATTRIBUTE_FLAG_CHECK}, and
   *                        {@link #ATTRIBUTE_FLAG_PREDEFINED}
   */
  public int getAttributeFlags()
  {
    return attributeFlags;
  }

  /**
   * Set the attribute flags
   * @param flags combination of {@link #ATTRIBUTE_FLAG_INVISIBLE},
   *                             {@link #ATTRIBUTE_FLAG_FIXED},
   *                             {@link #ATTRIBUTE_FLAG_CHECK}, and
   *                             {@link #ATTRIBUTE_FLAG_PREDEFINED}
   */
  public void setAttributeFlags(int flags)
  {
    attributeFlags = flags;
  }
}

// Usage
int flags = attribute.getAttributeFlags();
if ((flags & Attribute.ATTRIBUTE_FLAG_INVISIBLE) == 0) {
  // show attribute
}
if ((flags & Text.TEXT_FLAG_UNDERLINED) != 0) {  // this should not be possible
  // underline
}

versus

/** New style. */
public class Attribute
{
  /** Attribute flags. */
  public enum Flags
          implements BitFlag
  {
    /** Attribute is invisible. */
    Invisible(0),
    /** Attribute is fixed. */
    Fixed(1),
    /** Attribute should be checked during insertion. */
    Check(2),
    /** Attribute is predefined. */
    Predefined(3);

    /** The attribute flags mask where all flags are unset. */
    public static final EnumBitMask<AttributeFlags>  NONE = EnumBitMask.NONE16.cast(AttributeFlags.class);
    /** The attribute flags mask where all flags are set. */
    public static final EnumBitMask<AttributeFlags>  ALL = EnumBitMask.get16(values());

    /** Wrapped real bit flag. */
    private final BitFlag flag;

    /**
     * Constructor.
     * @param flagIndex index of flag
     */
    AttributeFlags(int flagIndex)
    {
      flag = SimpleBitFlag.get(flagIndex);
    }

    /**
     * Is this flag set in the given mask?
     *
     * @param mask bit mask
     * @return {@code true}: if the flag is set<br/>
     * {@code false}: if the flag is not set
     */
    @Override
    public boolean isSetIn(@NotNull BitMask mask)
    {
      return flag.isSetIn(mask);
    }

    /**
     * Set this flag in the given bit mask.
     *
     * @param mask bit mask
     * @return new bit mask where this flag is set
     */
    @NotNull
    @Override
    public BitMask setIn(@NotNull BitMask mask)
    {
      return flag.setIn(mask);
    }

    /**
     * Clear this flag in the given bit mask.
     *
     * @param mask bit mask
     * @return new bit mask where this flag is cleared
     */
    @NotNull
    @Override
    public BitMask clearIn(@NotNull BitMask mask)
    {
      return flag.clearIn(mask);
    }

    /**
     * Get the enum bit mask associated with a given internal value.
     * @param internalValue internal value (only the lower 16 bits are used)
     * @return associated bit mask
     */
    @NotNull
    public static EnumBitMask<AttributeFlags> fromInternal(int internalValue)
    {
      return EnumBitMask.get16(internalValue, AttributeFlags.class);
    }
  }

  @NotNull
  private EnumBitMask<Flags> attributeFlags = Flags.NONE;

  /**
   * Get the attribute flags.
   * @return attribute flags
   */
  @NotNull
  public EnumBitMask<Flags> getAttributeFlags()
  {
    return attributeFlags;
  }

  /**
   * Set the attribute flags.
   * @param flags attribute flags
   */
  public void setAttributeFlags(@NotNull EnumBitMask<Flags> flags)
  {
    attributeFlags = flags;
  }
}

// Usage
EnumBitMask<Attribute.Flags> flags = attribute.getAttributeFlags();
if (!flags.isSet(Attribute.Flags.Invsible)) {
  // display attribute
}
if (flags.isSet(Text.Flags.Underline)) { // this will give a compiler error
  // underline
}

If you are interested: the complete implementation is contained in the free de·caff Commons in module caff-commons. Javadoc documentation of the above classes is also available under