[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Adding functors to Lua (C++ specific)
- From: "Joshua Jensen" <jjensen@...>
- Date: Wed, 17 Apr 2002 02:19:52 -0600
I've always had to hack my Lua callback C functions to get them to call
the
appropriate C++ member functions. There are some elegant workarounds,
such
as using Luna, but I decided to bite the bullet and just make it appear
as if
Lua directly supported more C++ style functionality.
The purpose of this article is simply to demonstrate a facility whereby
Lua
callbacks may continue to be global (or static members), as they are
now, but
also can appear under the guise of both non-virtual and virtual member
functions of ANY class.
I'm not suggesting this support be inserted into the main Lua
distribution
since the C++ nature of the code would most certainly break Lua's
portability. It would be cool to find a standard C approach (which
would
likely be nonportable, too) that could do the global, member
non-virtual,
and member virtual callbacks this patch does. Either way, I find it
sufficient to just add the support to my personal Lua environments. You
may, too.
Thanks,
Josh
---------------------------------
Step 1: Download Functor Library
---------------------------------
I don't know where Rich Hickey's current functor library is anymore, but
it
is archived at:
http://web.archive.org/web/20010404033818/www.bestweb.net/~rhickey/
Download from:
http://web.archive.org/web/20010404033818/http://www.bestweb.net/~rhicke
y/callback.zip
---------------------------------
Step 2: Make Lua compile for C++
---------------------------------
Rename all .c files to .cpp in src/, src/lib, src/lua, and src/luac.
Lua compiles
fine with .cpp files under Visual C++ 6 and 7.
---------------------------------
Step 3: Callback.hpp
---------------------------------
Copy the unzipped Callback.hpp to include/.
If on VC6/7, comment out line 264:
//#define RHCB_CANT_OVERLOAD_ON_CONSTNESS //of mem funcs
---------------------------------
Step 4: lua.h
---------------------------------
To lua.h, add:
typedef int (*lua_CFunction) (lua_State *L); // Already exists.
#include "Callback.hpp"
typedef CBFunctor1wRet<lua_State*, int> LuaFunctor;
inline LuaFunctor* LuaFunctorType()
{
return 0;
}
LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);
// Already exists.
LUA_API void lua_pushcfunctorclosure (lua_State *L, LuaFunctor fn, int
n);
---------------------------------
Step 5: lobject.h
---------------------------------
To lobject.h, change Closure to look like:
typedef struct CClosure {
lu_byte isC; // 0 for Lua functions, 1 for C functions
lu_byte nupvalues;
lu_byte marked;
union Closure *next;
lua_CFunction f;
lu_byte f2[sizeof(LuaFunctor)]; // LuaFunctor f2;
TObject upvalue[1];
} CClosure;
---------------------------------
Step 5: lapi.cpp
---------------------------------
To lapi.cpp, add:
#include <new.h> // Or wherever your placement new is.
LUA_API void lua_pushcfunctorclosure (lua_State *L, LuaFunctor fn, int
n) {
Closure *cl;
lua_lock(L);
api_checknelems(L, n);
cl = luaF_newCclosure(L, n);
cl->c.f = NULL;
::new(&cl->c.f2) LuaFunctor;
LuaFunctor* functor = (LuaFunctor*)&cl->c.f2;
*functor = fn;
L->top -= n;
while (n--)
setobj(&cl->c.upvalue[n], L->top+n);
setclvalue(L->top, cl);
api_incr_top(L);
lua_unlock(L);
}
---------------------------------
Step 6: Compile/Run/Happiness!
---------------------------------
Add the following function and class to lua.cpp:
static int LS_LOG(lua_State* L)
{
printf("In static function\n");
return 0;
}
class Logger
{
public:
int LS_LOG(lua_State* L)
{
printf("In member function\n");
return 0;
}
virtual int LS_LOGVIRTUAL(lua_State* L)
{
printf("In virtual member function\n");
return 0;
}
};
Add the following test to function main() in lua.cpp:
lua_pushcfunctorclosure(L, makeFunctor(LuaFunctorType(), LS_LOG), 0);
lua_setglobal(L, "LOG");
lua_dostring(L, "LOG()");
Logger logger;
lua_pushcfunctorclosure(L, makeFunctor(LuaFunctorType(), logger,
Logger::LS_LOG), 0);
lua_setglobal(L, "LOG2");
lua_dostring(L, "LOG2()");
lua_pushcfunctorclosure(L, makeFunctor(LuaFunctorType(), logger,
Logger::LS_LOGVIRTUAL), 0);
lua_setglobal(L, "LOG3");
lua_dostring(L, "LOG3()");