Skip to content

Instantly share code, notes, and snippets.

@imaami
Last active July 24, 2023 00:40
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save imaami/43e96d243b21d873a23fda0c6267a89c to your computer and use it in GitHub Desktop.
Save imaami/43e96d243b21d873a23fda0c6267a89c to your computer and use it in GitHub Desktop.
Type information-encoded flags in C
#include <stdio.h>
enum {
FOO = 1 << 0,
BAR = 1 << 1,
BYX = 1 << 2,
QUE = 1 << 3
};
#define maybe_signed(T, cond) __typeof__( \
_Generic(&(char[2 - !(cond)]){0}, \
char(*)[1]: (unsigned T)0, \
char(*)[2]: (signed T)0))
#define if_signed(T, x, then) \
_Generic((__typeof__(x) *){0}, \
signed T const *: (then), unsigned T *: 0, \
signed T *: (then), unsigned T const *: 0)
#define define_metaflag(flag, flags) \
maybe_signed(char, flag & (flags)) meta_##flag
#define decode_metaflag(T, flag) \
if_signed(char, (T){0}.meta_##flag, flag)
#define define_metamap(T, flags) \
typedef union { \
define_metaflag(FOO, flags); \
define_metaflag(BAR, flags); \
define_metaflag(BYX, flags); \
define_metaflag(QUE, flags); \
} T
#define decode_metamap(T) ( \
0u | decode_metaflag(T, FOO) \
| decode_metaflag(T, BAR) \
| decode_metaflag(T, BYX) \
| decode_metaflag(T, QUE) \
)
int main (void)
{
define_metamap(foo_and_byx, FOO | BYX);
define_metamap(bar_and_que, BAR | QUE);
define_metamap(without_foo, BAR | BYX | QUE);
printf("0x%04x\n0x%04x\n0x%04x\n",
decode_metamap(foo_and_byx),
decode_metamap(bar_and_que),
decode_metamap(without_foo));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment