lua-users home
lua-l archive

Re: Multi-dimensional C arrays in Lua

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


At 07:13 PM 1/22/2004 -0500, Diego Nehab wrote:
Hi,
> I'm wondering if there is some elegant trickery
> I'm not grasping at the moment that would allow
> the access to be written as simply:
>
> x = myarray[1][2]
I once implemented something ugly: myarray had a gettable metamethod
that returned a userdata pointing to the begining of a given row. This
temporary userdata had a different gettable method, that returned the
value at a given column. Back in those days, all userdata were light,
and supported metamethods. Not sure how bad this would be now that
userdata with metamethods are heavy.
[]s,
Diego.
I had started down the road of creating temporary userdata(s?) as well.
It occurred to me today that the "__index" and "__newindex" methods
could probably be tricked into accepting "myarray[1][2]" without the
temporaries being created by manipulating an extra field in the original
userdata ("row" in the following example).
Thanks to "Programming in Lua" for a little inspiration. :)
Regards,
Dean.
(Dumb C question: is there a shorter way to initialize matrix->xform?)
/*** file: larray2d.c ***/
#include "lauxlib.h"
#include "lua.h"
#define ARRAY2D "array2d"
typedef float array2d[4][4];
typedef struct larray2d {
 lua_State *L;
 array2d xform;
 int row;
} larray2d;
static larray2d *checkmatrix (lua_State *L) {
 void *ud = luaL_checkudata(L, 1, ARRAY2D);
 luaL_argcheck(L, ud != NULL, 1, "'array2d' expected");
 return (larray2d *)ud;
}
static int newmatrix (lua_State *L) {
 size_t nbytes = sizeof(larray2d);
 larray2d *matrix = (larray2d *)lua_newuserdata(L, nbytes);
 luaL_getmetatable(L, ARRAY2D);
 lua_setmetatable(L, -2);
 matrix->xform[0][0] = 1.1; matrix->xform[0][1] = 1.2;
 matrix->xform[0][2] = 1.3; matrix->xform[0][3] = 1.4;
 matrix->xform[1][0] = 2.1; matrix->xform[1][1] = 2.2;
 matrix->xform[1][2] = 2.3; matrix->xform[1][3] = 2.4;
 matrix->xform[2][0] = 3.1; matrix->xform[2][1] = 3.2;
 matrix->xform[2][2] = 3.3; matrix->xform[2][3] = 3.4;
 matrix->xform[3][0] = 4.1; matrix->xform[3][1] = 4.2;
 matrix->xform[3][2] = 4.3; matrix->xform[3][3] = 4.4;
 matrix->row = 0;
 return 1;
}
static int getmatrix (lua_State *L) {
 larray2d *matrix = checkmatrix(L);
 int index = luaL_checkint(L, 2);
 luaL_argcheck(L, 1 <= index && index <= 4, 2, "index out of range");
 if (matrix->row == 0) {
 matrix->row = index;
 lua_settop(L, 1);
 } else {
 lua_pushnumber(L, matrix->xform[(matrix->row-1)][index-1]);
 matrix->row = 0;
 }
 return 1;
}
static int setmatrix (lua_State *L) {
 larray2d *matrix = checkmatrix(L);
 int index = luaL_checkint(L, 2);
 float value = (float)luaL_checknumber(L, 3);
 luaL_argcheck(L, 1 <= index && index <= 4, 2, "index out of range");
 if (matrix->row == 0) {
 luaL_error(L, "set failed: Row = %d, Col = ?", index);
 } else {
 matrix->xform[(matrix->row-1)][index-1] = value;
 matrix->row = 0;
 }
 return 0;
}
static int matrix2string (lua_State *L) {
 lua_pushstring(L, "Not implemented?");
 return 1;
}
static const struct luaL_reg array2d_meths[] = {
 {"__tostring", matrix2string},
 {"__index", getmatrix},
 {"__newindex", setmatrix},
 {NULL, NULL}
};
static const struct luaL_reg array2d_funcs[] = {
 {"new", newmatrix},
 {NULL, NULL}
};
LUALIB_API int luaopen_array (lua_State *L) {
 luaL_newmetatable(L, ARRAY2D);
 lua_pushliteral(L, "__index");
 lua_pushvalue(L, -2);
 lua_rawset(L, -3);
 luaL_openlib(L, NULL, array2d_meths, 0);
 luaL_openlib(L, ARRAY2D, array2d_funcs, 0);
 return 1;
}
/****************************/
x = array2d.new()
y = array2d.new()
for i=1,4 do
 for j=1,4 do
 print(string.format("%2.1f", x[i][j]))
 end
end
for i=1,4 do
 for j=1,4 do
 x[i][j] = 0
 end
end
y[4] = 0 -- error! (expected)

AltStyle によって変換されたページ (->オリジナル) /