lua-users home
lua-l archive

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


On Mon, Oct 12, 2009 at 3:06 PM, liam mail <liam.list@googlemail.com> wrote:
>
>
> 2009/10/12 Jerome Vuarand <jerome.vuarand@gmail.com>
>>
>> 2009/10/12 liam mail <liam.list@googlemail.com>:
>> > Whilst integrating C++ with Lua which enables the passing of C++ objects
>> > to
>> > Lua, calling methods, operators and vice versa I have encountered a
>> > problem
>> > with my current implementation. I use the method with is described on
>> > the
>> > wiki entitled Luna and which is also described in many other
>> > publications
>> > such as Game Programming Gems.
>> > The crux of my problem is that a new user data is only created when an
>> > object is currently not alive in Lua, when it is the pointer which was
>> > returned when the lua_newuserdata was created is pushed onto the stack
>> > using
>> > lua_pushlightuserdata and has it's metatable attached. This metatable
>> > defines the functions to be called for the operators such as __eq and
>> > __le;
>> > yet a lightuserdata is only equal to itself and does not look at the
>> > metatable to see if the operator is defined for the type, whilst it does
>> > look at the metatable for methods.
>> >
>> > Is there a way whilst still using the operators instead of say a le
>> > function
>> > (obj:le(rhs)) to accomplish this, or is using this type of function for
>> > the
>> > operator or using a table to represent the data the only method. Ie. is
>> > there a way to trick Lua into looking at the metatable of the
>> > lightuserdata
>> > for the operators without modifying the source of Lua itself?
>>
>> Your first paragraph is a little confusing. I'm not sure what you did
>> exactly, and what userdata is full or light.
>>
>> Light userdata are not meant to represent objects, but rather as a
>> convenience to pass C values around. If you have a C object that you
>> want to manipulate from Lua you should embed them in a full userdata.
>> You cannot push a full userdata. What you can do however is associate
>> a userdata with its address in some table (e.g. the registry), and
>> from the address you can push back the full userdata with a table
>> indexing operation (lua_gettable).
>
> Sorry for the confusion I will try to explain again :)
> Say for example a C++ class instance is pushed to Lua twice for a Lua
> function parameters. The first time it is detected that the instance is not
> currently valid in Lua and therefore a full userdata is created and the
> returned pointer is stored to enable the validity check and also to allow it
> being exchanged again. When the same instance is passed the second time it
> is detected that the instance is valid in Lua,  the pointer instance
> returned by the creating of the full user data is pushed onto the stack and
> the types metatable is associated with the light user data.
> This enables methods to be called on the light user data via a lookup in the
> metatable yet fails on the operators.
>
> Are you suggesting that the second time it is pushed the pointer returned
> from creating the full user data is pushed onto the stack then lua_gettable
> is called and this will enable the type to be seen as a full user data? If I
> do this is there still a need to attach the types metatable to the table
> pushed onto the stack via lua_gettable or should it be valid?
> Thanks.
>

Hello liam,

I think you may have misunderstood something about the way you should
use userdata. This is a simplified example of how you generally want
to handle using light and full userdata together:

void PushMyObject(lua_State* L, MyObject* myObject) {
  lua_pushlightuserdata(L, (void*)myObject);
  lua_gettable(L, LUA_REGISTRYINDEX);
  if (lua_isnil(L,-1)) {
    MyObject** new_wrapped_ptr = (MyObject**)lua_newuserdata(L,
sizeof(myObject*));
    *new_wrapped_ptr = myObject;
    lua_pushlightuserdata(L, (void*)myObject);
    lua_pushvalue(L, -2);
    lua_gettable(L, LUA_REGISTRYINDEX);
  }
}

...i.e. the light userdata value (which should contain the actual
pointer to the C++ object you are trying to store itself, *not* the
pointer to the full userdata that you are getting back from
lua_newuserdata to store that pointer) is only used as a *key* to
store the full userdata in the registry. Light userdata values should
(usually) not be manipulated by actual Lua code, it is (usually) more
of a behind-the-scenes, API tool. (I'm sure there are exceptions to
this that people have, but I don't think it is very common.)

-Duncan