X macros

From vegard.wiki
Revision as of 19:00, 14 December 2019 by Vegard (talk | contribs) (new page)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

Definitions:

#define _DEFINE_ENUM_NAME(name) name,
#define _DEFINE_ENUM_STR(name) #name,
#define DEFINE_ENUM(name) \
        enum name { \
                name(_DEFINE_ENUM_NAME) \
        }; \
        \
        const char *name##_names[] = { \
                name(_DEFINE_ENUM_STR) \
        }; \
        \
        const unsigned int nr_##name##s = sizeof(name##_names) / sizeof(*name##_names);

Usage:

#define opcode(X) \
        X(LOAD_CONSTANT) \
        X(LOAD_LOCAL) \
        X(STORE_LOCAL) \
        X(ADD) \
        X(SUB)

DEFINE_ENUM(opcode)

This defines enum opcode which contains LOAD_CONSTANT, etc. You can also map enum values to strings using the opcode_names array, like this:

void print_value(enum opcode opc)
{
        printf("%s\n", opcode_names[opc]);
}

Discontiguous values

For bitfields and cases where you need specific values, you can also modify the definition to allow specific/discontiguous enum values.

To avoid the name array from growing too large it is probably useful to use a map instead of an array.

#include <map>

#define _DEFINE_ENUM_NAME(name) name,
#define _DEFINE_ENUM_NAME_VALUE(name, value) name = value,

#define _DEFINE_ENUM_VALUE_STR1(name) { name, #name },
#define _DEFINE_ENUM_VALUE_STR2(name, value) { name, #name },

#define DEFINE_ENUM(name) \
        enum name { \
                name(_DEFINE_ENUM_NAME, _DEFINE_ENUM_NAME_VALUE) \
        }; \
        \
        std::map<enum name, const char *> name##s = { \
                name(_DEFINE_ENUM_VALUE_STR1, _DEFINE_ENUM_VALUE_STR2) \
        };

#define opcode(X, Y) \
        Y(LOAD_CONSTANT, 100) \
        X(LOAD_LOCAL) \
        Y(STORE_LOCAL,   200) \
        Y(ADD,           300) \
        X(SUB)

DEFINE_ENUM(opcode)

int main(int argc, char *argv[])
{
    for (auto &it: opcodes)
        printf("%d => %s\n", it.first, it.second);

    return 0;
}

This prints:

100 => LOAD_CONSTANT
101 => LOAD_LOCAL
200 => STORE_LOCAL
300 => ADD
301 => SUB

See also