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