Tell me more ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I'm writing a library that would ease the exportation of C++ classes (that is the definition of their members) to Lua. It originated from the need of tidying up the code for a server mod of a open source game, Sauerbraten. The mod is SpaghettiMod, a fork of hopmod. Unfortunately I'm enough busy in developing it and so have no time to strip it out of the actual software to allow its evaluation as standalone, but anyway it's enough independent from the rest of the code to allow a static inspection. This is the directory of the component, the main code is in luaproxy.hpp, the rest is pretty much ancillary and glue code.


Description and usage

A luaproxy is an object that acts as a proxy between your Lua environment and the C++ instance of a class, and forwards its interface back to Lua. Say for example that you have this simple class in the C++ side:

struct trivial{
    int field;
    int a_method(int arg){ return arg*3; }
}

with this library you would be able, with little instructions, to export the definition of the class to Lua, link a C++ instantiated object to a proxy, and then read/write field and call a_method from Lua. You would first define the proxy this way:

//in a compile unit
luaproxy_define(trivial){
    addmember(field);
    addmember(a_method);
}

then, to push to the Lua a proxy bound to an instance of trivial,

lua_State* l;  //l is given
luaproxy<trivial>* proxy=luaproxy_new(l, *new trivial(), true);  //don't mind the third parameter yet

Then say you have a ref mytrivial to this proxy within Lua. You can do stuff like:

print(mytrivial.field)         --fetches the field from the C++ object
mytrivial.field=42             --sets it
print(mytrivial:a_method(2))   --prints 6, actually calling trivial::a_method()

You can also build objects of type trivial from Lua, after exporting a constructor. You can either expose the default constructor:

luaproxy_luanew_default(trivial);

or have one with arguments:

luaproxy_luanew_define(test){
    //code that reads arguments from the Lua's stack
    luaproxy_new(l, new *trivial(gathered_arguments...), true);
    //l is a lua_State*, it is provided by the macro.
}

You would then be able from Lua to do like...

mytrivial=trivial.new(args...)  --args is empty in the first case.

Some design principles (review them please!)

Memory management

This is a challenging one. C++ leaves up to your responsibility everything about memory management. Lua has a gc. So one cannot (or not?) enforce an universal method to hop between the two. But here's my design. The luaproxy object itself is fully subject to the Lua gc. In fact, it also only lives in the Lua environment as a userdata. The user cannot instantiate it directly, nor call the copy constructor or assignment operator, nor destroy it (see the misuse_blockers() macro). The user can decide whether the proxy has ownership on the C++ instance: the third bool argument in luaproxy_new (see example above) tells exactly that. I'm considering to add some function to toggle ownership on and off from C++ and/or Lua.

Templatize as much as possible

The exportation is basically a lot of template magic. The methods exportation is done with variadic template (hence the need of C++11). I decided to embed in the helper template classes and functions both the type of the member pointer, and its value, for type safety and coherence. This basically means a template instantiation for each single member, but I believe that on modern hardware and with modern compilers this shouldn't be a true drawback. Also, this lets almost everything be executed at compile-time, and I also hope (see this unanswered question on stackoverflow) that the compiler is so driven to do lots of optimization, especially in the recursive trickery that reconstructs a C++ method call fetching arguments from Lua.


What has yet to be done

  • Inheritance. Zero thoughts. Ideas are much welcome.
  • const stuff. I believe that member_helper is ready for it, it's just a matter of some partial specializations. If there's even a more concise way to deal with it, please let me know. I won't bother with volatile and const volatile.
  • Pointers and reference types. Besides the idea of handling references as non-modifiable pointers, I haven't yet concretised anything in my mind.

So, please have a look at luaproxy.hpp, and tell me if you see monstrosities around. It is my first experimentation with C++11 and advanced template usage, so be understanding. An actual usage in the server mod is in src/fpsgame/luaproxy_impl.cpp

share|improve this question
sorry for not really reviewing, but why isn't LuaBridge or LuaBind enough? BTW, you can simulate variadic templates by writing out or generating the different type parameter counts – Dmitry Ledentsov Dec 7 '12 at 8:22

Know someone who can answer? Share a link to this question via email, Google+, Twitter, or Facebook.

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.