diff lua/luadyncall/src/smartptr.c @ 0:0cfcc391201f

initial from svn dyncall-1745
author Daniel Adler
date Thu, 19 Mar 2015 22:26:28 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lua/luadyncall/src/smartptr.c	Thu Mar 19 22:26:28 2015 +0100
@@ -0,0 +1,158 @@
+/* lua smart pointers - version 0.2 (C only version) */
+/* (C) 2010 Daniel Adler */
+
+#include "lua.h"
+#include "lauxlib.h"
+
+#define LUA_SMARTPTR_LIBNAME "smartptr"
+#define LUA_SMARTPTR_TNAME   "SmartPtr"
+
+/*
+** lua smart pointer
+**
+** DESCRIPTION
+** the smart pointer wraps lightuserdata (lua's object type for carrying raw pointer values)
+** into a userdata structure where it also references a finalizer function, which will be called
+** with the lightuserdata (not the userdata!) as an argument.
+** 
+** 
+** LUA INTERFACE
+** smartptr = newsmartptr(lightuserdata, function)
+** setfinalizer(smartptr, function)
+** lightuserdata = tolightuserdata(integer)
+**
+*/
+ 
+typedef struct 
+{
+  const void* pointer;
+  int   finalizer; /* lua reference */
+} lua_SmartPtr;
+
+/*
+** constructs a SmartPtr userdata lua object.
+**
+** smartptr.new( pointer, finalizer )
+**
+** @param pointer
+** @param finalizer function ( to be called with pointer ) or nil
+** @return SmartPtr userdata object
+*/
+
+int lua_smartptr_new(lua_State *L)
+{
+  const void   *ptr;
+  int           ref; 
+  lua_SmartPtr *sptr; 
+  
+  if (lua_gettop(L) != 2)
+    luaL_error(L, "argument mismatch, usage:\n\tnewsmartptr( lightuserdata [, finalizer] )");
+ 
+  ptr  = lua_topointer(L, 1);
+  luaL_argcheck(L, lua_isfunction(L, 2), 2, "must be a finalizer function");
+  
+  ref = luaL_ref(L, LUA_REGISTRYINDEX);
+
+  sptr = (lua_SmartPtr*) lua_newuserdata(L, sizeof(lua_SmartPtr) );
+  
+  sptr->pointer   = ptr;
+  sptr->finalizer = ref;
+  
+  luaL_getmetatable(L, LUA_SMARTPTR_TNAME);
+  lua_setmetatable(L, -2);
+  
+  return 1;
+}
+
+/*
+** update finalizer value on SmartPtr object
+**
+** smartptr.setfinalizer(smartptr, newfinalizer)
+**
+** @param smartptr object
+** @param newfinalizer function or nil
+*/ 
+
+int lua_smartptr_setfinalizer(lua_State *L)
+{
+  lua_SmartPtr* sptr = (lua_SmartPtr*) luaL_checkudata(L, 1, LUA_SMARTPTR_TNAME);
+  if (lua_isnil(L, 2)) sptr->finalizer = LUA_REFNIL;
+  lua_rawseti(L, LUA_REGISTRYINDEX, sptr->finalizer);
+  return 0;
+}
+
+/*
+** call finalizer (internal through __gc event)
+**
+*/
+
+int lua_smartptr_callfinalizer(lua_State *L)
+{
+  lua_SmartPtr* sptr = (lua_SmartPtr*) lua_topointer(L,1);
+  int r = sptr->finalizer;
+  if (r != LUA_REFNIL) {
+    lua_rawgeti(L, LUA_REGISTRYINDEX, r);
+    lua_pushlightuserdata(L, (void*) sptr->pointer);
+    lua_call(L, 1, 0);
+    luaL_unref(L, LUA_REGISTRYINDEX, r);
+  }
+}
+
+/*
+** get pointer value
+**
+** lua_smartptr_get(smartptr)
+**
+** @return lightuserdata
+**
+*/
+
+int lua_smartptr_get(lua_State *L)
+{
+  lua_SmartPtr* sptr = (lua_SmartPtr*) lua_topointer(L,1);
+  lua_pushlightuserdata(L, (void*) sptr->pointer);
+  return 1;
+}
+
+/*
+** lua c function tolightuserdata(integer)
+**
+** @return lightuserdata 
+**
+*/
+
+int lua_tolightuserdata(lua_State *L)
+{
+  lua_Number number = lua_tonumber(L, 1);
+  lua_pushlightuserdata(L,  (void*) ( (unsigned long) number ) );
+  return 1;
+}
+
+void lua_smartptr_installmetatable(lua_State *L)
+{
+  if ( luaL_newmetatable(L,LUA_SMARTPTR_TNAME) ) {
+    lua_pushliteral(L, "__gc");
+    lua_pushcfunction(L, lua_smartptr_callfinalizer);
+    lua_settable(L, -3);
+    lua_pushliteral(L, "__call");
+    lua_pushcfunction(L, lua_smartptr_get);
+    lua_settable(L, -3);
+    lua_pop(L,1);
+  }
+}
+  
+static const struct luaL_Reg luareg_smartptr[] = 
+{
+  { "new", lua_smartptr_new },
+  { "setfinalizer", lua_smartptr_setfinalizer },
+  { "tolightuserdata", lua_tolightuserdata },
+  { NULL, NULL }
+};
+
+LUALIB_API int luaopen_smartptr(lua_State *L)
+{
+  lua_smartptr_installmetatable(L);
+  luaL_register(L, LUA_SMARTPTR_LIBNAME, luareg_smartptr);
+  return 0;
+}
+