Handmade Network»Forums
235 posts
How to get a flag's position from an enum
Edited by longtran2904 on

In C, it's common to declare an enum as a bunch of flags:

typedef u32 MyFlags;
enum
{
    A = 1 << 0, // 1
    B = 1 << 1, // 2
    C = 1 << 2, // 4
};

Is there any way to get back the flag's position from these enums at compile time?

GetFlagPos(A) // 0
GetFlagPos(B) // 1
GetFlagPos(C) // 2
// not 1, 2, 4

The reason I want this is because:

  1. I want to shift some value based on the flag flags |= value << GetFlagPos(A)
  2. Lookup table value *= myTable[GetFlagPos(C)] // element 2 not 4
Simon Anciaux
1356 posts
How to get a flag's position from an enum
Edited by Simon Anciaux on

Maybe there is a better way but this seems to work (only if you pass it a enum label or a number literal. Otherwise it won't be compile time.

#define flag_bit_index( flag ) \
( flag & 0x2 ) ? 1 : \
( flag & 0x4 ) ? 2 : \
( flag & 0x8 ) ? 3 : \
( flag & 0x10 ) ? 4 : \
( flag & 0x20 ) ? 5 : \
( flag & 0x40 ) ? 6 : \
( flag & 0x80 ) ? 7 : \
( flag & 0x100 ) ? 8 : \
( flag & 0x200 ) ? 9 : \
( flag & 0x400 ) ? 10 : \
( flag & 0x800 ) ? 11 : \
( flag & 0x1000 ) ? 12 : \
( flag & 0x2000 ) ? 13 : \
( flag & 0x4000 ) ? 14 : \
( flag & 0x8000 ) ? 15 : \
( flag & 0x10000 ) ? 16 : \
( flag & 0x20000 ) ? 17 : \
( flag & 0x40000 ) ? 18 : \
( flag & 0x80000 ) ? 19 : \
( flag & 0x100000 ) ? 20 : \
( flag & 0x200000 ) ? 21 : \
( flag & 0x400000 ) ? 22 : \
( flag & 0x800000 ) ? 23 : \
( flag & 0x1000000 ) ? 24 : \
( flag & 0x2000000 ) ? 25 : \
( flag & 0x4000000 ) ? 26 : \
( flag & 0x8000000 ) ? 27 : \
( flag & 0x10000000 ) ? 28 : \
( flag & 0x20000000 ) ? 29 : \
( flag & 0x40000000 ) ? 30 : \
( flag & 0x80000000 ) ? 31 : \
( flag & 0x100000000 ) ? 32 : \
( flag & 0x200000000 ) ? 33 : \
( flag & 0x400000000 ) ? 34 : \
( flag & 0x800000000 ) ? 35 : \
( flag & 0x1000000000 ) ? 36 : \
( flag & 0x2000000000 ) ? 37 : \
( flag & 0x4000000000 ) ? 38 : \
( flag & 0x8000000000 ) ? 39 : \
( flag & 0x10000000000 ) ? 40 : \
( flag & 0x20000000000 ) ? 41 : \
( flag & 0x40000000000 ) ? 42 : \
( flag & 0x80000000000 ) ? 43 : \
( flag & 0x100000000000 ) ? 44 : \
( flag & 0x200000000000 ) ? 45 : \
( flag & 0x400000000000 ) ? 46 : \
( flag & 0x800000000000 ) ? 47 : \
( flag & 0x1000000000000 ) ? 48 : \
( flag & 0x2000000000000 ) ? 49 : \
( flag & 0x4000000000000 ) ? 50 : \
( flag & 0x8000000000000 ) ? 51 : \
( flag & 0x10000000000000 ) ? 52 : \
( flag & 0x20000000000000 ) ? 53 : \
( flag & 0x40000000000000 ) ? 54 : \
( flag & 0x80000000000000 ) ? 55 : \
( flag & 0x100000000000000 ) ? 56 : \
( flag & 0x200000000000000 ) ? 57 : \
( flag & 0x400000000000000 ) ? 58 : \
( flag & 0x800000000000000 ) ? 59 : \
( flag & 0x1000000000000000 ) ? 60 : \
( flag & 0x2000000000000000 ) ? 61 : \
( flag & 0x4000000000000000 ) ? 62 : \
( flag & 0x8000000000000000 ) ? 63 : 0
Mārtiņš Možeiko
2575 posts / 2 projects
How to get a flag's position from an enum
Edited by Mārtiņš Možeiko on

Why do you want flag position to be compile time value?

Classically you would typically do this:

enum {
  A_INDEX = 0,
  B_INDEX = 1,
  C_INDEX = 2,
};

enum {
  A = 1 << A_INDEX,
  B = 1 << B_INDEX,
  C = 1 << C_INDEX,
};

Then you can do flags |= value << A_INDEX;

And you can do #define FLAG(x) (1 << (x)) then you can write FLAG(A_INDEX) and not use those preshifted enum values.

But on modern compilers you can simply do flags |= value * A; Compiler will optimize to same shift, no multiplication will be involved.

Also what exactly is value? if it is boolean you want to set flag A or not, then you can simply write flags |= (value ? A : 0) and no need to worry about bit positions or shifts.

And if you're fine with value not to be compile time value, you can calculate bit position from flag value with very simple operation:

int GetFlagPos(MyFlags flag)
{
  assert(flag != 0);
  unsigned long index;
  _BitScanForward(&index, flag);
  return index;
}

Then you can do value *= myTable[GetFlagPos(C)]; That'll cost just one extra simple operation.

235 posts
How to get a flag's position from an enum
Edited by longtran2904 on
Replying to mmozeiko (#30103)

flags |= (value ? A : 0) is what I ended up doing, but isn't a runtime unpredictable check slower than a left shift?

Talking about compile-time value makes me wonder: Is the compiler required by the C spec to return compile-time value? For example, with int a = 5 + 3, can the compiler allow to produce an add?

Mārtiņš Možeiko
2575 posts / 2 projects
How to get a flag's position from an enum
Edited by Mārtiņš Možeiko on
Replying to longtran2904 (#30104)

By "unpredictable check" you mean "unpredictable branch" ? There will be no branch. It will compile to exactly same code with few simple bitwise operations - in all cases, be it conditional operation, manual shift, or with multiplication.

See here: https://godbolt.org/z/5rG39oj6f

Identical code for all three functions.

if you write int a = 5 + 3; then compiler is allowed to do either - leave 5 + 3 as runtime operation, or just produce 8. In either case variable a won't be compile time value. It's a variable, so you won't be able to use it where compile time constants are expected.

If you want to force compiler to produce compile time value, the typical trick in C is to use enum: enum { a = 5 + 3 }; Now a is compile time value. In C++ you can use constexpr for same effect.