summaryrefslogtreecommitdiff
path: root/include/llmr/util/enum.hpp
blob: 85a2d7c8969e41a0cce1c35cd624c9ef8a3a45b3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#ifndef LLMR_UTIL_ENUM
#define LLMR_UTIL_ENUM

#include <iosfwd>
#include <string>

namespace llmr {

template <typename Type>
struct EnumValue {
    const Type value;
    const char *name;
};

template <typename EnumName, const EnumValue<EnumName> *names, const size_t length>
struct Enum {
    using Type = EnumName;
    Type value;
    static const constexpr size_t l = length;
private:
    static constexpr inline bool compare(const char *a, const char *b) {
        return *a == *b && (*a == '\0' || compare(a + 1, b + 1));
    }
    static constexpr inline const char *lookup_type(Type e, EnumValue<Type> const * const l, size_t r) {
        return r == 0 ? "" : l->value == e ? l->name : lookup_type(e, l + 1, r - 1);
    }
    static constexpr inline Type lookup_name(const char *n, EnumValue<Type> const * const l, size_t r) {
        return r == 0 ? Type(-1) : compare(l->name, n) ? l->value : lookup_name(n, l + 1, r - 1);
    }
public:
    inline constexpr Enum(const char *n) : value(lookup_name(n, names, length)) {}
    inline constexpr Enum(const std::string &n) : value(lookup_name(n.c_str(), names, length)) {}
    inline constexpr Enum(Type t) : value(t) {}

    inline void operator=(const char *n) { value = lookup_name(n, names, length); }
    inline void operator=(const std::string &n) { *this = n.c_str(); }
    inline void operator=(Type t) { value = t; }

    inline constexpr bool valid() const { return value != Type(-1); }

    inline constexpr const char *c_str() const { return lookup_type(value, names, length); }
    inline std::string str() const { return c_str(); }

    inline constexpr operator Type() const { return value; }
};

#define LLMR_DEFINE_ENUM_CLASS(name, type, strings...) \
    const constexpr ::llmr::EnumValue<type> type##_names[] = strings; \
    using name = ::llmr::Enum<type, type##_names, sizeof(type##_names) / sizeof(::llmr::EnumValue<type>)>; \
    inline std::ostream& operator<<(std::ostream& os, type t) { return os << name(t).str(); }

}

#endif