Etterna 0.74.4
Loading...
Searching...
No Matches
EnumHelper.h
1#ifndef ENUM_HELPER_H
2#define ENUM_HELPER_H
3
4#include "Etterna/Models/Lua/LuaReference.h"
5#include <memory>
6
7#include "lua.hpp"
8
10#define FOREACH_ENUM_N(e, max, var) \
11 for (e var = (e)0; (var) < (max); enum_add<e>((var), +1))
13#define FOREACH_ENUM(e, var) \
14 for (e var = (e)0; (var) < NUM_##e; enum_add<e>((var), +1))
15
16auto
17CheckEnum(lua_State* L,
18 LuaReference& table,
19 int iPos,
20 int iInvalid,
21 const char* szType,
22 bool bAllowInvalid,
23 bool bAllowAnything = false) -> int;
24
25template<typename T>
27{
28 static LuaReference StringToEnum;
29 static LuaReference EnumToString;
30 static T Invalid;
31 static const char* szName;
32};
33template<typename T>
35template<typename T>
39auto
40EnumToString(int iVal,
41 int iMax,
42 const char** szNameArray,
43 std::unique_ptr<std::string>* pNameCache)
44 -> const std::string&; // XToString helper
45
46#define XToString(X) \
47 \
48 const std::string& X##ToString(X x); \
49 \
50static_assert(NUM_##X == ARRAYLEN(X##Names), "Size mismatch between "#X" enum and "#X"Names (Did you forget to add a string for a new enum entry?)"); \
51 \
52 const std::string& X##ToString(X x) \
53 \
54 { \
55 static std::unique_ptr<std::string> as_##X##Name[NUM_##X + 2]; \
56 return EnumToString(x, NUM_##X, X##Names, as_##X##Name); \
57 } \
58 \
59 namespace StringConversion { \
60 template<> \
61 std::string ToString<X>(const X& value) \
62 { \
63 return X##ToString(value); \
64 } \
65 }
66
67#define XToLocalizedString(X) \
68 \
69 const std::string& X##ToLocalizedString(X x); \
70 \
71 const std::string& X##ToLocalizedString(X x) \
72 \
73 { \
74 static std::unique_ptr<LocalizedString> g_##X##Name[NUM_##X]; \
75 if (g_##X##Name[0].get() == nullptr) { \
76 for (unsigned i = 0; i < NUM_##X; ++i) { \
77 std::unique_ptr<LocalizedString> ap( \
78 new LocalizedString(#X, X##ToString((X)i))); \
79 g_##X##Name[i] = std::move(ap); \
80 } \
81 } \
82 return g_##X##Name[x]->GetValue(); \
83 }
84
85#define StringToX(X) \
86 \
87 X StringTo##X(const std::string&); \
88 \
89 X StringTo##X(const std::string& s) \
90 \
91 { \
92 for (unsigned i = 0; i < ARRAYLEN(X##Names); ++i) \
93 if (!CompareNoCase(s, X##Names[i])) \
94 return (X)i; \
95 return X##_Invalid; \
96 } \
97 \
98 namespace StringConversion \
99 \
100 { \
101 template<> \
102 bool FromString<X>(const std::string& sValue, X& out) \
103 { \
104 out = StringTo##X(sValue); \
105 return out != X##_Invalid; \
106 } \
107 }
108
109/* Disable warnings about instantiations of static member variables of the
110 * templated class not being defined. These are all defined in different
111 * translation units by LuaXType, a macro that does a whole lot of stuff
112 * including initializing them.
113 *
114 * Because it happens in a different translation unit, there's not really a
115 * great way to do this better. You could state that external instantiations
116 * happen elsewhere with a `extern template struct EnumTraits<T>;` for every T,
117 * but the issue is that this header file doesn't know about the existence of
118 * those classes.
119 */
120
121#if defined(__clang__)
122#pragma clang diagnostic push
123#pragma clang diagnostic ignored "-Wundefined-var-template"
124#elif defined(__GNUC__)
125#pragma GCC diagnostic push
126#pragma GCC diagnostic ignored "-Wundefined-var-template"
127#elif defined(_MSC_VER)
128// TODO: Does anything need to be here?
129#endif
130
131namespace Enum {
132template<typename T>
133static auto
134Check(lua_State* L,
135 int iPos,
136 bool bAllowInvalid = false,
137 bool bAllowAnything = false) -> T
138{
139 return static_cast<T>(CheckEnum(L,
141 iPos,
144 bAllowInvalid,
145 bAllowAnything));
146}
147#if defined(__clang__)
148#pragma clang pop
149#elif defined(__GNUC__)
150#pragma GCC pop
151#elif defined(_MSC_VER)
152
153#endif
154
155template<typename T>
156static void
157Push(lua_State* L, T iVal)
158{
159 /* Enum_Invalid values are nil in Lua. */
160 if (iVal == EnumTraits<T>::Invalid) {
161 lua_pushnil(L);
162 return;
163 }
164
165 /* Look up the string value. */
166 EnumTraits<T>::EnumToString.PushSelf(L);
167 lua_rawgeti(L, -1, iVal + 1);
168 lua_remove(L, -2);
169}
170
171void
172SetMetatable(lua_State* L,
173 LuaReference& EnumTable,
174 LuaReference& EnumIndexTable,
175 const char* szName);
176} // namespace Enum
177
178#define LuaDeclareType(X)
179
180#define LuaXType(X) \
181 \
182 template struct EnumTraits<X>; \
183 \
184 static void Lua##X(lua_State* L) \
185 \
186 { \
187 lua_newtable(L); \
188 FOREACH_ENUM(X, i) \
189 { \
190 std::string s = X##ToString(i); \
191 lua_pushstring(L, ((#X "_") + s).c_str()); \
192 lua_rawseti(L, -2, i + 1); /* 1-based */ \
193 } \
194 EnumTraits<X>::EnumToString.SetFromStack(L); \
195 EnumTraits<X>::EnumToString.PushSelf(L); \
196 lua_setglobal(L, #X); \
197 lua_newtable(L); \
198 FOREACH_ENUM(X, i) \
199 { \
200 std::string s = X##ToString(i); \
201 lua_pushstring(L, ((#X "_") + s).c_str()); \
202 lua_pushnumber(L, i); /* 0-based */ \
203 lua_rawset(L, -3); \
204 /* Compatibility with old, case-insensitive values */ \
205 s = make_lower(s); \
206 lua_pushstring(L, s.c_str()); \
207 lua_pushnumber(L, i); /* 0-based */ \
208 lua_rawset(L, -3); \
209 /* Compatibility with old, raw values */ \
210 lua_pushnumber(L, i); \
211 lua_rawseti(L, -2, i); \
212 } \
213 EnumTraits<X>::StringToEnum.SetFromStack(L); \
214 EnumTraits<X>::StringToEnum.PushSelf(L); \
215 Enum::SetMetatable( \
216 L, EnumTraits<X>::EnumToString, EnumTraits<X>::StringToEnum, #X); \
217 } \
218 \
219 REGISTER_WITH_LUA_FUNCTION(Lua##X); \
220 \
221 template<> \
222 X EnumTraits<X>::Invalid = X##_Invalid; \
223 \
224 template<> \
225 const char* EnumTraits<X>::szName = #X; \
226 \
227 namespace LuaHelpers \
228 \
229 { \
230 template<> \
231 bool FromStack<X>(lua_State * L, X& Object, int iOffset) \
232 { \
233 Object = Enum::Check<X>(L, iOffset, true); \
234 return Object != EnumTraits<X>::Invalid; \
235 } \
236 } \
237 \
238 namespace LuaHelpers \
239 \
240 { \
241 template<> \
242 void Push<X>(lua_State * L, const X& Object) \
243 { \
244 Enum::Push<X>(L, Object); \
245 } \
246 }
247
248#endif
A self-cleaning Lua reference.
Definition LuaReference.h:10
Definition EnumHelper.h:27