I've been twiddling a lot of bits with MINA and got tired of it so I
created a utility class that converts instances of EnumSet to bit
vectors and vice-versa.
I thought this feature would be a good addition to MINA's ByteBuffer.
Instead of just committing the change, I wanted to run the idea past the
MINA community since ByteBuffer is such an integral part of the MINA
framework. I propose adding the following to
org.apache.mina.common.ByteBuffer in TRUNK:
public <E extends Enum<E>> EnumSet<E> getEnumSet(Class<E> enumClass)
{
return toEnumSet(enumClass, (long)get() & 0xFFL);
}
public <E extends Enum<E>> EnumSet<E> getEnumSetShort(Class<E>
enumClass) {
return toEnumSet(enumClass, ((long)getShort()) & 0xFFFFL);
}
public <E extends Enum<E>> EnumSet<E> getEnumSetInt(Class<E>
enumClass) {
return toEnumSet(enumClass, (long)getInt() & 0xFFFFFFFFL);
}
public <E extends Enum<E>> EnumSet<E> getEnumSetLong(Class<E>
enumClass) {
return toEnumSet(enumClass, getLong());
}
private <E extends Enum<E>> EnumSet<E> toEnumSet(Class<E> enumClass,
long vector) {
EnumSet<E> set = EnumSet.noneOf(enumClass);
long mask = 1;
for (E e : enumClass.getEnumConstants()) {
if ((mask & vector) == mask) {
set.add(e);
}
mask <<= 1;
}
return set;
}
public <E extends Enum<E>> void putEnumSet(EnumSet<E> set) {
put((byte)toLong(set));
}
public <E extends Enum<E>> void putEnumSetShort(EnumSet<E> set) {
putShort((short)toLong(set));
}
public <E extends Enum<E>> void putEnumSetInt(EnumSet<E> set) {
putInt((int)toLong(set));
}
public <E extends Enum<E>> void putEnumSetLong(EnumSet<E> set) {
putLong(toLong(set));
}
private <E extends Enum<E>> long toLong(EnumSet<E> s) {
long vector = 0;
for (E e : s) {
vector |= 1L << e.ordinal();
}
return vector;
}
It works like this. Suppose I have a protocol that uses an integer
sized (32-bit) bit mask to send 32 boolean values. Instead of masking
off each bit to see if it's set or not, I create an enum that represents
each value in the mask like:
public enum MaskValues {
VALUE_1, // 0x00000001
VALUE_2, // 0x00000002
...,
VALUE_31, // 0x40000000
VALUE_32 // 0x80000000
}
I then do:
EnumSet<MaskValues> values = buf.getEnumSetInt(MaskValues.class);
To see if any bit is set I can do values.contains(MaskValues.VALUE_XX)
or to see if a group of bits are set I can do
values.containsAll(EnumSet.of(MaskValues.VALUE_XX, MaskValues.VALUE_YY))
and so on. This is much easier to read then:
int bitVector = buf.getInt();
if (bitVector & mask == mask) { do something }
The putXXXX methods provide a mechanism for putting an EnumSet into the
ByteBuffer as a bit vector.
If this functionality is desired, I'll add some Java Docs to the above
methods and commit my code and accompanying unit tests.
-Mike