lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


It was thus said that the Great Jairo A. del Rio once stated:
> Hi, list. I'm trying to understand how to write Lua modules from C (I use
> GSL as an example). Code is below.

  I have many C based Lua modules written by hand, you can look at:

	https://github.com/spc476/lua-conmanorg/tree/master/src

  The closest one I have to what you are trying to do is tcc.c.  I don't
think you need to really understand what it does (it wraps the Tiny C
compiler as a Lua module).

  In any case, let's go through your code:

> #include <gsl/gsl_vector.h>
> #include "lua.h"
> #include "lauxlib.h"
> 
> #define VECTOR_MT "GSL vector"
> 
> static int vector_new(lua_State *L)
> {
>   int i;
>   int n = lua_gettop(L);
>   gsl_vector *t = gsl_vector_alloc(n);
>   for (i = 0; i < n; i++)
>   {
>     gsl_vector_set(t, i, luaL_checknumber(L,i+1));
>   }
> //Is this right?
>   gsl_vector *r = (gsl_vector *)lua_newuserdata(L, sizeof(gsl_vector));
>   *r = *t;
>   luaL_getmetatable(L, VECTOR_MT);
>   lua_setmetatable(L, -2);
>   return 1;
> }

  Almost there---
  
	static int vector_new(lua_State *L)
	{
	  int i;
	  int n = lua_gettop(L);
	  gsl_vector *v = gsl_vector_alloc(n);
	  for (i = 0 ; i < n ; i++)
	    gsl_vector_set(v,i,luaL_checknumber(L,i + 1));
	  
	  gal_vector **r = lua_newuserdata(L,sizeof(gsl_vector *)); /* [1] */
	  *r = v;
	  luaL_setmetatable(L,VECTOR_MT); /* [2] */
	  return 1;
	}

[1] 	Since the GLS library is doing the allocation, let it.  Here, we are
	defining r to be a pointer to a pointer to a GSL vector, which is
	the space that Lua will manage.  You will need to add a __gc
	metamethod though.  This will work:
	
	static int vector___gc(lua_State *L)
	{
	  gsl_vector **v = luaL_checkudata(L,1,VECTOR_MT); /* [3] */
	  if (*r != NULL)
	  {
	    gsl_vector_free(*r); /* [4] */
	    *r = NULL;
	  }
	  
	  return 0;
	}

[2]	If you are using Lua 5.1, you can replace this function with:

		luaL_getmetatable(L,VECTOR_MT);
		lua_setmetatable(L,-2);
		
[3]	If you are using a C compiler (and NOT a C++ compiler) you don't
	need the pointer casts.  Also, what you are getting back here is a
	pointer to a pointer to a GSL thing.

[4]	Since we have a pointer to a pointer to a GSL objet, this will
	dereference the pointer-to-pointer to get the pointer.
 
> static int vector_get(lua_State *L)
> {
>   gsl_vector *v = (gsl_vector *)lua_touserdata(L,1);
>   int max = (int)v->size;
>   int n = luaL_checkinteger(L,2)-1;
>   if ((0<=n) && (n <= max))
>     lua_pushnumber(L, gsl_vector_get(v,n));
>   else
>     lua_pushnil(L);
>   return 1;
> }

	gsl_vector **r = luaL_checkudata(L,1,VECTOR_MT);
	gsl_vector  *v = *r; /* get to the actual object */
	
  The rest is fine.
  
> static int vector_m_add(lua_State *L)
> {
>   gsl_vector *v1 = (gsl_vector *)lua_touserdata(L,1);
>   gsl_vector *v2 = (gsl_vector *)lua_touserdata(L,2);
>   if ((v1 -> size) == (v2 -> size))
>   {
> // I'm not sure whether this is right or not, but it seems to work so far
>     gsl_vector *t = gsl_vector_alloc(v1 -> size);
>     gsl_vector_memcpy(t, v1);
>     gsl_vector_add(t,v2);
>     gsl_vector *r = (gsl_vector *)lua_newuserdata(L, sizeof(gsl_vector));
>     luaL_getmetatable(L, VECTOR_MT);
>     lua_setmetatable(L, -2);
>     *r = *t;
>   }
>   else
>   {
>     lua_pushnil(L);
>   }
>   return 1;
> }

  Follow the code in vector_new().

  [ snip rest of code---no comments, looked decent ]
  
> I have two questions:
> 
> 1. Am I right wrt "new", i.e., the way userdata is created?

  Not quite.  You're close though.
  
> 2. According to some docs I've read, userdata content should be freed by
> defining a function for __gc. However, I don't understand when or how to do
> that, as defining a function using gsl_vector_free in the case above is
> giving me an error prompt complaining about an invalid pointer.

  That's probably because you're passing in memory allocated by Lua and the
GSL library is getting confused.  See the vector___gc() function for how to
do this safely.

> I don't want a ready-made application to create bindings to GSL or an
> already existing one (I think two are freely available in GitHub) as I only
> use it as an example. I don't want a Lua solution, either (I know how to do
> that using pure Lua). Instead, I want to better understand the way Lua
> modules are defined when C is used, and perhaps to better understand C
> given that pointers are not intuitive for me. Thank you in advance and
> sorry for any inconvenience caused by this noob question.

  Don't apologize---you tried, and you showed your work.  That's commendable
in and of itself.  Yes, pointers in C can be confusing, especially pointers
to pointers (which, unfortunately, you need here).  I hope the code I
presented will help you in your endevour.

  -spc