Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass C++ object to Lua function

Tags:

c++

lua

I have a C++ project, where 1 method of a 1 class changes very often. So I want to take that code from C++ to Lua. Note, I'm novice to Lua.

The whole task:

  1. Bind some class methods to Lua state machine;
  2. Pass reference to class object to a function, written in Lua;
  3. Operate with passed C++ object in Lua function.

I've found how to make first step with Lunar, and can't cope with second and third.

I can't use SWIG and boost.

like image 711
peterdemin Avatar asked Apr 05 '10 21:04

peterdemin


3 Answers

//This has a large number of steps, but I'm gonna post them all. This is all using native Lua 5 and the lua CAPI.
int CreateInstanceOfT(lua_State* L) {
    new (lua_newuserdata(L, sizeof(T))) T(constructor args);
    return 1;
}
int CallSomeFuncOnT(lua_State* L) {
    if (lua_istable(L, 1)) { // If we're passed a table, get CData
        lua_getfield(L, 1, "CData");
        lua_replace(L, 1);
    }
    if (!lua_touserdata(L, 1))
        lua_error(L); // longjmp out.
    T& ref = *(T*)lua_touserdata(L, 1);
    ref.SomeFunc(); // If you want args, I'll assume that you can pass them yourself
    return 0;
}
int main() {
    lua_State* L = luaL_newstate();
    lua_pushcfunction(L, CreateInstanceOfT);
    lua_setglobal(L, "CreateInstanceOfT");
    lua_pushcfunction(L, CallSomeFuncOnT);
    lua_setglobal(L, "CallSomeFuncOnT");
    luaL_dofile(L, "something.lua");
    lua_close(L);
}
-- Accompanying Lua code: semicolons are optional but I do out of habit. In something.lua
function CreateCInstance()
    local Instance = {
        CData = CreateInstanceOfT();
        SomeFunc = CallSomeFuncOnT;
    }
    return Instance;
end

local object = CreateCInstance();
object:SomeFunc(); // Calls somefunc.

I could post a great quantity of detail about how to make exposure easier, and how to make inheritance, and suchlike - and it'll need altering if you want to expose more than one T (I think the most common solution is a simple struct { std::auto_ptr<void>, int type } deal). But, it should be a starting point if you don't understand anything about this process.

Bascally, first, we ask Lua to allocate some space (the userdata), then put T in it. When CallSomeFuncOnT comes up, first we ask it if we have a table (many Lua classes are based around tables, as they support object orientation, metatables, and such), and get the userdata out, which we then convert into a pointer to our object, and then convert into a reference. Remember that lua_touserdata gives you a void*, so you'd better be damn sure about what's on the other end. Then we call somefunc and return. In Main, we just register the functions as globals.

Now, in Lua, when you call CreateInstanceOfT, it effectively just calls the T constructor, transparently to the Lua user. Then we ditch it in a table, which is simpler for Lua novices, and call SomeFunc by passing it this table.

like image 147
Puppy Avatar answered Nov 05 '22 08:11

Puppy


Have you taken a look at luabind? It makes it fairly easy to expose C++ objects and functions to LUA.

like image 34
John Ledbetter Avatar answered Nov 05 '22 08:11

John Ledbetter


Like John, I've used luabind and recommend it. However, since using boost isn't an option for you, you may find the list of libraries on this page helpful. You may also want to check out the DoItYourselfCppBinding page on the lua-users wiki.

One library mentioned on the page is oolua, which has no dependencies (so it says).

like image 1
Zack The Human Avatar answered Nov 05 '22 10:11

Zack The Human