Skip to content

Instantly share code, notes, and snippets.

@NocturnDragon
Created October 25, 2018 16:25
Show Gist options
  • Save NocturnDragon/524b8b97a813e8f7a1f950c6ecc6e2be to your computer and use it in GitHub Desktop.
Save NocturnDragon/524b8b97a813e8f7a1f950c6ecc6e2be to your computer and use it in GitHub Desktop.
A supremely dirty way of converting an enum value to a string at runtime, without the use of double-declaration XMacros or its ilk.
// Source: https://twitter.com/zygoloid/status/735275127873540096
//
// A supremely dirty way of converting an enum value to a string at runtime, without
// the use of double-declaration XMacros or its ilk.
//
// Very silly code but it actually works.
//
#include <stdio.h>
//
// Example enum
//
enum TestEnum
{
// List your enums
// They don't *actually* have to be sequential and you can assign any values
// you want. However, the bigger the values, the longer it will take to find
// your enum string!
Zero, One, Two, Three, Four, Five, Six, Seven, Eight, Monkeys,
// Uniquely named total count
// With enum classes this could be made a little simpler
TestEnum_Count
};
#if __cplusplus < 201402L
namespace std {
template<typename T, T...> struct integer_sequence {};
template<typename T, T N> using make_integer_sequence = __make_integer_seq<integer_sequence, T, N>;
template<size_t ...N> using index_sequence = integer_sequence<size_t, N...>;
template<size_t N> using make_index_sequence = make_integer_sequence<size_t, N>;
}
#endif
template<int n> struct StrCpy {
char buf[n+1];
constexpr StrCpy(const char *p)
#if __cplusplus < 201402L
: StrCpy(std::make_index_sequence<n>(), p) {}
template<size_t ...i>
constexpr StrCpy(std::index_sequence<i...>, const char *p)
: buf{p[i]...} {}
#else
{ for (int i = 0; i < n; ++i) buf[i] = p[i]; buf[n] = 0; }
#endif
};
//
// The magic.
// This is terrible and there are ways to make it even more useful.
// Please send help, I should not be writing crap like this!
//
template <typename ENUM_TYPE, ENUM_TYPE ENUM_VALUE>
const char* EnumName()
{
constexpr const char *s = __PRETTY_FUNCTION__ + 59;
constexpr int n = __builtin_strlen(s) - 1;
static constexpr StrCpy<n> str{s};
return str.buf;
}
template <typename ENUM_TYPE, ENUM_TYPE ENUM_COUNT, ENUM_TYPE ENUM_VALUE>
struct EnumMatch
{
static const char* Do(ENUM_TYPE enum_value)
{
if (enum_value == ENUM_VALUE)
return EnumName<ENUM_TYPE, ENUM_VALUE>();
return EnumMatch<ENUM_TYPE, ENUM_COUNT, ENUM_TYPE(ENUM_VALUE+1)>::Do(enum_value);
}
};
template <typename ENUM_TYPE, ENUM_TYPE ENUM_COUNT>
struct EnumMatch<ENUM_TYPE, ENUM_COUNT, ENUM_COUNT>
{
static const char* Do(ENUM_TYPE enum_value)
{
return "Enum not found";
}
};
#define ENUM_NAME(enum_type, enum_value) \
EnumMatch<enum_type, enum_type##_Count, enum_type(0)>::Do(enum_value)
int main()
{
for (int i = 0; i < TestEnum_Count; i++)
printf("%s\n", ENUM_NAME(TestEnum, TestEnum(i)));
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment