Question

I have an enum with 8 bit shifted values. I would like to be able to determine how far apart any two values are. This would be simple if the values were simply increasing integers. Here is what I've got for now.

typedef NS_ENUM(NSInteger, TestEnum) {
    TestEnumValue1 = 1 << 0,
    ...
    TestEnumValue8 = 1 << 7
};

TestEnum left = TestEnumValue8;
TestEnum right = TestEnumValue3;

TestEnum high = MAX(left, right);
TestEnum low = MIN(left, right);

int distance = 0;
int maximumEnum = 8;
int cumulativeResult = high;
for (int i = 0; i < maximumEnum; i++) 
{
    cumulativeResult = cumulativeResult / 2;
    if (cumulativeResult == low)
    {
        distance = i;
        break;
    }
}
NSLog (@"Distance is %d", distance);

The above seems to be working well, but is it the best way?

Était-ce utile?

La solution

Ignoring whether using an enum is appropriate or not, try this:

TestEnum left = TestEnumValue8;
TestEnum right = TestEnumValue3;

TestEnum high = MAX(left, right);
TestEnum low = MIN(left, right);

int distance = 0;
while (low < high) {
    low <<= 1;
    distance++;
}

NSLog (@"Distance is %d", distance);

Keep in mind that this only works if both left and right have a single "flag" set.

Autres conseils

Here's a potential solution: Add the two (positive) integers and count the zero bits between the one bits. The commutativity of addition obviates the fiddly need to figure out which operand is bigger.

int distance;
int k = left + right;
int started = 0;
while (k > 1) {
        if (!started && (k & 1)) {
                started = 1;
                distance = 0;
        }
        if (started) distance++;
        k >>= 1;
}

printf("%d\n", distance);

I hacked together something nasty, but which sort of works and allows use of enum values that aren't contiguous powers-of-2. The following is the 'enum' definition, with the actual enum values being defined in the DEFINE_MYENUM(x,y) statements:

#include <cmath>
#include <map>

class Value {
public:
    virtual operator int() const = 0;
    int getIndex() const { return index; }

    static const Value& fromValue(int val)
    {
        return *(getReverseMap().find(val)->second);
    }

protected:
    int index;
    static int getNextIndex() {
        static int curIndex = 0;
        return curIndex++;
    }
    static std::map<int, Value*>& getReverseMap() {
        static std::map<int, Value*> reverseMap = std::map<int, Value*>();
        return reverseMap;
    }
};

template<int y> class ValueImpl : Value {
public:
    ValueImpl() {
        index = Value::getNextIndex();
        Value::getReverseMap()[y] = this;
    }
    virtual operator int() const override { return y; }
};

#define DEFINE_MYENUM(NAME, VALUE) const ValueImpl<VALUE> NAME
class MyEnumDefs {
public:
    DEFINE_MYENUM(Value1, 2);
    DEFINE_MYENUM(Value2, 4);
    DEFINE_MYENUM(Value3, 8);
    DEFINE_MYENUM(Value4, 16);
    DEFINE_MYENUM(Value5, 20);
    DEFINE_MYENUM(Value6, 25);

    int distance(const Value& x, const Value& y) {
        return std::abs(x.getIndex() - y.getIndex());
    }
    int distance(int x, int y) {
        const Value& xx = Value::fromValue(x);
        const Value& yy = Value::fromValue(y);
        return distance(xx, yy);
    }
};
#undef DEFINE_MYENUM

class MyEnum {
public:
    static MyEnumDefs& inst() {
        static MyEnumDefs internalInst = MyEnumDefs();
        return internalInst;
    }
};
#define MyEnum MyEnum::inst()

The following is the test code:

int main(int argc, const char * argv[])
{
    int a = MyEnum.Value1;
    int b = MyEnum.Value2;
    int c = MyEnum.Value3;
    int d = MyEnum.Value4;
    int e = MyEnum.Value5;
    int f = MyEnum.Value6;
    printf("a b c d e f: %d %d %d %d %d %d\n", a, b, c, d, e, f);

    printf("Distance b d: %d\n", MyEnum.distance(b, d));
    printf("Distance d b: %d\n", MyEnum.distance(d, b));

    printf("Distance e f: %d\n", MyEnum.distance(e, f));
    return 0;
}

Output:

a b c d e f: 2 4 8 16 20 25
Distance b d: 2
Distance d b: 2
Distance e f: 1

Obviously this is not perfect, e.g. syntax MyEnum.XXX instead of XXX or MyEnum::XXX, lack of ability to use 'MyEnum' as a type etc... but figured it's a good start on something that could be pretty neat :)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top