Skip to content

Instantly share code, notes, and snippets.

@blaz-kranjc
Created October 26, 2017 13:19
Show Gist options
  • Save blaz-kranjc/1e22e6dc6bb0807ceb49c6f6df9cb3bf to your computer and use it in GitHub Desktop.
Save blaz-kranjc/1e22e6dc6bb0807ceb49c6f6df9cb3bf to your computer and use it in GitHub Desktop.
Trying to make DRY Enum bitsets
package low.level.stuff;
import java.lang.reflect.InvocationTargetException;
import java.util.EnumSet;
import java.util.Set;
interface EnumBitsetGeneric<T extends Enum<T> & EnumBitsetGeneric<T>> { // Actually as none of this works EnumBitset does not need to be generic
int getBitPosition();
//byte valueOf(Set<T> flags); // Cannot do this, as I want this method to be static
//Set<T> flagsOf(byte value); // Cannot do this, as I want this method to be static
//static byte valueOf(Set<T> flags) {...} // Cannot do this... same for flagsOf
}
enum EnumBitsetOne implements EnumBitsetGeneric<EnumBitsetOne> {
BIT0(0),
BIT1(1),
BIT2(2);
private final int bitPosition;
EnumBitsetOne(final int bitPosition) {
this.bitPosition = bitPosition;
}
@Override
public int getBitPosition() {
return bitPosition;
}
public static byte valueOf(final Set<EnumBitsetOne> flags) {
// I don't like this, I'm duplicating the code in every BitsetEnum
byte value = 0;
for (final EnumBitsetOne flag : flags) {
value |= (1 << flag.getBitPosition());
}
return value;
}
public static Set<EnumBitsetOne> flagsOf(final byte value) {
// I don't like this, I'm duplicating the code in every BitsetEnum
final EnumSet<EnumBitsetOne> flags = EnumSet.noneOf(EnumBitsetOne.class);
for (final EnumBitsetOne mode : EnumBitsetOne.values()) {
final long modeValue = 1 << mode.getBitPosition();
if ((value & modeValue) == modeValue) {
flags.add(mode);
}
}
return flags;
}
}
class EnumBitsetHelper {
private EnumBitsetHelper() { /* Only contains static methods */ }
public static <T extends Enum<T> & EnumBitsetGeneric<T>> byte valueOf(final Set<T> flags) {
byte value = 0;
for (final T flag : flags) {
value |= (1 << flag.getBitPosition());
}
return value;
}
//public static <T extends Enum<T> & EnumBitsetGeneric<T>> Set<T> flagsOf(final byte value) {
// final EnumSet<T> flags = EnumSet.noneOf(T.class); // This is not possible
// for (final T mode : T.values()) { // Cannot get to the values
// final long modeValue = 1 << mode.getBitPosition();
// if ((value & modeValue) == modeValue) {
// flags.add(mode);
// }
// }
// return flags;
//}
public static <T extends Enum<T> & EnumBitsetGeneric<T>> Set<T> flagsOf(final byte value, Class<T> clazz)
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
final EnumSet<T> flags = EnumSet.noneOf(clazz); // Without clazz I have no idea what to do
Object enumValues = clazz.getMethod("values").invoke(null);
final T[] values = (T[]) enumValues; // I don't really know how to check instanceof with generics, I need Class<T[]> which I cannot get again
for (final T mode : values) {
final long modeValue = 1 << mode.getBitPosition();
if ((value & modeValue) == modeValue) {
flags.add(mode);
}
}
return flags;
}
}
class Main {
public static void main(String[] args)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
EnumSet<EnumBitsetOne> flags = EnumSet.allOf(EnumBitsetOne.class);
Set<EnumBitsetOne> flags_helper = EnumBitsetHelper.flagsOf(EnumBitsetHelper.valueOf(flags), EnumBitsetOne.class);
EnumBitsetOne.flagsOf(EnumBitsetHelper.valueOf(flags))
.forEach( flag -> System.out.println(flags_helper.contains(flag)));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment