Created
October 26, 2017 13:19
-
-
Save blaz-kranjc/1e22e6dc6bb0807ceb49c6f6df9cb3bf to your computer and use it in GitHub Desktop.
Trying to make DRY Enum bitsets
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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