Best way to pass a table of floats to a C function ?

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Best way to pass a table of floats to a C function ?

Luc Van den Borre
Hello all,

Right now I'm using this snippet of code to do this:

  loObject = lua_getparam(1);
  luaL_arg_check(lua_istable(loObject), 1, "table expected");
	
  lua_pushobject(loObject);
  lua_pushnumber(1);
  nNumber = lua_getnumber(lua_gettable());		

It gets the first number from the table that was passed to my C function from Lua.
However, I've got a feeling that this is a very roundabout way of doing things...

Does Lua store all values in a table in a continuous block ?
Could I perhaps just pass a pointer to this memory to my C function ?
Or am I completely barking up the wrong tree here ?

Thanks for any help,

--Luc

Reply | Threaded
Open this post in threaded view
|

Re: Best way to pass a table of floats to a C function ?

David Jeske-2
On Tue, Jun 02, 1998 at 01:22:58PM -0300, Luc Van den Borre wrote:
> Hello all,
> 
> Right now I'm using this snippet of code to do this:
> 
>   loObject = lua_getparam(1);
>   luaL_arg_check(lua_istable(loObject), 1, "table expected");
> 	
>   lua_pushobject(loObject);
>   lua_pushnumber(1);
>   nNumber = lua_getnumber(lua_gettable());		
> 
> It gets the first number from the table that was passed to my C function from Lua.
> However, I've got a feeling that this is a very roundabout way of doing things...

That looks like the right way.

> Does Lua store all values in a table in a continuous block ?
> Could I perhaps just pass a pointer to this memory to my C function ?
> Or am I completely barking up the wrong tree here ?

Uhm, the whole point of using lua is that it automagically manages things
for you with intelligent hashes and GC. If you want things to be contigous
then you should invert the relationship between Lua and your C code. Write
"table of floats" code in C, and then publish fallback mechanisms into Lua
so that when Lua code writes the table it "looks" and "works" normally,
but in actuality, it's just calling your "fast" C code to get things out
of the table.

Here is an example, there will be syntax errors (and possibly worse) in it
as I wrote it off the top of my head... 

// the ref for our tag type...

int lua_floattbl_tag = -1;

// this should be called both to register the lua "new_float_table"
// function, and to setup our tag type.

void elua_float_table_init(void) {
   lua_register("new_float_table", elua_new_float_table);

   lua_floattbl_tag = lua_newtag(); // create a new tag 

   // setup our fallback handlers
   lua_pushCclosure(etlua_read_float_table, 0);
   lua_settagmethod(lua_floattbl_tag, "gettable");

   lua_pushCclosure(etlua_write_float_table, 0);
   lua_settagmethod(lua_floattbl_tag, "settable");

   lua_pushCclosure(etlua_free_table, 0); 
   lua_settagmethod(lua_floattbl_tag, "gc"); // garbage collector!
}

// here is the C representation for our float table. As you requested, the
// floats are arranged linearly...

struct float_table_struct {
    int size;
    float data[1];  // this must be the last element in the struct!
}

// this creates a float table, pushes it into lua, and sets up the tag
// methods

void elua_new_float_table(void) {
    int tbl_ref;
    int size = luaL_get_number(1); // size of the table
    struct float_table_struct *f_tbl;
    

    // this is a neat trick for doing variable sized struct allocation
    f_tbl = malloc(sizeof(struct float_table_struct) + (size - 1) * 
	sizeof(float));

    if (!f_tbl) {
        lua_error("couldn't allocate float table");
    }

    f_tbl->size = size;

    lua_pushuserdata((void *)f_tbl);
    tbl_ref = lua_ref(0);   // get an unlocked ref for the userdata

    // set the tag of this userdata to be our float table tag
    lua_pushobject(lua_getref(tbl_ref));
    lua_settag(lua_floattbl_tag_ref);

    // return the userdata
    lua_pushobject(lua_gerref(tbl_ref));
}

// this handles people reading from the table elements

void etlua_read_float_table(void) { /* tag method */
    lua_Object floattable = lua_getparam(1); // 'table' they accessed
    struct float_table_struct *f_tbl;
    int index = lua_getnumber(lua_getparam(2)) - 1; // 'index'
       // the ' - 1' makes it so that the first element from lua is "1"
       // like all other lua tables
    

    f_tbl = (struct float_table_struct *) lua_getuserdata(floattable);
    if ((index < 0) || (index > f_tbl->size)) {
       lua_error("accessed float table out of range");
    } 

    lua_pushnumber(f_tbl->data[index]);
    
}

// this handles people writing to the table elements

void etlua_write_float_table(void) { /* tag method */
    lua_Object floattable = lua_getparam(1); // 'table' they accessed
    struct float_table_struct *f_tbl;
    int index = lua_getnumber(lua_getparam(2)); // 'index'
    

    f_tbl = (struct float_table_struct *) lua_getuserdata(floattable);
    if ((index < 0) || (index > f_tbl->size)) {
       lua_error("accessed float table out of range");
    } 

    f_tbl->data[index] = luaL_check_number(3); // assign the table entry
}

void etlua_free_table(void) { /* tag method */
    lua_Object floattable = lua_getparam(1);
    
    // the all-important "free" :)
    free(lua_getuserdata(floattable));
}

-- from lua code you do:

f_tbl = new_float_table(4);

f_tbl[2] = 2.0;
f_fbl[1] = 1.5;
f_tbl[3] = 7;
f_tbl[4] = 8.0;

f_tbl[0] = 2;  -- these are both invalid
f_tbl[5] = 6;  -- access of the table

another_c_function(f_tbl);

// now in "another_c_function" you can find out that it's one of your
// float tables and access it directly

void elua_another_c_function(void) { /* exported to lua with lua_register */
    lua_Object arg = lua_getparam(1);
    struct float_table_struct f_tbl;

    if (lua_floattbl_tag != lua_tag(arg)) {
       lua_error("invalid argument, should have been a float_table");
    }

    f_tbl = (struct float_table_struct *)lua_getuserdata(arg);

    // now we have the real C table, so use it directly!

    if (f_tl->size < 4) {
       lua_error("you passed me a table which is too small");
    }

    f_tbl->data[2] = 3;
    f_tbl->data[1] = 2;

}



-- 
David Jeske (N9LCA) + http://www.chat.net/~jeske/ + [hidden email]