[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Multi-dimensional C arrays in Lua
- From: sessile@...
- Date: Sun, 25 Jan 2004 00:53:00 -0500
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)