Find out if an int contains an element from an enum set using binary operations

1

I am using a library that concatenates one or more enums by ORing their values like this:

    TestEnum {
        VAL1(0x00000001),
        VAL2(0x00000002),
        VAL3(0x00000100),
        VAL4(0x00000200),
        VAL5(0x00000400),
        VAL6(0x00000800),
        VAL7(0x00001000),
        VAL8(0x00002000),
        VAL9(0x00004000),
        VAL10(0x00008000),

        // special values
        VAL11(0x00000000),
        VAL12(0x00000010),
        VAL13(0x00000020),
        VAL14(0x00000030);

        private static final Map<Integer, TestEnum> TEST_ENUM_MAP;

        // constructor, populate map etc.

        public static TestEnum fromValue(final int value) {
            return TEST_ENUM_MAP.get(value);
        }
    }

    int valuesAsInt = 0;

    for (TestEnum testEnum : TestEnum.values()) {
        valuesAsInt |= testEnum.getValue();
    }

I need to extract the enums that were combined to produce valueAsInt keeping in mind that:

  • The int MUST contain one of the special enum values (0x00000000...0x00000030)
  • The int can contain zero or more of the non-special enum values.

This is what I did:

 private static final int MASK_FOR_SPECIAL_ENUMS = 0x000000FF;

 private static final ImmutableSet<TestEnum> SPECIAL_ENUMS = ImmutableSet.copyOf(Sets.newHashSet(TestEnum.VAL11, TestEnum.VAL12, TestEnum.VAL13, TestEnum.VAL14));

 private void lookupTestEnums(final int valueAsInt) {

      TestEnum testEnum = TestEnum.fromValue(valueAsInt & MASK_FOR_SPECIAL_ENUMS);
    if (testEnum == null || !SPECIAL_ENUMS.contains(testEnum)) {
        throw new ExceptionType("");
    }
 }

Just ANDing with the mask isn't sufficient because it'll return positive results for TestEnum values, VAL1 (0x00000001) etc.

Is there a better way of doing this?

java
enums
binary-operators
asked on Stack Overflow Feb 28, 2017 by user1071840

2 Answers

3

It appears that your MASK_FOR_SPECIAL_ENUMS must be equal to 0x000000F0, not 0x000000FF.

Then, after checking for validity, your lookup method needs to loop through values VAL1 through VAL10, and collect those that match.

In other words, something like this:

private static final int SPECIAL_MASK = 0x000000F0;

int specialValue = valueAsInt & SPECIAL_MASK;
int nonSpecialBits = valueAsInt & ~SPECIAL_MASK;
for (TestEnum testEnum : TestEnum.values()) 
{
    int value = testEnum.getValue();
    if( (value & SPECIAL_MASK) != 0 )
        continue; //this is one of the special values; ignore.
    if( (value & nonSpecialBits) == value )
        collection.add( testEnum );
}
answered on Stack Overflow Feb 28, 2017 by Mike Nakis • edited Mar 8, 2017 by Mike Nakis
0

Your question does not state that there can be only one special value; it states there must be one, which is another way of saying at least one, so it is not possible to do what you want, because:

0x00000010 | 0x00000020 == 0x00000030

Once 0x00000010 and 0x00000020 have been accumulated in the collective OR value, the value will be indistinguishable from an accumulated value that has 0x00000030 in it.


However, if the special value was 0x00000040, a simple bit-mask would work.

answered on Stack Overflow Feb 28, 2017 by Bohemian • edited Feb 28, 2017 by Bohemian

User contributions licensed under CC BY-SA 3.0