[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()");