lua-users home
lua-l archive

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


2011/4/13 Javier Guerra Giraldez <javier@guerrag.com>:
> AFAICT, a cdata value is just a wrapper for.... C data
>
> what API would you need to pass C data to a C function?

Well, I did think more about this point and I at some point I realized
something. I understood that LuaJIT2 plus FFI introduce a new paradigm
for calling C function and the old Lua methodology in some cases
doesn't make sense anymore.

I will try to explain better. The standard Lua method to access C
function is to create ad hoc a Lua C function with the following
prototype:

int my_lua_function (lua_State *L);

and to call the C functions you need inside this function
implementation. In this case you need a complete set of Lua C API to
bridge the Lua values passed as arguments to C values that you can use
with standard C operations. In the Lua C function you can also perform
Lua operations by using the C API like lua_pushvalue, lua_rawget et
things like that.

>From this point of view my remark was correct in the sense that all
the Lua types have corresponding C API function to retrieve them and
push them on the Lua stack except cdata.

For the other side I realized that with LuaJIT2 and FFI you don't need
anymore to implement a classic Lua C function to wrap the call to the
low level C functions. You can call directly the low level C function
using FFI or, in alternative, you can define a new Lua function that
can perform some Lua operations and call the low level C functions
when needed.

Here a give an example to use the GSL library to compute the square of a matrix.

Example with old Lua paradigm:

int matrix_square (lua_State *L)
{
   /* We retrive a userdata and cast it to the appropriate pointer type.
     This is unsafe and in production code the type of the argument should
     be checked. */
   gsl_matrix *m = lua_touserdata (L, 1);

   /* push a new matrix inizialized to zero into the Lua stack
      and return a pointer to it */
   gsl_matrix *r = new_gsl_matrix (L, m->size1, m->size2);

   /* perform the matrix multiplication and store the result in r */
   gsl_blas_dgemm (CblasNoTrans, CblasNoTrans, 1.0, m, m, 1.0, r);

   /* we return the newly allocated matrix that is already in the stack */
   return 1;
}

with LuaJIT2 plus FFI you can do:

function square(m)
   local r, c = matrix.dim(r, c)
   local x = matrix.new(r, c)
   gsl.gsl_blas_dgemm (gsl.CblasNoTrans, gsl.CblasNoTrans, 1, m, m, 1, x)
   return x
end

in the example above we suppose that our matrix object is just a cdata
object that correspond to the ctype 'gsl_matrix'. The function
matrix.new should return a newly allocated matrix initialized to 0.
The suppose that gsl point to the FFI library with gsl functions, it
could be obtained with:

gsl = ffi.load('libgsl-0')

Actually the new methodology based on FFI is much more convenient
because you don't need to write and compile boiler plate C code but
you just have plain Lua function and FFI call to C functions.

Please note that to adopt the ne methodology you need to switch from a
userdata object implementation into a cdata implementations. Normally
you cannot mix them freely even if some mixed operations are possible.
This methodology is possible because now cdata support metatables.
Before it was very difficult because a proxy was needed or otherwise
no metatable facilities were available.

So, my request for C API was logical if we think in term of the old
Lua C function but if you adopt the new FFI paradigm you don't need
the C API anymore, you just write Lua code and directly call C
functions when needed.

-- 
Francesco