1

Given a binary string coded on 1 byte, is it possible to map several of that byte's bits into an enum value ?
e.g. : suppose I want to cut my field into this :

  • bit1 and bit2 = field1
  • bit3 = field2
  • bit4 = field3
  • bit5 = field4
  • other bits are unused

How could I map that to, say :

public enum MyEnum {
    FIELD1, FIELD2, FIELD3, FIELD4;

    private static final EnumSet<MyEnum> ALLFIELDS = EnumSet.allOf(MyEnum.class);

}

What I'm trying to do is to filter out these enum values using a bitmask. For that, I did the following method :

public static <E extends Enum<E>> EnumSet<E> filterWithBitMask(EnumSet<E> set, int bitmask) {
    List<E> kept = new ArrayList<E>();
    for (E property : set) {
        if ((bitmask & (1 << ((Enum<E>) property).ordinal())) != 0) {
            kept.add(property);
        }
    }
    EnumSet<E> selectedProperties = set.clone();
    selectedProperties.retainAll(kept);
    return selectedProperties;
}

This works fine as long as my enum fields represent a single bit, but I can't figure out how to combine them into a single field. Sorry if that looks obvious, but this is the first time I'm manipulating data at the bit level...

EDIT COMMENTS : I edited the field structure to represent what I really have. So the only field that spans more than 1 bit is field1. Based on the presence of bit1 and bit2, I assign an weight variable to field1.

public enum MyByte {    
    BIT_1, BIT_2, BIT_3, BIT_4, BIT_5;

    private static final EnumSet<MyByte> ALLPROPERTIES = EnumSet.allOf(MyByte.class);

    public static EnumSet<Fields> getValues(int bitmask) {
        EnumSet<MyByte> selectedBits = filterWithBitMask(ALLPROPERTIES, bitmask);
        int weight = 0;
        EnumSet<Fields> fields = null;
        if (selectedBits.contains(BIT_1)) 
            weight += 1;
        if (selectedBits.contains(BIT_2))
            weight += 2;
        if (selectedBits.contains(BIT_1) || selectedBits.contains(BIT_2)) 
            fields = EnumSet.of(Fields.FIELD1.setValue(weight));
        if (selectedBits.contains(BIT_3)) {
            if (fields != null)
                fields.add(Fields.FIELD2);
            else fields = EnumSet.of(Fields.FIELD2);
        }
        if (selectedBits.contains(BIT_4)) {
            if (fields != null)
                fields.add(Fields.FIELD3);
            else fields = EnumSet.of(Fields.FIELD3);
        }

        if (selectedBits.contains(BIT_5)) {
            if (fields != null)
                fields.add(Fields.FIELD4);
            else fields = EnumSet.of(Fields.FIELD4);
        }

        return fields;
    }

    public enum Fields {

        // BIT_1 and BIT_2
        FIELD1,
        // BIT_3
        FIELD2,
        // BIT_4
        FIELD3,
        // BIT_5
        FIELD4;

        private int value;

        public Fields setValue(int i) {
            this.value = i;
            return this;
        }

    }


}

Here is the dirty solution I came up with for now, but I don't really like it with all those if statements. If someone has a better solution, I'd be glad to change this ;-)

Thanks !

Philippe
  • 6,703
  • 3
  • 30
  • 50
  • 1
    Why are you using 3 bits for field3? Do you mean field3 can hold up to 8 different values? – Mister Smith Sep 07 '11 at 14:53
  • 1
    If field1 has 2 bits, then it can hold 4 possible values (00, 01, 10, 11). An enum is not the proper representation unless you define 4 enum values, one for each combination of 2 bits. Ditto for field3 and field4. – Jim Garrison Sep 07 '11 at 14:55
  • @Jim Garrison Maybie I'll try with an outer enum containing 8 fields (1 for each bit), and an inner enum containing my fields... – Philippe Sep 07 '11 at 15:25
  • 1
    It seems like each of your 4 fields needs its own enum. You need a method to extract the bits into 4 integer fields, then each field would me mapped to its own enum. – Gilbert Le Blanc Sep 07 '11 at 15:55
  • It would be far easier if you forget the enums and just define the masks and values to test agaist with bitwise OR: `intToCheck | MASK == VALUE` – Mister Smith Sep 08 '11 at 08:33

1 Answers1

2

not quite sure what you want. this might be of interest:

import java.util.*;
enum Field {
    field1((byte) 0xc0) {
        int filter_(byte mask) { // you may want this one to be different
            return mask & this.mask;
        }
    },
    field2((byte) 0x20), field3((byte) 0x10), field4((byte) 0x08);
    Field(byte mask) {
        this.mask = mask;
    }
    int filter_(byte mask) {
        return mask & this.mask;
    }
    static EnumSet<Field> filter(byte mask) {
        final EnumSet<Field> fields = EnumSet.noneOf(Field.class);
        for (Field field : values())
            if (field.filter_(mask) != 0) fields.add(field);
        return fields;
    }
    final byte mask;
}
public class Main {
    public static void main(String[] args) {
        for(Field field:Field.values()) {
            System.out.println(Field.filter(field.mask));
        }
    }
}
Ray Tayek
  • 9,841
  • 8
  • 50
  • 90