Skip to content

Instantly share code, notes, and snippets.

@zolo-mario
Forked from Rochet2/LuaVal.h
Created March 20, 2023 03:58
Show Gist options
  • Save zolo-mario/c78c5460fa24bb62d53d807233fd9738 to your computer and use it in GitHub Desktop.
Save zolo-mario/c78c5460fa24bb62d53d807233fd9738 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.
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