lua-users home
lua-l archive

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


It was thus said that the Great linuxfan@tin.it once stated:
> 
> >storing the lua value for my just created tables, and they work as 
> 
> >expected. Dirk said that this is not a good idea, because lua doesn't 
> 
> >assure the pointer stays valid, perhaps after a garbage collection
> 
> 
> First of all, sorry - I don't understand how to post correctly under a 
> given topic. It's easy to start a topic, not so easy to post a message 
> and make it go under the correct thread.

  Are you reading this as email or through a website?  Because email clients
offset a "respond" option that should keep the post in the current thread.  

> Second, sorry again - I don't 
> want to be pedantic, but someone could explain me better than the 
> manual?
> Here: http://www.lua.org/manual/5.2/manual.html#4.5the lua manual says 
> that a host application can store data in the registry, and also says 
> that "you should use as key a string containing your library name, ..., 
> or any Lua object created by your code". What I understand is that "lua 
> objects created by your code" means "created by the host application". 
> If so, this implies that it is safe to take the lua value for an object 
> (say, "its pointer"), and use it in whatever manner because that value 
> will never change (as long as the object exists, of course). If such a 
> value is good to be used as a key in the registry, it is also good to 
> be used as a key in the host application. or not?

  Here's a simple example.  It's in C, not Pascal, but it does illustrate
one way of handling your problem.  This is for a single structure (record)
but can be expanded to any number.

	/*--------------------------------------------------------------------
	; a name to tag our metatable for this data structure.  It's not
	; really needed for this example, but I'm using it anyway to provide
	; some addtional typechecking and in case we have any other
	; functions that might want to typecheck the metatable.
	;--------------------------------------------------------------------*/
	
	#define TYPE_FOO	"typefoo"
	
	/*---------------------------------------------------------------
	; The format of the structure (record) we want to mirror to Lua.
	;---------------------------------------------------------------*/
	
	struct foo
	{
	  char *lang;
	  int   screenwidth;
	}

	/*------------------------------------------------------------------
	; The metatable for this structure.  We can index into it (__index)
	; or set some fields (__newindex).
	;------------------------------------------------------------------*/
	
	luaL_Reg foo_meta[] =
	{
	  { "__index"	 , foometa___index	},
	  { "__newindex" , foometa___newindex	},
	  { NULL	 , NULL			}
	};
	
	/*----------------------------------------------------------------
	; pass our structure to Lua.  For this example, I'm assuming the
	; structure exists outside of Lua so we need to point to it.  We
	; define a pointer-to-a-pointer so we can point to our pre-existing
	; structure.  Lua will manage the lifetime of the
	; pointer-to-pointer, but not of the structure itself.  
	;
	; But first, we create our metatable for this structure and register
	; it with Lua.  Then we create our pointer-to-pointer, point to the
	; pre-existing structure, then associate the metatable with this
	; userdata
	;------------------------------------------------------------------*/

	int luaopen_foo(lua_State *L)
	{
	  struct foo **rfoo;
	  
	  luaL_newmetatable(L,TYPE_FOO);
	  luaL_setfuncs(L,foo_meta,0);
	  
	  rfoo  = lua_newuserdata(L,sizeof(rfoo));
	  *rfoo = global_real_foo;
	  luaL_getmetatable(L,TYPE_FOO);
	  lua_setmetatable(L,-2);
	  return 1;
	}
	
	/*-----------------------------------------------------------------
	; The __index() metamethod.  This expects our userdata and a key
	; (and for this example, we are only using strings as keys).  We
	; check the key and return the appropriate value from our
	; pre-existing structure.  The line:
	;
	; struct foo *pfoo = *(struct foo **)luaL_checkudata(L,1,TYPE_FOO);
	;
	; Does two things---it makes sure we were passed the proper userdata
	; (luaL_checkudata()) and it dereferences the pointer-to-pointer to
	; point to the actual pre-exsiting structure we want to read.
	;
	; The rest should be stright forward code.
	;-------------------------------------------------------------------*/

	int foometa___index(lua_State *L)
	{
	  struct foo *pfoo = *(struct foo **)luaL_checkudata(L,1,TYPE_FOO);
	  const char *name = luaL_checkstring(L,2);
	  
	  if (strcmp(name,"lang") == 0)
	    lua_pushstring(L,pfoo->lang);
	  else if (strcmp(name,"screenwidth") == 0)
	    lua_pushinteger(L,pfoo->screenwidth);
	  return 1;
	}
	
	/*-----------------------------------------------------------------
	; The __newindex() metamethod.  This expects our userdata, a key and
	; a value.  The preamble (getting the userdata and key) is the same
	; as above, only here instead of returning a field, we set it to a
	; new value.  The only caveat is that as written, we leak memory if
	; we keep setting the lang field.  We should really free (or
	; overwrite---it depends upon the implementation) the field.  But
	; again, this is example code.
	;-----------------------------------------------------------------*/
	
	int foometa___newindex(lua_State *L)
	{
	  struct foo *pfoo = *(struct foo**)luaL_checkudata(L,1,TYPE_FOO);
	  const char *name = luaL_checkstring(L,2);
	  
	  if (strcmp(name,"lang") == 0)
	    pfoo->lang = strdup(luaL_checkstring(L,3));
	  else if (strcmp(name,"screenwidth") == 0)
	    pfoo->screenwidth = luaL_checkinteger(L,3);
	  return 0;
	}
	
  -spc