!!!!! There is now a project with much better code than this !!!!! http://claude-martin.ch/enumbitset/ I made this because enums can not easily be stored to bit fields. Set and bitwise operations are equally difficult. I put this on pastebin because it's just one single interface. I will edit this paste if I change anything. Maybe I'll put in on a repository later. Note that I didn't really test this! You can use it for whatever you want. There is no copyright. But it would be nice if you would keep my name in the file. ----------------- package ch.claude_martin.java8; import java.math.BigInteger; import java.util.Arrays; import java.util.BitSet; import java.util.EnumSet; import java.util.Set; /** * This adds support to use bit fields and bit masks for the enym type. The set * of enum values is interpreted as a bit set, which can be stored to a bit * field. * *

* Since this is an interface it does not change the state of the element it is * used on or any parameters. Instead it always returns a newly created object. * I.e. all methods that take a Set return a new Set. If you wish to alter the * set you can simply use the methods of that set. * *

* Bit fields are by default of type {@link BigInteger}, but {@link BitSet} and * {@link Long long} can be used as well. Bit masks should not be stored into a * database unless you can guarantee that no changes are made in the future. The * only change that would not break your code is to add new enums at the end of * the list of existing enums. Note that {@link EnumSet} and {@link BigInteger} * already has many methods to help using sets of enums and large integers. * *

* A bit field is always used to store a set of bits. Each bit can represent one * enum value. each enum has a distinct {@link #bitmask() bit mask}. * *

* Java 8 Beta has still a bug that does not allow assert statements in * interfaces: https:/ * /bugs.openjdk.java.net/browse/JDK-8025141 * *

* Nomenclature: *

*
enum type
*
Any type that is an enum. I.e. it uses "enum" insteaf of "class" in its * declaration.
* Example: Planet.class
*
enum
*
A field of an enumy type. This is one single value of any enum type.
* Example: Planet.VENUS
*
* Example: * *
* public enum Planet { * MERCURY, VENUS, EARTH, ... * } *
*

* The goal of this interface is to use only existing types. Since all primitive * types are limited this uses {@link BigInteger} instead. * * @author Claude Martin * * @param * The Enum-Type. */ public interface EnumBitOperations> { /** * Returns whether this enum can be found in the list of enums of the same * type. * * @returns true, if this can be found. */ public default boolean elementOf(final Enum... set) { for (final Enum e : set) if (e == this) return true; return false; } /** * Returns whether this enum can be found in the set of enums of the same * type. *

* This is equivalent to: * set.contains(this); * * * @returns true, if this can be found. */ public default boolean elementOf(final Set> set) { return set.contains(this); } /** * Creates a new EnumSet with this added. * * @returns A new {@link EnumSet} including all given elements and also * this. */ @SuppressWarnings("unchecked") public default EnumSet addTo(final E... set) { final EnumSet result = EnumSet.copyOf(Arrays.asList(set)); result.add((E) this); return result; } /** * Creates a new EnumSet with this added. * * @returns A new {@link EnumSet} including all elements of the set and also * this. */ @SuppressWarnings("unchecked") public default EnumSet addedTo(final EnumSet set) { final EnumSet result = EnumSet.copyOf(set); result.add((E) this); return result; } /** * Creates a new EnumSet with this removed. * * @returns A new {@link EnumSet} with all given enums, except * this. A copy of the set is returned if * this is not present. */ @SuppressWarnings("unchecked") public default EnumSet removedFrom(final E... set) { final EnumSet result = EnumSet.copyOf(Arrays.asList(set)); result.remove(this); return result; } /** * Creates a new EnumSet with this removed. * * @returns A new {@link EnumSet} with all elements of the set, except * this. A copy of the set is returned if * this is not present. */ public default EnumSet removedFrom(final EnumSet set) { final EnumSet result = EnumSet.copyOf(set); result.remove(this); return result; } /** * Returns a set of all enums except this. * *

* This is equivalent to: EnumSet.complementOf(this.asSet()) * * @returns A new {@link EnumSet} with all elements except this. */ @SuppressWarnings("unchecked") public default EnumSet others() { final E e = (E) this; final EnumSet result = EnumSet.allOf(e.getClass()); result.remove(e); return result; } /** * Returns a set containing nothing but this. * * @returns A new {@link EnumSet} containing this. */ @SuppressWarnings("unchecked") public default EnumSet asEnumSet() { final E e = (E) this; final EnumSet result = EnumSet.noneOf(e.getClass()); result.add(e); return result; } /** * Returns a BitSet with all bits set to 0, except the bit representing * this. * * @returns A new {@link EnumSet} containing this. */ @SuppressWarnings("unchecked") public default BitSet asBitSet() { final E e = (E) this; final BitSet result = new BitSet(); result.set(e.ordinal()); return result; } /** * Bitmask for this. The value is based on the ordinal. * * @return 1<<this.ordinal() * @deprecated This is actually the same as {@link #bitmask()}. This is here * so that programmers will find and use {@link #bitmask()}. */ @Deprecated public default BigInteger asBigInteger() { return this.bitmask(); } /** * 64 bit bitmask for this. The value is based on the ordinal. * * @return 1<<this.ordinal() */ @SuppressWarnings("unchecked") public default long bitmask64() { final E e = (E) this; // assert EnumSet.allOf(e.getClass()).size() <= 64; return 1 << e.ordinal(); } /** * Bitmask for this. The value is based on the ordinal. * * @return 1<<this.ordinal() */ @SuppressWarnings("unchecked") public default BigInteger bitmask() { final E e = (E) this; return BigInteger.ONE.shiftLeft(e.ordinal()); } /** * Returns whether this value is set in the given bitmask. * * @param bitmask64 * A bitmask. * @return (this.bitmask64() & bitmask8) != 0; */ public default boolean elementOf(final long bitmask64) { return (this.bitmask64() & bitmask64) != 0; } /** * Returns whether this value is set in the given bitmask. * * @param bitmask * A bitmask. * @return (this.bitmask() & bitmask) != 0 */ public default boolean elementOf(final BigInteger bitmask) { return !this.bitmask().and(bitmask).equals(BigInteger.ZERO); } /** * Returns whether this value is set in the given bitset. * * @param bitset * @return bitset.get(this.ordinal()); */ @SuppressWarnings("unchecked") public default boolean elementOf(final BitSet bitset) { return bitset.get(((E) this).ordinal()); } /** Creates a 64 bit bitmask of a given set of enums. */ public static & EnumBitOperations> long toBitmask64(final EnumSet set) { long result = 0; for (final X e : set) result |= e.bitmask64(); return result; } /** Creates a 64 bit bitmask of a given set of enums. */ @SafeVarargs public static & EnumBitOperations> long toBitmask64(final X... set) { long result = 0; for (final X e : set) result |= e.bitmask64(); return result; } /** Creates a bitmask of a given set of enums. */ public static & EnumBitOperations> BigInteger toBitmask(final EnumSet set) { BigInteger result = BigInteger.ZERO; for (final X e : set) result = result.or(e.bitmask()); return result; } /** Creates a bitmask of a given set of enums. */ @SafeVarargs public static & EnumBitOperations> BigInteger toBitmask(final X... set) { BigInteger result = BigInteger.ZERO; for (final X e : set) result = result.or(e.bitmask()); return result; } /** * Creates a BitSet of a given set of enums. * */ @SafeVarargs public static & EnumBitOperations> BitSet toBitSet(final X... set) { final BitSet result = new BitSet(); for (final X e : set) result.set(e.ordinal()); return result; } /** * Creates a BitSet of a given set of enums. */ public static & EnumBitOperations> BitSet toBitSet(final EnumSet set) { final BitSet result = new BitSet(); for (final X e : set) result.set(e.ordinal()); return result; } /** Creates a BitSet of a given mask. */ public static BitSet toBitSet(final BigInteger mask) { return BitSet.valueOf(mask.toByteArray()); } /** Creates a BigInteger of a given mask. */ public static BigInteger toBigInteger(final BitSet bitset) { return new BigInteger(bitset.toByteArray()); } /** Creates set of enums from a 64 bit bitset. */ public static & EnumBitOperations> EnumSet toEnumSet(final long mask, final Class type) { final EnumSet result = EnumSet.noneOf(type); for (final X e : EnumSet.allOf(type)) if ((e.bitmask64() & mask) != 0) result.add(e); return result; } /** Creates set of enums from a BitSet. */ public static & EnumBitOperations> EnumSet toEnumSet(final BitSet bitset, final Class type) { long mask = 0L; for (int i = 0; i < bitset.length(); ++i) mask += bitset.get(i) ? 1L << i : 0L; return EnumBitOperations.toEnumSet(mask, type); } /** * Takes the bitmasks of this and all arguments, then applies * logical OR to all. This results in a bitmask for all given enums (including * this). * * @see #or(Enum...) * @see EnumSet#of(Enum) * @return this.bitmask64() | arg0.bitmask64() | ... | argN.bitmask64() */ @SuppressWarnings("unchecked") public default & EnumBitOperations> long or64(final X... set) { long result = this.bitmask64(); for (final X e : set) result |= 1 << e.ordinal(); return result; } /** * * Note that there is a much simpler way using {@link EnumSet#of(Enum) * of(...)}. The following expressions define the same set:
* Planet.EARTH.or(Planet.MARS, Planet.JUPITER)
* Planet.of(Planet.EARTH, Planet.MARS, Planet.JUPITER)
*
* However, this method returns a bitmask of type BigInteger. * * @see EnumSet#of(Enum) * @see #or(BigInteger) * @return this.bitmask() | arg0.bitmask() | ... | argN.bitmask() */ @SuppressWarnings("unchecked") public default & EnumBitOperations> BigInteger addedTo(final X... set) { BigInteger result = this.bitmask(); for (final X e : set) result = result.or(e.bitmask()); return result; } /** * Takes the bitmasks of this and mask, then applies * logical OR. This results in a new bitmask that also includes * this. * * @see #addedTo(BigInteger) * @see #addedTo(EnumSet) * @see #addedTo(Enum...) * @return mask.or(this.bitmask()) */ public default & EnumBitOperations> BigInteger or(final BigInteger mask) { return mask.or(this.bitmask()); } /** * @return mask.and(this.bitmask()) */ public default & EnumBitOperations> BigInteger and(final BigInteger mask) { return mask.and(this.bitmask()); } /** * @return mask.xor(this.bitmask()) */ public default & EnumBitOperations> BigInteger xor(final BigInteger mask) { return mask.xor(this.bitmask()); } /** * Removes this from mask, but only if its bit is set in the mask. * * @return mask.andNot(this.bitmask()) */ public default & EnumBitOperations> BigInteger removedFrom(final BigInteger mask) { return mask.andNot(this.bitmask()); } }