lua-users home
lua-l archive

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


Hello Sean
 
Thanks for showing that detailed example, it was exactly what I was looking for, I managed to understand that example much better than the online examples. I tweaked it a little bit to change the memory allocation for my oddball OS, and corrected a minor typo in the range check for the bar indexer funtion. It worked first time when I tried it, I debugged the C source  to check the gc call was working OK and doing what it should, and added a few extra Lua lines to check out the __len method, all seemed fine.
 
My next experiment will be to try to change it so that C creates the memory and Lua doesnt manage the memory allocs.
 
Thanks again
 
Geoff
 
> Date: Mon, 29 Aug 2011 01:10:39 -0400
> From: sean@conman.org
> To: lua-l@lists.lua.org
> Subject: Re: Struggling with userdata concepts
>
> It was thus said that the Great Jeff Smith once stated:
>
> > Thanks for the suggestion, but I am already using SWIG in the embedded
> > project I am working on. I chose Swig as it had the advantage of not having
> > any Windows dependencies, so it was pretty easy to use in an embedded
> > environment. I have found it has some limitations, for example as far as I
> > can see it cannot really handle arrays of data, hence my question here.
> >
> > Besides, I wanted to gain an understanding of the Lua C API, so I was happy
> > to go with a hybrid approach, SWIG for some bindings and manuallly written
> > binding code for some of the things that SWIG didnt handle. So far its
> > working out well, and its easy to mix and match SWIG bound code and manual
> > code.
> >
> > I just need to figure out this userdata stuff as it is obviously pretty
> > important in getting a good handle on understanding the Lua/C API. Pity I
> > dont think I can use the light userdata as I now understand that
> > sufficiently. I wonder if anyone has got time to post a full user data
> > example to contrast with the light userdata example earlier in this thread ?
> > I am sure it would help other folks in the future apart from just me !
>
> I just whipped this up. There are two different userdata objects created,
> one that uses strings for indicies, and another one that uses numeric
> indicies. They don't have to be separate objects, I just did it that way to
> keep things easy. So first, the code:
>
>
> #include <string.h>
>
> #include <lua.h>
> #include <lualib.h>
> #include <lauxlib.h>
>
> #define MAX_BAR 10
> #define FOO_TYPE "FOO"
> #define BAR_TYPE "BAR"
>
> /******************************************************************/
>
> struct bar
> {
> int data[MAX_BAR];
> };
>
> struct foo
> {
> int x;
> int y;
> int z;
> int xyzzy;
> char *blah;
> };
>
> /******************************************************************/
>
> static int foolua___index(lua_State *L)
> {
> struct foo *pfoo;
> const char *idx;
>
> pfoo = luaL_checkudata(L,1,FOO_TYPE);
> if (lua_isstring(L,2))
> {
> idx = lua_tostring(L,2);
> if (strcmp(idx,"x") == 0)
> lua_pushinteger(L,pfoo->x);
> else if (strcmp(idx,"y") == 0)
> lua_pushinteger(L,pfoo->y);
> else if (strcmp(idx,"z") == 0)
> lua_pushinteger(L,pfoo->z);
> else if (strcmp(idx,"xyzzy") == 0)
> lua_pushinteger(L,pfoo->xyzzy);
> else if (strcmp(idx,"confuse a cat") == 0)
> lua_pushstring(L,pfoo->blah);
> else
> lua_pushnil(L);
> }
> else
> lua_pushnil(L);
>
> return 1;
> }
>
> /******************************************************************/
>
> static int foolua___newindex(lua_State *L)
> {
> struct foo *pfoo;
> const char *idx;
>
> pfoo = luaL_checkudata(L,1,FOO_TYPE);
>
> if (lua_isstring(L,2))
> {
> idx = lua_tostring(L,2);
> if (strcmp(idx,"x") == 0)
> pfoo->x = luaL_checkint(L,3);
> else if (strcmp(idx,"y") == 0)
> pfoo->y = luaL_checkint(L,3);
> else if (strcmp(idx,"z") == 0)
> pfoo->z = luaL_checkint(L,3);
> else if (strcmp(idx,"xyzzy") == 0)
> pfoo->xyzzy = luaL_checkint(L,3);
> else if (strcmp(idx,"confuse a cat") == 0)
> {
> const char *val;
> size_t vsize;
>
> free(pfoo->blah); /* free(NULL) valid in C89 */
> val = luaL_checklstring(L,3,&vsize);
> vsize += 1; /* include trailing NUL byte */
> pfoo->blah = malloc(vsize);
> if (pfoo->blah)
> memcpy(pfoo->blah,val,vsize);
> }
> }
> return 0;
> }
>
> /******************************************************************/
>
> static int foolua___gc(lua_State *L)
> {
> struct foo *pfoo;
>
> pfoo = luaL_checkudata(L,1,FOO_TYPE);
> free(pfoo->blah);
> pfoo->blah = NULL;
> return 0;
> }
>
> /******************************************************************/
>
> static int foolua_new(lua_State *L)
> {
> struct foo *pfoo;
>
> pfoo = lua_newuserdata(L,sizeof(struct foo));
> memset(pfoo,0,sizeof(struct foo));
> pfoo->blah = NULL; /* required---too long to describe why */
> luaL_getmetatable(L,FOO_TYPE);
> lua_setmetatable(L,-2);
> return 1;
> }
>
> /******************************************************************/
>
> static int barlua___index(lua_State *L)
> {
> struct bar *pbar;
> int idx;
>
> pbar = luaL_checkudata(L,1,BAR_TYPE);
> if (lua_isnumber(L,2))
> {
> idx = lua_tointeger(L,2) - 1;
> if (idx > MAX_BAR)
> lua_pushnil(L);
> else
> lua_pushinteger(L,pbar->data[idx]);
> }
> else
> lua_pushnil(L);
>
> return 1;
> }
>
> /******************************************************************/
>
> static int barlua___newindex(lua_State *L)
> {
> struct bar *pbar;
> int idx;
> int val;
>
> pbar = luaL_checkudata(L,1,BAR_TYPE);
> val = luaL_checkint(L,3);
>
> if (lua_isnumber(L,2))
> {
> idx = lua_tointeger(L,2) - 1;
> if (idx < MAX_BAR)
> pbar->data[idx] = val;
> }
>
> return 0;
> }
>
> /******************************************************************/
>
> static int barlua___len(lua_State *L)
> {
> struct bar *pbar;
>
> pbar = luaL_checkudata(L,1,BAR_TYPE);
> lua_pushinteger(L,MAX_BAR);
> return 1;
> }
>
> /******************************************************************/
>
> static int barlua_new(lua_State *L)
> {
> struct bar *pbar;
>
> pbar = lua_newuserdata(L,sizeof(struct bar));
> memset(pbar,0,sizeof(struct bar));
> luaL_getmetatable(L,BAR_TYPE);
> lua_setmetatable(L,-2);
> return 1;
> }
>
> /******************************************************************/
>
> static const luaL_Reg m_foobarreg[] =
> {
> { "new_foo" , foolua_new } ,
> { "new_bar" , barlua_new } ,
> { NULL , NULL }
> };
>
> static const luaL_Reg m_foometareg[] =
> {
> { "__index" , foolua___index } ,
> { "__newindex" , foolua___newindex } ,
> { "__gc" , foolua___gc } ,
> { NULL , NULL }
> };
>
> static const luaL_Reg m_barmetareg[] =
> {
> { "__index" , barlua___index } ,
> { "__newindex" , barlua___newindex } ,
> { "__len" , barlua___len } ,
> { NULL , NULL }
> };
>
> int luaopen_foobar(lua_State *L)
> {
> luaL_newmetatable(L,FOO_TYPE);
> luaL_register(L,NULL,m_foometareg);
> luaL_newmetatable(L,BAR_TYPE);
> luaL_register(L,NULL,m_barmetareg);
> luaL_register(L,"foobar",m_foobarreg);
> return 1;
> }
>
> /********************************************************************/
>
> The Lua code here manages the memory for the objects---it doesn't have to
> and the changes are rather minimal (basically, have Lua manage pointers to
> the pre-defined structures). Both objects support the Lua __index() and
> __newindex() methods, and I have an example of both __gc() and __len()
> metamethods. Here's a sample run:
>
> [spc]lucy:~/source/lua/C>lua
> Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
> > require "foobar"
> > x = foobar.new_foo()
> > x.x = 4
> > x.xyzzy = 5
> > x['confuse a cat'] = "hello"
> > print(x.x,x.xyzzy,x['confuse a cat'])
> 4 5 hello
> >
>
> -spc (Hope this clears up some issues)
>
>