tl;dr: LuaTables++ is a library that allows you to access values from Lua scripts in an easy manner. Custom types (i.e. structs or classes) can be easily added so that storing and retrieval to and from Lua is super simple. Serialization to strings is included. Code available here (MIT license). Handling of custom classes / structs is explained here.
For my visualization tool MeshUp I am using jsoncpp to store the configurations files. However it dawned to me that it should be easy to implement a library that allows to store and retrieve values from Lua scripts similarly easy as jsoncpp. As Lua has a nicer syntax than JSON this would allow me to store the configuration as Lua scripts and thus getting all the scripting capabilities there as well.
The last few days I spent some time to pimp the my LuaTables (which I mentioned here) library to make it more intuitive to use from C++ and I ended up something very nice. It even deserves a renaming to LuaTables++. First, an example:
-- agentsettings.lua
person = {
name = "James Bond",
age = 42.,
drunken = true,
address = {
country = "United Kingdom"
}
}
return person
Can be accessed using LuaTables++ using:
LuaTable ltable = LuaTable::fromFile("myfile.lua")
std::string name = ltable["name"];
double age = ltable["age"];
bool drunken = ltable["drunken"];
std::string country = ltable["address"]["country"];
Similarly you can set values:
ltable["drunken"] = false;
And also convert the table back to a string, e.g. to save the configuration back to a file:
std::string config_string = ltable.serialize();
Update: I have found a much better solution on how to handle custom types with LuaTables++.
This was very nice, but it gets better: LuaTables++ uses some templating magic inside which can be used to add reading and writing for structured data. E.g. to add the following custom type:
struct CustomType {
CustomType() :
name ("unnamed"),
age (-1.),
drunken (false) {}
string name;
double age;
bool drunken;
};
one has to implement two functions:
template<> CustomType LuaTableNode::getDefault<CustomType>(const CustomType &default_value)
template<> void LuaTableNode::set<CustomType>(const CustomType &value)
Here the function for converting from LuaTables++ to the C++ CustomType
:
template<> CustomType LuaTableNode::getDefault<CustomType>(const CustomType &default_value) {
CustomType result = default_value;
if (stackQueryValue()) {
lua_getfield (luaTable->L, -1, "name");
result.name = lua_tostring (luaTable->L, -1);
lua_pop (luaTable->L, 1);
lua_getfield (luaTable->L, -1, "age");
result.age = lua_tonumber (luaTable->L, -1);
lua_pop (luaTable->L, 1);
lua_getfield (luaTable->L, -1, "drunken");
result.drunken = lua_toboolean (luaTable->L, -1);
lua_pop (luaTable->L, 1);
}
stackRestore();
return result;
}
And here the function to store a C++ CustomType
to LuaTables++:
template<> void LuaTableNode::set<CustomType>(const CustomType &value) {
stackCreateValue();
// create new table for the CustomType
lua_newtable(luaTable->L); // parent, CustomTable
// set the fields of the custom type
lua_pushstring (luaTable->L, "name");
lua_pushstring (luaTable->L, value.name.c_str());
lua_settable (luaTable->L, -3);
lua_pushstring (luaTable->L, "age");
lua_pushnumber (luaTable->L, value.age);
lua_settable (luaTable->L, -3);
lua_pushstring (luaTable->L, "drunken");
lua_pushboolean (luaTable->L, value.drunken);
lua_settable (luaTable->L, -3);
// add table of CustomType to the parent
stackPushKey(); // parent, CustomTable, key
lua_pushvalue(luaTable->L, -2); // parent, CustomTable, key, CustomTable
lua_settable(luaTable->L, -4);
// restore the stack
stackRestore();
}
Once this is done, one can directly store and retrieve any CustomType to Lua:
// Create a new Custom Type
CustomType agent007;
agent007.name = "James Bond";
agent007.age = 42.;
agent007.drunken = true;
// Store it in LuaTables++
ltable["agents"][123] = agent007;
// Retrieve it from LuaTables++
CustomType other_agent = ltable["agents"][123];
One nice thing about this is, that once you have implemented the set() and getDefault() functions you automatically can serialize and de-serialize CustomTypes. Yeeeehaaaa!
LuaTables++ is available from https://bitbucket.org/MartinFelis/luatables only depends on the STL and Lua, which should be easy to fulfill. It is licensed under the MIT license (same as Lua).
Fun Fact: Around the same time Elias Daler implemented something similar to retrieve values from a Lua script http://eliasdaler.wordpress.com/2013/10/11/lua_cpp_binder/. His article also contains a brief introduction how the internals work.