Upcoming Events
Southwest Gaming Expo
11/20 - 11/22 @ Dallas, TX

Workshop on Network and Systems Support for Games (NetGames 2009)
11/23 - 11/25 @ Paris, France

ICIDS 2009 Interactive Storytelling
12/9 - 12/11 @ Guimarães, Portugal

Global Game Jam
1/29 - 1/31  

More events...


Quick Stats
7353 people currently visiting GDNet.
2341 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!



Link to us

Link to us

  Intel sponsors gamedev.net search:   

Exporting C++ functions to Lua


Introduction

This whole adventure started a couple of weeks ago, when a question about using Boost.Python was posted on a Swedish game development forum where I usually lurk. I hadn’t used Boost.Python before, and I wasn’t even using Python in my current project, but I decided to take a quick look anyway. A really cool thing that I saw was that they could automatically deduce the types of the parameters for functions they were exporting, but I didn’t give it that much more thought. A little while later I started looking around for a C++ library that would let me export functions to Lua, and I stumbled upon Luabind which used a lot of the same techniques as Boost.Python. Once again, the library could automatically deduce types, and now I was really curious.

I downloaded the Luabind code and started rummaging through it. I quickly realized that the project was way beyond the scope of what I was looking to do (which was just the most basic automatic exporting of functions from C++ to Lua). But in skimming the code, I noticed that Luabind used Boost.FunctionTypes, which was a library that I'd never paid much attention to before, so I decided to check it out. And when I did, it literally blew my mind.

Boost.FunctionTypes gives you functionality to generate typelists containing the types of the parameters to any function you specify (and more!). My Spidey sense was telling me that this was all I needed to automatically generate a type-safe interface between C++ and Lua, so I decided to see were this would take me

Breaking It Down

The problem of exporting C++ functions to Lua can be broken down into a couple of distinct parts:
  • Better dispatching of the Lua callback. The Lua C interface allows you to connect a string (the function name) to a static function with a given prototype, and from this callback I had to be able to call the correct instance of the class that would handle the real executing.
  • Type checking and value extraction. Given the Lua stack, I needed to be able to traverse it, and for each value on the stack verify that it was of the correct type, and if it was, store it away somewhere until it was time to call my function.
  • Execution. At this stage, I would be holding some kind of function object that represented the C++ function I was going to call, and I also had a list of the parameters, so the problem was invoking the functor with the parameters.
  • Handling the return value. Functions that don't return anything aren't really that fun, so the final part of the puzzle was getting the return values from my C++ function back to Lua via the stack.

Better Dispatching of the Lua Callback

When dealing with function pointers to unknown types, I usually begin with a template class holding with a member variable representing the function pointer, so I started with that.

Lua states that all C callbacks we expose must have the following signature:

typedef int (*lua_CFunction) (lua_State *L);
Now this didn’t exactly match anything I had written yet, but I added the static method inside my template class, thus guaranteeing that I’d at least have a unique static method for each type of function I was exporting.

Lua allows for C closures, which enable you to associate variables, integers in this case, with a specific callback. As I had a unique static callback for each type, I knew that it would be safe to store my this pointer as an integer in the closure, and cast it back when my callback got called. This gave me the following structure:

template< class T >
struct CommandT : public Command {
  CommandT(const string& name, const T& fn) 
    : Command(name)
    , fn_(fn) 
  {}

  int Execute(lua_State* lua_state) const {
    return 1;
  }

  static int callback(lua_State* lua_state){
    const CommandT* this_ptr = reinterpret_cast<CommandT*>(lua_tointeger(lua_state, lua_upvalueindex(1)));
    return this_ptr->Execute(lua_state);
  }
  T fn_;
};
I also added a simple base class, Command, and a class to manage some state, like the Lua state, and the pointers to the Command classes that I’m creating, and gave the manager class a Register method to call where I could register function names and pointers. Register would create an instance of the CommandT class, register the callback, store a pointer to the class in the C closure of the function, and also put the pointer in an internal list so it could be deleted when we shut down.
  template< class T >
  void Register(string function_name, const T& t) {
    CommandT<T>* ptr = new CommandT<T>(function_name, t);
    // Store the this pointer in the c-closure
    lua_pushinteger(lua_state_, reinterpret_cast<int>(ptr));
    lua_pushcclosure(lua_state_, &CommandT<T>::callback, 1);
    lua_setglobal(lua_state_, function_name.c_str());
    commands_.push_back(boost::shared_ptr<Command>(ptr));
  }

Type Checking and Value Extraction

Ok, this is where it starts to get exciting! By applying the function_types::parameter_types metafunction1 we get a typelist that contains the types of the parameters of the function we want to export2. What’s even better is that this typelist is in boost::mpl format, meaning that we can manipulate the typelist using the tools available in the metaprogramming library. One of these tools is for_each, which applies a user-specified functor on each type in the typelist.

I’ve experimented a bit with functors mapped over typelists before, so I had a pretty good idea of what I wanted to do here. For each application of the functor, we’re basically walking one step down the Lua stack, and seeing if the type we get from the typelist matches the type that Lua says is on the stack. If it is, we want to get the value from the stack and store it; otherwise we signal an error in some way.

One way to implement this is by having the functor’s operator() call a method that we’ve overloaded with all the types we want to be able to handle. The overloaded method can then use Lua’s own lua_isXXX family of functions to ensure that the parameter has the correct type. The functor also holds a stack pointer, keeping track of where we are in the Lua stack, and increments this on each iteration.

class Extractor
{
public:
  Extractor(lua_State* lua_state, AnyParams& params) : lua_state_(lua_state), params_(params), stack_index_(1) {}

  void Extract(const int&) {
    if (!lua_isnumber(lua_state_, stack_index_)) {
      throw exception("Expected parameter of type interger");
    }
    params_.push_back(lua_tointeger(lua_state_, stack_index_));
  }

  void Extract(const std::string&) { 
    if (!lua_isstring(lua_state_, stack_index_)) {
      throw exception("Expected parameter of type string");
    }
    params_.push_back(string(lua_tostring(lua_state_, stack_index_)));
  }

  template< typename T >
  void operator()(T t) {
    Extract(t);
    stack_index_++;
  }
private:
  lua_State* lua_state_;
  vector<boost::any>& params_;
  int stack_index_;
};
The Extract method is overloaded for each type we want to be able to extract (double and bool have been omitted above). I’ve actually rushed ahead a little here, and also shown how I extract the values from the Lua stack. This turned out to be trivial, just adding this little guy:
typedef vector AnyParams; 
So if the value on the stack is of the correct type, we just store it in our boost::any vector. Our Execute method has been extended a little to apply the Extractor functor as well
   typedef typename parameter_types<T>::type ParamTypes;

  int Execute(lua_State* lua_state) const {
    AnyParams params;
    boost::mpl::for_each<ParamTypes>(Extractor(lua_state, params));
    return 1;
  }

1 I’m not sure of the proper name for this type of construct, and I realize that metafunction is probably wrong, as it returns a type and not a value, but it will have to do.
2 This isn’t 100% accurate, as the typelist may contain references to types, which we don’t want, so we apply a transform to the list to remove references. See the code for more details




Page 2


Contents
  Page 1
  Page 2

  Source code
  Printable version
  Discuss this article