FlatImage
A configurable Linux containerization system
Loading...
Searching...
No Matches
enum.hpp
Go to the documentation of this file.
1
8
9#pragma once
10#include <cstdlib>
11#include <expected>
12#include <print>
13
14// Get size of __VA_ARGS__
15#define VA_SIZE(...) VA_SIZE_(__VA_ARGS__,VA_SIZE_RSEQ())
16#define VA_SIZE_(...) VA_SIZE_SEQ(__VA_ARGS__)
17#define VA_SIZE_SEQ( \
18 _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
19 _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
20 _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
21 _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
22 _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
23 _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
24 _61,_62,_63,N,...) N
25#define VA_SIZE_RSEQ() \
26 63,62,61,60, \
27 59,58,57,56,55,54,53,52,51,50, \
28 49,48,47,46,45,44,43,42,41,40, \
29 39,38,37,36,35,34,33,32,31,30, \
30 29,28,27,26,25,24,23,22,21,20, \
31 19,18,17,16,15,14,13,12,11,10, \
32 9,8,7,6,5,4,3,2,1,0
33
34// Pop front of __VA_ARGS__
35#define VA_DROP(x,...) __VA_ARGS__
36
37// Create a case statement for enum to string
38#define ENUM_TO_STRING_EXPR(NAME,value) case enum_t::value: return #value;
39#define ENUM_CASE_TO_STRING_0(NAME,x) ENUM_TO_STRING_EXPR(NAME,x)
40#define ENUM_CASE_TO_STRING_1(NAME,x,...) ENUM_TO_STRING_EXPR(NAME,x) ENUM_CASE_TO_STRING_0(NAME,__VA_ARGS__)
41#define ENUM_CASE_TO_STRING_2(NAME,x,...) ENUM_TO_STRING_EXPR(NAME,x) ENUM_CASE_TO_STRING_1(NAME,__VA_ARGS__)
42#define ENUM_CASE_TO_STRING_3(NAME,x,...) ENUM_TO_STRING_EXPR(NAME,x) ENUM_CASE_TO_STRING_2(NAME,__VA_ARGS__)
43#define ENUM_CASE_TO_STRING_4(NAME,x,...) ENUM_TO_STRING_EXPR(NAME,x) ENUM_CASE_TO_STRING_3(NAME,__VA_ARGS__)
44#define ENUM_CASE_TO_STRING_5(NAME,x,...) ENUM_TO_STRING_EXPR(NAME,x) ENUM_CASE_TO_STRING_4(NAME,__VA_ARGS__)
45#define ENUM_CASE_TO_STRING_6(NAME,x,...) ENUM_TO_STRING_EXPR(NAME,x) ENUM_CASE_TO_STRING_5(NAME,__VA_ARGS__)
46#define ENUM_CASE_TO_STRING_7(NAME,x,...) ENUM_TO_STRING_EXPR(NAME,x) ENUM_CASE_TO_STRING_6(NAME,__VA_ARGS__)
47#define ENUM_CASE_TO_STRING_8(NAME,x,...) ENUM_TO_STRING_EXPR(NAME,x) ENUM_CASE_TO_STRING_7(NAME,__VA_ARGS__)
48#define ENUM_CASE_TO_STRING_9(NAME,x,...) ENUM_TO_STRING_EXPR(NAME,x) ENUM_CASE_TO_STRING_8(NAME,__VA_ARGS__)
49#define ENUM_CASE_TO_STRING_10(NAME,x,...) ENUM_TO_STRING_EXPR(NAME,x) ENUM_CASE_TO_STRING_9(NAME,__VA_ARGS__)
50#define ENUM_CASE_TO_STRING_11(NAME,x,...) ENUM_TO_STRING_EXPR(NAME,x) ENUM_CASE_TO_STRING_10(NAME,__VA_ARGS__)
51#define ENUM_CASE_TO_STRING_12(NAME,x,...) ENUM_TO_STRING_EXPR(NAME,x) ENUM_CASE_TO_STRING_11(NAME,__VA_ARGS__)
52#define ENUM_CASE_TO_STRING_13(NAME,x,...) ENUM_TO_STRING_EXPR(NAME,x) ENUM_CASE_TO_STRING_12(NAME,__VA_ARGS__)
53#define ENUM_CASE_TO_STRING_14(NAME,x,...) ENUM_TO_STRING_EXPR(NAME,x) ENUM_CASE_TO_STRING_13(NAME,__VA_ARGS__)
54#define ENUM_CASE_TO_STRING_15(NAME,x,...) ENUM_TO_STRING_EXPR(NAME,x) ENUM_CASE_TO_STRING_14(NAME,__VA_ARGS__)
55#define ENUM_CASE_TO_STRING_16(NAME,x,...) ENUM_TO_STRING_EXPR(NAME,x) ENUM_CASE_TO_STRING_15(NAME,__VA_ARGS__)
56#define ENUM_CASE_TO_STRING_17(NAME,x,...) ENUM_TO_STRING_EXPR(NAME,x) ENUM_CASE_TO_STRING_16(NAME,__VA_ARGS__)
57#define ENUM_CASE_TO_STRING_18(NAME,x,...) ENUM_TO_STRING_EXPR(NAME,x) ENUM_CASE_TO_STRING_17(NAME,__VA_ARGS__)
58#define ENUM_CASE_TO_STRING_19(NAME,x,...) ENUM_TO_STRING_EXPR(NAME,x) ENUM_CASE_TO_STRING_18(NAME,__VA_ARGS__)
59#define ENUM_CASE_TO_STRING_20(NAME,x,...) ENUM_TO_STRING_EXPR(NAME,x) ENUM_CASE_TO_STRING_19(NAME,__VA_ARGS__)
60#define ENUM_CASE_TO_STRING_IMPL(i,NAME,...) ENUM_CASE_TO_STRING_##i(NAME,__VA_ARGS__)
61#define ENUM_CASE_TO_STRING(i,NAME,...) ENUM_CASE_TO_STRING_IMPL(i,NAME,__VA_ARGS__)
62
63// Create a case statement for string to enum
64#define ENUM_FROM_STRING_EXPR(NAME,value) if ( str_enum == #value ) { return NAME(value); }
65#define ENUM_CASE_FROM_STRING_0(NAME,x) ENUM_FROM_STRING_EXPR(NAME,x)
66#define ENUM_CASE_FROM_STRING_1(NAME,x,...) ENUM_FROM_STRING_EXPR(NAME,x) ENUM_CASE_FROM_STRING_0(NAME,__VA_ARGS__)
67#define ENUM_CASE_FROM_STRING_2(NAME,x,...) ENUM_FROM_STRING_EXPR(NAME,x) ENUM_CASE_FROM_STRING_1(NAME,__VA_ARGS__)
68#define ENUM_CASE_FROM_STRING_3(NAME,x,...) ENUM_FROM_STRING_EXPR(NAME,x) ENUM_CASE_FROM_STRING_2(NAME,__VA_ARGS__)
69#define ENUM_CASE_FROM_STRING_4(NAME,x,...) ENUM_FROM_STRING_EXPR(NAME,x) ENUM_CASE_FROM_STRING_3(NAME,__VA_ARGS__)
70#define ENUM_CASE_FROM_STRING_5(NAME,x,...) ENUM_FROM_STRING_EXPR(NAME,x) ENUM_CASE_FROM_STRING_4(NAME,__VA_ARGS__)
71#define ENUM_CASE_FROM_STRING_6(NAME,x,...) ENUM_FROM_STRING_EXPR(NAME,x) ENUM_CASE_FROM_STRING_5(NAME,__VA_ARGS__)
72#define ENUM_CASE_FROM_STRING_7(NAME,x,...) ENUM_FROM_STRING_EXPR(NAME,x) ENUM_CASE_FROM_STRING_6(NAME,__VA_ARGS__)
73#define ENUM_CASE_FROM_STRING_8(NAME,x,...) ENUM_FROM_STRING_EXPR(NAME,x) ENUM_CASE_FROM_STRING_7(NAME,__VA_ARGS__)
74#define ENUM_CASE_FROM_STRING_9(NAME,x,...) ENUM_FROM_STRING_EXPR(NAME,x) ENUM_CASE_FROM_STRING_8(NAME,__VA_ARGS__)
75#define ENUM_CASE_FROM_STRING_10(NAME,x,...) ENUM_FROM_STRING_EXPR(NAME,x) ENUM_CASE_FROM_STRING_9(NAME,__VA_ARGS__)
76#define ENUM_CASE_FROM_STRING_11(NAME,x,...) ENUM_FROM_STRING_EXPR(NAME,x) ENUM_CASE_FROM_STRING_10(NAME,__VA_ARGS__)
77#define ENUM_CASE_FROM_STRING_12(NAME,x,...) ENUM_FROM_STRING_EXPR(NAME,x) ENUM_CASE_FROM_STRING_11(NAME,__VA_ARGS__)
78#define ENUM_CASE_FROM_STRING_13(NAME,x,...) ENUM_FROM_STRING_EXPR(NAME,x) ENUM_CASE_FROM_STRING_12(NAME,__VA_ARGS__)
79#define ENUM_CASE_FROM_STRING_14(NAME,x,...) ENUM_FROM_STRING_EXPR(NAME,x) ENUM_CASE_FROM_STRING_13(NAME,__VA_ARGS__)
80#define ENUM_CASE_FROM_STRING_15(NAME,x,...) ENUM_FROM_STRING_EXPR(NAME,x) ENUM_CASE_FROM_STRING_14(NAME,__VA_ARGS__)
81#define ENUM_CASE_FROM_STRING_16(NAME,x,...) ENUM_FROM_STRING_EXPR(NAME,x) ENUM_CASE_FROM_STRING_15(NAME,__VA_ARGS__)
82#define ENUM_CASE_FROM_STRING_17(NAME,x,...) ENUM_FROM_STRING_EXPR(NAME,x) ENUM_CASE_FROM_STRING_16(NAME,__VA_ARGS__)
83#define ENUM_CASE_FROM_STRING_18(NAME,x,...) ENUM_FROM_STRING_EXPR(NAME,x) ENUM_CASE_FROM_STRING_17(NAME,__VA_ARGS__)
84#define ENUM_CASE_FROM_STRING_19(NAME,x,...) ENUM_FROM_STRING_EXPR(NAME,x) ENUM_CASE_FROM_STRING_18(NAME,__VA_ARGS__)
85#define ENUM_CASE_FROM_STRING_20(NAME,x,...) ENUM_FROM_STRING_EXPR(NAME,x) ENUM_CASE_FROM_STRING_19(NAME,__VA_ARGS__)
86#define ENUM_CASE_FROM_STRING_IMPL(i,NAME,...) ENUM_CASE_FROM_STRING_##i(NAME,__VA_ARGS__)
87#define ENUM_CASE_FROM_STRING(i,NAME,...) ENUM_CASE_FROM_STRING_IMPL(i,NAME,__VA_ARGS__)
88
89// Create a static member entry
90#define ENUM_TO_MEMBER_EXPR(NAME,value) static enum_t const value;
91#define ENUM_TO_MEMBER_0(NAME,x) ENUM_TO_MEMBER_EXPR(NAME,x)
92#define ENUM_TO_MEMBER_1(NAME,x,...) ENUM_TO_MEMBER_EXPR(NAME,x) ENUM_TO_MEMBER_0(NAME,__VA_ARGS__)
93#define ENUM_TO_MEMBER_2(NAME,x,...) ENUM_TO_MEMBER_EXPR(NAME,x) ENUM_TO_MEMBER_1(NAME,__VA_ARGS__)
94#define ENUM_TO_MEMBER_3(NAME,x,...) ENUM_TO_MEMBER_EXPR(NAME,x) ENUM_TO_MEMBER_2(NAME,__VA_ARGS__)
95#define ENUM_TO_MEMBER_4(NAME,x,...) ENUM_TO_MEMBER_EXPR(NAME,x) ENUM_TO_MEMBER_3(NAME,__VA_ARGS__)
96#define ENUM_TO_MEMBER_5(NAME,x,...) ENUM_TO_MEMBER_EXPR(NAME,x) ENUM_TO_MEMBER_4(NAME,__VA_ARGS__)
97#define ENUM_TO_MEMBER_6(NAME,x,...) ENUM_TO_MEMBER_EXPR(NAME,x) ENUM_TO_MEMBER_5(NAME,__VA_ARGS__)
98#define ENUM_TO_MEMBER_7(NAME,x,...) ENUM_TO_MEMBER_EXPR(NAME,x) ENUM_TO_MEMBER_6(NAME,__VA_ARGS__)
99#define ENUM_TO_MEMBER_8(NAME,x,...) ENUM_TO_MEMBER_EXPR(NAME,x) ENUM_TO_MEMBER_7(NAME,__VA_ARGS__)
100#define ENUM_TO_MEMBER_9(NAME,x,...) ENUM_TO_MEMBER_EXPR(NAME,x) ENUM_TO_MEMBER_8(NAME,__VA_ARGS__)
101#define ENUM_TO_MEMBER_10(NAME,x,...) ENUM_TO_MEMBER_EXPR(NAME,x) ENUM_TO_MEMBER_9(NAME,__VA_ARGS__)
102#define ENUM_TO_MEMBER_11(NAME,x,...) ENUM_TO_MEMBER_EXPR(NAME,x) ENUM_TO_MEMBER_10(NAME,__VA_ARGS__)
103#define ENUM_TO_MEMBER_12(NAME,x,...) ENUM_TO_MEMBER_EXPR(NAME,x) ENUM_TO_MEMBER_11(NAME,__VA_ARGS__)
104#define ENUM_TO_MEMBER_13(NAME,x,...) ENUM_TO_MEMBER_EXPR(NAME,x) ENUM_TO_MEMBER_12(NAME,__VA_ARGS__)
105#define ENUM_TO_MEMBER_14(NAME,x,...) ENUM_TO_MEMBER_EXPR(NAME,x) ENUM_TO_MEMBER_13(NAME,__VA_ARGS__)
106#define ENUM_TO_MEMBER_15(NAME,x,...) ENUM_TO_MEMBER_EXPR(NAME,x) ENUM_TO_MEMBER_14(NAME,__VA_ARGS__)
107#define ENUM_TO_MEMBER_16(NAME,x,...) ENUM_TO_MEMBER_EXPR(NAME,x) ENUM_TO_MEMBER_15(NAME,__VA_ARGS__)
108#define ENUM_TO_MEMBER_17(NAME,x,...) ENUM_TO_MEMBER_EXPR(NAME,x) ENUM_TO_MEMBER_16(NAME,__VA_ARGS__)
109#define ENUM_TO_MEMBER_18(NAME,x,...) ENUM_TO_MEMBER_EXPR(NAME,x) ENUM_TO_MEMBER_17(NAME,__VA_ARGS__)
110#define ENUM_TO_MEMBER_19(NAME,x,...) ENUM_TO_MEMBER_EXPR(NAME,x) ENUM_TO_MEMBER_18(NAME,__VA_ARGS__)
111#define ENUM_TO_MEMBER_20(NAME,x,...) ENUM_TO_MEMBER_EXPR(NAME,x) ENUM_TO_MEMBER_19(NAME,__VA_ARGS__)
112#define ENUM_TO_MEMBER_IMPL(i,NAME,...) ENUM_TO_MEMBER_##i(NAME,__VA_ARGS__)
113#define ENUM_TO_MEMBER(i,NAME,...) ENUM_TO_MEMBER_IMPL(i, NAME, __VA_ARGS__)
114
115// Initialize the static member entry
116#define ENUM_STATIC_INIT_EXPR(NAME,value) inline NAME::enum_t const NAME::value = NAME::enum_t::value;
117#define ENUM_STATIC_INIT_0(NAME,x) ENUM_STATIC_INIT_EXPR(NAME,x)
118#define ENUM_STATIC_INIT_1(NAME,x,...) ENUM_STATIC_INIT_EXPR(NAME,x) ENUM_STATIC_INIT_0(NAME,__VA_ARGS__)
119#define ENUM_STATIC_INIT_2(NAME,x,...) ENUM_STATIC_INIT_EXPR(NAME,x) ENUM_STATIC_INIT_1(NAME,__VA_ARGS__)
120#define ENUM_STATIC_INIT_3(NAME,x,...) ENUM_STATIC_INIT_EXPR(NAME,x) ENUM_STATIC_INIT_2(NAME,__VA_ARGS__)
121#define ENUM_STATIC_INIT_4(NAME,x,...) ENUM_STATIC_INIT_EXPR(NAME,x) ENUM_STATIC_INIT_3(NAME,__VA_ARGS__)
122#define ENUM_STATIC_INIT_5(NAME,x,...) ENUM_STATIC_INIT_EXPR(NAME,x) ENUM_STATIC_INIT_4(NAME,__VA_ARGS__)
123#define ENUM_STATIC_INIT_6(NAME,x,...) ENUM_STATIC_INIT_EXPR(NAME,x) ENUM_STATIC_INIT_5(NAME,__VA_ARGS__)
124#define ENUM_STATIC_INIT_7(NAME,x,...) ENUM_STATIC_INIT_EXPR(NAME,x) ENUM_STATIC_INIT_6(NAME,__VA_ARGS__)
125#define ENUM_STATIC_INIT_8(NAME,x,...) ENUM_STATIC_INIT_EXPR(NAME,x) ENUM_STATIC_INIT_7(NAME,__VA_ARGS__)
126#define ENUM_STATIC_INIT_9(NAME,x,...) ENUM_STATIC_INIT_EXPR(NAME,x) ENUM_STATIC_INIT_8(NAME,__VA_ARGS__)
127#define ENUM_STATIC_INIT_10(NAME,x,...) ENUM_STATIC_INIT_EXPR(NAME,x) ENUM_STATIC_INIT_9(NAME,__VA_ARGS__)
128#define ENUM_STATIC_INIT_11(NAME,x,...) ENUM_STATIC_INIT_EXPR(NAME,x) ENUM_STATIC_INIT_10(NAME,__VA_ARGS__)
129#define ENUM_STATIC_INIT_12(NAME,x,...) ENUM_STATIC_INIT_EXPR(NAME,x) ENUM_STATIC_INIT_11(NAME,__VA_ARGS__)
130#define ENUM_STATIC_INIT_13(NAME,x,...) ENUM_STATIC_INIT_EXPR(NAME,x) ENUM_STATIC_INIT_12(NAME,__VA_ARGS__)
131#define ENUM_STATIC_INIT_14(NAME,x,...) ENUM_STATIC_INIT_EXPR(NAME,x) ENUM_STATIC_INIT_13(NAME,__VA_ARGS__)
132#define ENUM_STATIC_INIT_15(NAME,x,...) ENUM_STATIC_INIT_EXPR(NAME,x) ENUM_STATIC_INIT_14(NAME,__VA_ARGS__)
133#define ENUM_STATIC_INIT_16(NAME,x,...) ENUM_STATIC_INIT_EXPR(NAME,x) ENUM_STATIC_INIT_15(NAME,__VA_ARGS__)
134#define ENUM_STATIC_INIT_17(NAME,x,...) ENUM_STATIC_INIT_EXPR(NAME,x) ENUM_STATIC_INIT_16(NAME,__VA_ARGS__)
135#define ENUM_STATIC_INIT_18(NAME,x,...) ENUM_STATIC_INIT_EXPR(NAME,x) ENUM_STATIC_INIT_17(NAME,__VA_ARGS__)
136#define ENUM_STATIC_INIT_19(NAME,x,...) ENUM_STATIC_INIT_EXPR(NAME,x) ENUM_STATIC_INIT_18(NAME,__VA_ARGS__)
137#define ENUM_STATIC_INIT_20(NAME,x,...) ENUM_STATIC_INIT_EXPR(NAME,x) ENUM_STATIC_INIT_19(NAME,__VA_ARGS__)
138#define ENUM_STATIC_INIT_IMPL(i,NAME,...) ENUM_STATIC_INIT_##i(NAME,__VA_ARGS__)
139#define ENUM_STATIC_INIT(i,NAME,...) ENUM_STATIC_INIT_IMPL(i, NAME, __VA_ARGS__)
140
141#define ENUM_IMPL(NAME, ...) \
142struct NAME \
143{ \
144 public: \
145 enum class enum_t : int { __VA_ARGS__ }; \
146 private: \
147 enum_t m_current; \
148 public: \
149 size_t const size = VA_SIZE(__VA_ARGS__); \
150 ENUM_TO_MEMBER(VA_SIZE(VA_DROP(__VA_ARGS__)), NAME, __VA_ARGS__) \
151 NAME() : m_current(enum_t::NONE) {} \
152 NAME(NAME const&) = default;\
153 NAME(NAME&&) = default;\
154 NAME(enum_t entry) : m_current(entry) {}\
155 /* from_string callable (declaration) */ \
156 struct from_string_t { \
157 std::expected<NAME, std::string> operator()(std::string) const; \
158 }; \
159 static inline constexpr from_string_t from_string{}; \
160 operator enum_t() const \
161 { \
162 return m_current; \
163 } \
164 enum_t get() const \
165 { \
166 return m_current; \
167 } \
168 std::string lower() const \
169 { \
170 std::string str{*this}; \
171 std::ranges::transform(str, str.begin(), ::tolower); \
172 return str; \
173 } \
174 operator std::string() const \
175 { \
176 switch(m_current) \
177 { \
178 ENUM_CASE_TO_STRING(VA_SIZE(VA_DROP(__VA_ARGS__)), NAME, __VA_ARGS__) \
179 } \
180 return ""; /* Unreachable */ \
181 } \
182 bool operator<(NAME const& other) const \
183 { \
184 return this->m_current < other.m_current; \
185 } \
186 bool operator==(enum_t const& enum_value) const \
187 { \
188 return m_current == enum_value; \
189 } \
190 NAME& operator=(NAME const& other) { m_current = other.m_current; return *this; }\
191 NAME& operator=(NAME&& other) { m_current = other.m_current; return *this; }\
192}; \
193ENUM_STATIC_INIT(VA_SIZE(VA_DROP(__VA_ARGS__)), NAME, __VA_ARGS__) \
194/* Define the callable after the class is complete */ \
195inline std::expected<NAME, std::string> NAME::from_string_t::operator()(std::string str_enum) const { \
196 std::ranges::transform(str_enum, str_enum.begin(), [](unsigned char c){ return static_cast<char>(std::toupper(c)); }); \
197 ENUM_CASE_FROM_STRING(VA_SIZE(VA_DROP(__VA_ARGS__)), NAME, __VA_ARGS__) \
198 return std::unexpected(std::string("Could not determine enum entry from '") + str_enum + "'"); \
199}
200
201#define ENUM(NAME, ...) ENUM_IMPL(NAME, __VA_ARGS__, NONE)
202
203/* vim: set expandtab fdm=marker ts=2 sw=2 tw=100 et :*/