lua-users home
lua-l archive

Re: example of array AND method support for userdata?

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


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;
}

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