[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: example of array AND method support for userdata?
- From: Sam Roberts <sroberts@...>
- Date: Thu, 31 Aug 2006 11:44:24 -0700
On Wed, Aug 30, 2006 at 11:56:42AM -0700, Sam Roberts wrote:
> I was following through PILv1 online, but it abruptly ended before
> discussing how to have both methods like a:size() AND array
> indexors like a[2] = 5 or a.some_field = "value" for user data.
I rewrote in C, and added both implementations to
http://lua-users.org/wiki/ObjectProperties
where it might be useful to others trying to have what this page calls
"properties" for userdata.
Usage is as:
o = array:new(3)
print(o:size())
o[1] = 1
o[2] = 2
o[3] = 3
print(o:get(2))
o:set(3, -1)
print(o[3])
Cheers,
Sam
/*
Rewrite in C of array example from http://www.lua.org/pil/28.4.html that
implements both array and OO access.
Lacks bounds checking, its not pertinent to this example.
*/
#include "lauxlib.h"
#include "lua.h"
#include <assert.h>
#include <stdint.h>
#include <string.h>
#define ARRAY_REGID "22d3fa81-aef3-4335-be43-6ff037daf78e"
#define ARRAY_CLASS "array"
struct array {
lua_Integer size;
lua_Number data[1];
};
typedef struct array* array;
static array array_check(lua_State* L, int index)
{
void* userdata = luaL_checkudata(L,index,ARRAY_REGID);
assert(userdata);
return userdata;
}
int array_new(lua_State* L)
{
// Ignoring [1], the "array" global table.
int size = luaL_checkinteger(L, 2);
array self = (array) lua_newuserdata(L,sizeof(*self) + (size-1) * sizeof(self->data));
self->size = size;
for(size = 0; size < self->size; size++)
self->data[size] = 0;
luaL_getmetatable(L, ARRAY_REGID);
lua_setmetatable(L, -2);
return 1;
}
int array_size(lua_State* L)
{
array self = array_check(L, 1);
lua_pushinteger(L, self->size);
return 1;
}
int array_get(lua_State* L)
{
array self = array_check(L, 1);
lua_Integer i = luaL_checkinteger(L, 2);
// TODO bounds checking on i
lua_pushnumber(L, self->data[i-1]);
return 1;
}
int array_set(lua_State* L)
{
array self = array_check(L, 1);
lua_Integer i = luaL_checkinteger(L, 2);
lua_Number v = luaL_checknumber(L, 3);
// TODO bounds checking on i
self->data[i-1] = v;
return 0;
}
int array_index(lua_State* L)
{
const char* key = luaL_checkstring(L, 2);
lua_getmetatable(L, 1);
lua_getfield(L, -1, key);
// Either key is name of a method in the metatable
if(!lua_isnil(L, -1))
return 1;
// ... or its a field access, so recall as self.get(self, value).
lua_settop(L, 2);
return array_get(L);
}
static const struct luaL_reg array_class_methods[] = {
{ "new", array_new },
{ NULL, NULL }
};
static const struct luaL_reg array_instance_methods[] = {
{ "get", array_get },
{ "set", array_set },
{ "size", array_size },
{ "__index", array_index },
{ "__newindex", array_set },
{ NULL, NULL }
};
int array_open(lua_State* L)
{
luaL_newmetatable(L, ARRAY_REGID);
luaL_openlib(L, NULL, array_instance_methods, 0);
luaL_openlib(L, ARRAY_CLASS, array_class_methods, 0);
return 1;
}