Pioneer
LuaFlags.h
Go to the documentation of this file.
1 // Copyright © 2008-2023 Pioneer Developers. See AUTHORS.txt for details
2 // Licensed under the terms of the GPL v3. See licenses/GPL-3.txt
3 
4 #pragma once
5 
6 #include "utils.h"
7 #include <lua.hpp>
8 #include <stdexcept>
9 #include <string>
10 #include <vector>
11 
12 template <typename FlagType>
13 struct LuaFlags {
14  std::vector<std::pair<const char *, FlagType>> LUT;
15  std::string typeName;
16  int lookupTableRef = LUA_NOREF;
17 
18  LuaFlags(std::initializer_list<std::pair<const char *, FlagType>> init) :
19  LUT(init) {}
20 
21  void Register(lua_State *l, std::string name)
22  {
23  if (lookupTableRef != LUA_NOREF)
24  throw std::runtime_error(std::string("Class ") + name + " is already registered.");
25 
26  lua_newtable(l);
27  typeName = name;
28 
29  for (auto &pair : LUT) {
30  lua_pushstring(l, pair.first);
31  lua_pushinteger(l, static_cast<unsigned int>(pair.second));
32  lua_settable(l, -3);
33  }
34 
35  // luaL_ref pops the table off the stack.
36  lookupTableRef = luaL_ref(l, LUA_REGISTRYINDEX);
37  }
38 
39  void Unregister(lua_State *l)
40  {
41  luaL_unref(l, LUA_REGISTRYINDEX, lookupTableRef);
42  lookupTableRef = LUA_NOREF;
43  }
44 
45  FlagType LookupTable(lua_State *l, int index)
46  {
47  FlagType flagAccum = FlagType(0);
48  index = lua_absindex(l, index);
49  if (!lua_istable(l, index) || lookupTableRef == LUA_NOREF) return flagAccum;
50 
51  lua_checkstack(l, 2);
52  lua_pushinteger(l, lookupTableRef);
53  lua_gettable(l, LUA_REGISTRYINDEX);
54 
55  int table_idx = 1;
56  while (true) {
57  lua_pushinteger(l, table_idx++);
58  lua_gettable(l, index);
59 
60  if (!lua_isstring(l, -1)) {
61  lua_pop(l, 1);
62  break;
63  }
64 
65  flagAccum = static_cast<FlagType>(flagAccum | checkFlag(l, -1, -2));
66  }
67 
68  lua_pop(l, 1);
69  return flagAccum;
70  }
71 
72  FlagType LookupEnum(lua_State *l, int index)
73  {
74  FlagType flagAccum = FlagType(0);
75  index = lua_absindex(l, index);
76  if (!lua_isstring(l, index) || lookupTableRef == LUA_NOREF) return flagAccum;
77 
78  lua_checkstack(l, 2);
79  lua_pushinteger(l, lookupTableRef);
80  lua_gettable(l, LUA_REGISTRYINDEX);
81 
82  return checkFlag(l, index, -1);
83  }
84 
85 private:
86  inline FlagType checkFlag(lua_State *l, int index, int lookup_index)
87  {
88  lookup_index = lua_absindex(l, lookup_index);
89  lua_pushvalue(l, index);
90  lua_gettable(l, lookup_index);
91  if (lua_isnumber(l, -1)) {
92  // bitwise operations implicitly convert to int, so we must explicitly convert back to FlagType.
93  FlagType fl_ret = static_cast<FlagType>(lua_tointeger(l, -1));
94  lua_pop(l, 2); // clean up the stack!
95  return fl_ret;
96  } else {
97  lua_pop(l, 1);
98  std::string index_name = lua_tostring(l, index);
99  lua_pop(l, 2); // clean up the stack!
100  luaL_error(l, "Unknown %s %s", typeName.c_str(), index_name.c_str());
101  }
102  return FlagType(0);
103  }
104 };
Definition: LuaFlags.h:13
FlagType LookupEnum(lua_State *l, int index)
Definition: LuaFlags.h:72
void Unregister(lua_State *l)
Definition: LuaFlags.h:39
void Register(lua_State *l, std::string name)
Definition: LuaFlags.h:21
LuaFlags(std::initializer_list< std::pair< const char *, FlagType >> init)
Definition: LuaFlags.h:18
FlagType LookupTable(lua_State *l, int index)
Definition: LuaFlags.h:45
std::vector< std::pair< const char *, FlagType > > LUT
Definition: LuaFlags.h:14
std::string typeName
Definition: LuaFlags.h:15
int lookupTableRef
Definition: LuaFlags.h:16