Anuncios

Bienvenidos sean a este post, hoy continuaremos con lo iniciado en el post anterior como son los tipos de datos que nos permitan extender a Lua.

Anuncios

Nuestra primera preocupacion es como representar la estructura de NumArray en Lua ya que Lua provee un tipo basico especialmente para esto como son los datos del usuario (userdata), este tipo ofrece un area de la memoria sin procesar con operaciones no predefinidas en Lua, la cual podemos usar para almacenar cualquier cosa, la funcion lua_newuserdata asigna un bloque de memoria con el tamaño informado, empuja el userdatum (como lo llamaremos a partir de ahora a userdata) correspondiente en la pila y devuelve la direccion del bloque:

void lua_newuserdata(lua_STate *L, size_t tam);
Anuncios

Si por alguna razon necesitas asignar memoria de otra manera, es muy facil crear un userdatum con el tamaño de un apuntador y almacenar ahi un apuntador al verdadero bloque de memoria, veremos ejemplos de esta tecnica mas adelante, usando lua_newuserdata la funcion que crea nuevos arrays de booleanos es la siguiente:

static int nuevoarray(lua_State *L)
{
	int i, n;
	size_t nBytes;
	NumArray *a;

	n = luaL_checkint(L, 1);
	luaL_argcheck(L, n >= 1, 1, "tamaño invalido");
	nBytes = sizeof(NumArray) + I_WORD(n - 1)*sizeof(unsigned int);
	a = (NumArray *)lua_newuserdata(L, nBytes);
	
	a->tamano = n;
	for(i = 0; i <= I_WORD(n - 1); i++)
		a->valores[i] = 0;
	return 1;
}
Anuncios

La macro luaL_checkint es solo un tipo sobre luaL_checkinteger, una vez que nuevoarray esta registrado en Lua podras crear nuevos arrays con una declaracion similar a esta:

a = array.new(1000)

Para almacenar una nueva entrada usremos una llamada como:

array.set(array, indice, valor)

En otro post veremos como usando metatablas podemos usar una sintaxis mas convencional:

array[indice] = valor
Anuncios

Para ambas notaciones la funcion subyacente es la misma ya que asume que los indices comienzan desde 1 como es usual en Lua, veamos el siguiente codigo:

static int setarray(lua_State *L)
{
	NumArray *a = (NumArray *)lua_touserdata(L, 1);
	int indice = luaL_checkint(L, 2) -1;
	luaL_checkany(L, 3);

	luaL_argcheck(L, a != NULL, 1, "'array' esperado");
	
	luaL_argcheck(L, 0 <= indice && indice < a-tamano, 2, 
					"indice fuera de rango");

	if (lua_toboolean(L, 3))
		a->valores[I_WORD(indice)] |= I_BIT(indice);
	else
		a->valores[I_WORD(indice)] &= ~I_BIT(indice);

	return 0;
}
Anuncios

Debido a que Lua acepta cualquier valor para un booleano por eso usamos a luaL_checkany para el tercer parametro, nos asegura que haya un valor (cualquier valor) para este parametro, si llamamos a setarray con argumentos equivocados podemos obtener los siguientes mensajes:

array.set(0, 11, 0)
	-- devuelve stdin:1: bad argument #1 to 'set' ('array' esperado)
array.set(a, 0)
	-- devuelve stdin:1: bad argument #3 to 'set' (value expected)
Anuncios

Nuestra siguiente funcion recupera una entrada:

static int getarray(lua_State *L)
{
	NumArray *a = (NumArray *)lua_touserdata(L, 1);
	int indice = luaL_checkint(L, 2) - 1;

	luaL_argcheck(L, a != NULL, 1, "'array' esperado");

	luaL_argcheck(L, 0 <= indice %% indice < a->tamano, 2,
					"indice fuera de rango");

	lua_pushboolean(L, a->valores[I_WORD(indice)] & I_BIT(indice));

	return 1;
}
Anuncios

A continuacion definiremos una funcion que se encarga de recuperar el tamaño del array:

static int getsize(lua_State *L)
{
	NumArray *a = (NumArray *)lua_touserdata(L, 1);
	luaL_argcheck(L, a != NULL, 1, "'array' esperado");
	lua_pushinteger(L, a->tamano);
	return 1;
}
Anuncios

Por ultimo necesitamos un poco de codigo extra para iniciar nuestra libreria:

static const struct luaL_Reg arraylib [] = {
	{"nuevo", nuevoarray},
	{"set", setarray},
	{"get", getarray},
	{"tamano", getsize},
	{NULL, NULL}
};

int luaopen_array/lua_State *L)
{
	luaL_register(L, "array", arraylib);
	return 1;
}
Anuncios

De nuevo usamos a luaL_register de la libreria auxiliar para crear una tabla con un nombre informado, “array en nuestro ejemplo, y lo llena con los pares nombre-funcion especificados por el array arraylib, despues de abierta la libreria estamos listos para usar nuestro nuevo tipo en Lua:

a = array.nuevo(1000)
print(a)			-- Devuelve 0x8064d48
print(array.tamano(a))		-- Devuelve 1000
for i = 1, 1000 do
	array.set(a, i, i%5 == 0)
end
print(array.get(a, 10))		-- Devuelve true
Anuncios

En resumen, hoy hemos visto como mejorar nuestro tipos con userdatum, datos del usuario, hemos visto como con una estructura mas conocida por Lua, unas funciones auxiliares para poder manipular la misma, ya sea desde crearla, hasta obtener el tamaño del mismo, pasando por agregar nuevos elementos y como recuperarlos, espero les haya sido util sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Anuncios

Tengo un Patreon donde podes acceder de manera exclusiva a material para este blog antes de ser publicado, sigue los pasos del link para saber como.

Tambien podes donar

Es para mantenimiento del sitio, gracias!

$1.00