lua-users home
lua-l archive

[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)