Come posso combinare 2 bit in un singolo campo usando un enumset?
-
27-10-2019 - |
Domanda
Dato una stringa binaria codificata su 1 byte, è possibile mappare molti dei bit di quel byte in un valore enum?
EG: Supponi di voler tagliare il mio campo in questo:
- bit1 e bit2 = field1
- bit3 = field2
- bit4 = field3
- bit5 = field4
- Altri bit sono inutilizzati
Come potrei mapparlo a, dire:
public enum MyEnum {
FIELD1, FIELD2, FIELD3, FIELD4;
private static final EnumSet<MyEnum> ALLFIELDS = EnumSet.allOf(MyEnum.class);
}
Quello che sto cercando di fare è filtrare questi valori enum usando una maschera bit. Per questo, ho fatto il seguente metodo:
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;
}
Funziona bene fintanto che i miei campi enum rappresentano un singolo bit, ma non riesco a capire come combinarli in un singolo campo. Scusa se sembra ovvio, ma questa è la prima volta che manipolo i dati a livello di bit ...
Modifica commenti: ho modificato la struttura sul campo per rappresentare ciò che ho veramente. Quindi l'unico campo che copre più di 1 bit è Field1. Sulla base della presenza di Bit1 e Bit2, assegno una variabile di peso a 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;
}
}
}
Ecco la soluzione sporca che mi è venuta in mente per ora, ma non mi piace molto con tutte quelle dichiarazioni IF. Se qualcuno ha una soluzione migliore, sarei felice di cambiarlo ;-)
Grazie !
Soluzione
Non sono sicuro di quello che vuoi. Questo potrebbe essere di interesse:
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));
}
}
}