Last active
March 20, 2023 03:58
-
-
Save Rochet2/69c6b88070cf84ad7f547ded589db493 to your computer and use it in GitHub Desktop.
LuaVal is a C++ structure that is convertible from a lua table and to a lua table. Usage instructions at the bottom as a comment. Allows passing lua table between multiple lua states. Supports string, table, bool and number.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
enum LuaTypeTag | |
{ | |
TNIL, | |
TSTRING, | |
TTABLE, | |
TBOOL, | |
TNUMBER, | |
}; | |
class LuaVal; | |
size_t LuaValHash(LuaVal const& k); | |
namespace std { | |
template <> | |
struct hash<LuaVal> | |
{ | |
std::size_t operator()(const LuaVal& k) const | |
{ | |
return LuaValHash(k); | |
} | |
}; | |
} | |
class LuaVal | |
{ | |
public: | |
typedef std::map<LuaVal, LuaVal> MapType; | |
sol::object Get(sol::object const& key, sol::this_state const& s) const { | |
EASSERT(tag == TTABLE, "Trying to use non map LuaVal as table"); | |
sol::state_view lua(s); | |
auto& map = (*v.t); | |
auto klv = AsLuaVal(key); | |
auto it = map.find(klv); | |
if (it == map.end()) | |
return sol::make_object(lua, sol::lua_nil); | |
auto& val = it->second; | |
return val.asObject(s); | |
} | |
void Set(sol::object const& key, sol::object const& val) { | |
EASSERT(tag == TTABLE, "Trying to use non map LuaVal as table"); | |
auto kk = AsLuaVal(key); | |
auto vv = AsLuaVal(val); | |
EASSERT(kk.tag != TNIL, "table index is nil"); | |
if (vv.tag == TNIL) | |
v.t->erase(kk); | |
else | |
(*v.t)[std::move(kk)] = std::move(vv); | |
} | |
bool operator<(LuaVal const& b) const | |
{ | |
if (tag < b.tag) return true; | |
if (tag > b.tag) return false; | |
switch (tag) | |
{ | |
case TNIL: return false; | |
case TSTRING: return *v.s < *b.v.s; | |
case TTABLE: return v.t < b.v.t; | |
case TBOOL: return v.b < b.v.b; | |
case TNUMBER: return v.d < b.v.d; | |
} | |
return v.ptrrep < b.v.ptrrep; | |
} | |
bool operator==(LuaVal const& b) const | |
{ | |
if (tag != b.tag) return false; | |
switch (tag) | |
{ | |
case TNIL: return true; | |
case TSTRING: return *v.s == *b.v.s; | |
case TTABLE: return v.t == b.v.t; | |
case TBOOL: return v.b == b.v.b; | |
case TNUMBER: return v.d == b.v.d; | |
} | |
return v.ptrrep == b.v.ptrrep; | |
} | |
static std::string tostring(void* ptr) | |
{ | |
char arr[128]; | |
snprintf(arr, 128, "LuaVal: %p", ptr); | |
return arr; | |
} | |
std::string to_string() const | |
{ | |
switch (tag) | |
{ | |
case TNIL: return "nil"; | |
case TSTRING: return *v.s; | |
case TTABLE: return tostring(v.ptrrep); | |
case TBOOL: return v.b ? "true" : "false"; | |
case TNUMBER: return std::to_string(v.d); | |
} | |
return {}; | |
} | |
std::tuple<sol::object, MapType::iterator> iterate(sol::this_state const& s) const | |
{ | |
EASSERT(tag == TTABLE, "Trying to use non map LuaVal as table"); | |
auto func = [s, end = v.t->end()](MapType::iterator& it) -> std::tuple<sol::object, sol::object> { | |
sol::state_view lua(s); | |
if (it == end) | |
return { sol::make_object(lua, sol::lua_nil) , sol::make_object(lua, sol::lua_nil) }; | |
auto oldit = it++; | |
return std::make_tuple(oldit->first.asObject(s), oldit->second.asObject(s)); | |
}; | |
return std::make_tuple(sol::make_object(sol::state_view(s), func), v.t->begin()); | |
} | |
sol::object asObject(sol::this_state const& s) const | |
{ | |
sol::state_view lua(s); | |
switch (tag) { | |
case TNIL: return sol::make_object(lua, sol::lua_nil); | |
case TSTRING: return sol::make_object(lua, *v.s); | |
case TTABLE: return sol::make_object(lua, *this); | |
case TBOOL: return sol::make_object(lua, v.b); | |
case TNUMBER: return sol::make_object(lua, v.d); | |
} | |
return sol::make_object(lua, sol::lua_nil); | |
} | |
sol::object asTable(sol::this_state const& s) const | |
{ | |
if (tag == TTABLE) | |
{ | |
sol::state_view lua(s); | |
auto tbl = lua.create_table(); | |
for (auto& it : *v.t) | |
{ | |
it.first; | |
tbl.raw_set(it.first.asObject(s), it.second.asObject(s)); | |
} | |
return tbl; | |
} | |
return asObject(s); | |
} | |
sol::object asLua(sol::this_state const& s) const | |
{ | |
if (tag == TTABLE) | |
{ | |
sol::state_view lua(s); | |
auto tbl = lua.create_table(); | |
for (auto& it : *v.t) | |
{ | |
it.first; | |
tbl.raw_set(it.first.asLua(s), it.second.asLua(s)); | |
} | |
return tbl; | |
} | |
return asObject(s); | |
} | |
static LuaVal AsLuaVal(sol::object const& v) | |
{ | |
auto t = v.get_type(); | |
switch (t) | |
{ | |
case sol::type::boolean: | |
return LuaVal(v.as<bool>()); | |
case sol::type::lua_nil: | |
case sol::type::none: | |
return LuaVal(); | |
case sol::type::number: | |
return LuaVal(v.as<double>()); | |
case sol::type::string: | |
return LuaVal(v.as<std::string>()); | |
case sol::type::table: | |
return FromTable(v); | |
case sol::type::userdata: | |
if (v.is<LuaVal>()) | |
return v.as<LuaVal>(); | |
default: | |
EERROR("Trying to use unsupported type"); | |
} | |
} | |
static LuaVal FromTable(sol::table const& tbl) | |
{ | |
LuaVal m({}); | |
for (auto it : tbl) { | |
m.v.t->emplace(AsLuaVal(it.first), AsLuaVal(it.second)); | |
} | |
return m; | |
} | |
LuaVal() : tag(TNIL) {} | |
LuaVal(std::string const& s) : v(new std::string(s)), tag(TSTRING) {} | |
LuaVal(bool b) : v(b), tag(TBOOL) {} | |
LuaVal(double d) : v(d), tag(TNUMBER) {} | |
LuaVal(MapType const& t) : v(new MapType(t)), tag(TTABLE) {} | |
LuaVal(std::initializer_list<MapType::value_type> const& l) : v(new MapType(l)), tag(TTABLE) {} | |
LuaVal(LuaVal&& b) : tag(b.tag), v(b.v) { b.v.s = nullptr; b.v.t = nullptr; } | |
LuaVal(const LuaVal& b) : tag(b.tag), v(b.v) { | |
if (tag == TSTRING) v.s = new std::string(*b.v.s); | |
else if (tag == TTABLE) v.t = new MapType(*b.v.t); | |
} | |
~LuaVal() { | |
if (tag == TSTRING) delete v.s; | |
else if (tag == TTABLE) delete v.t; | |
} | |
LuaVal& operator=(const LuaVal& b) { | |
tag = b.tag; | |
v = b.v; | |
if (tag == TSTRING) v.s = new std::string(*b.v.s); | |
else if (tag == TTABLE) v.t = new MapType(*b.v.t); | |
return *this; | |
} | |
//LuaVal& operator=(LuaVal&& b) { | |
// tag = b.tag; | |
// v = b.v; | |
// b.v.s = nullptr; | |
// b.v.t = nullptr; | |
// return *this; | |
//} | |
LuaTypeTag tag; | |
union value { | |
value() : ptrrep(nullptr) {}; | |
value(double d) : d(d) {} | |
value(bool b) : b(b) {} | |
value(std::string* s) : s(s) {} | |
value(MapType* t) : t(t) {} | |
double d; | |
bool b; | |
std::string* s; | |
MapType* t; | |
void* ptrrep; | |
} v; | |
}; | |
inline size_t LuaValHash(LuaVal const& k) | |
{ | |
return std::hash<void*>{}(k.v.ptrrep); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The code allows using a LuaVal as a table like entity in lua. The data is stored in C, so you can pass it between different lua states safely.
usage for sol2: