lua-users home
lua-l archive

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


Am 21.08.2015 um 04:01 schröbte Coda Highland:
On Thu, Aug 20, 2015 at 6:55 PM, Philipp Janda <siffiejoe@gmx.net> wrote:
Am 21.08.2015 um 03:27 schröbte William Ahern:

On Fri, Aug 21, 2015 at 12:55:46AM +0200, Philipp Janda wrote:

Am 21.08.2015 um 00:21 schröbte Rena:

On Aug 20, 2015 6:05 PM, "Roberto Ierusalimschy"
<roberto@inf.puc-rio.br>
wrote:

if we want to put some extra bits in
'TValue' to good use and solve the OP problem, maybe a better idea
would
be to introduce metatables for light userdata.


That would be excellent. I find it difficult to find much real use for
light userdata with only a single global metatable.


That would be another welcome feature, but lightuserdata pointing into
full
userdata is unsafe: the full userdata could be collected without the
lightuserdata realizing/preventing that.


You wouldn't do that. You would store the reference to the full userdata
in
the metatable, not as the lightuserdata value. The lightuserdata would
only
contain the offset. That would require only one unique metatable per full
userdata, not per lightuserdata proxy.


That depends. If you have something like

     typedef struct {
       B b1;
       B b2;
       B b3;
     } A;

     a1 = newuserdata( sizeof( A ) );
     a2 = newuserdata( sizeof( A ) );

then you can reuse the same metatable for a1.b1, a1.b2, and a1.b3, but
you'll need a different metatable for a2.b1, a2.b2, and a2.b2. Also you'll
have trouble passing a1.b1 and a2.b1 to a function unless you invent a new
way to typecheck arguments (they have different metatables, so something
`luaL_checkudata` is out of the question).

That's actually pretty easy -- if they're offsets, then their numeric
value represents their type. If they're pointers, then their numeric
value minus the numeric value of the userdata itself represents their
type. You can't do this from the Lua side but the C function to do so
would be pretty trivial.

And if you go with one of the various user-defined type schemes
discussed on this list, you could include a __type() function on the
metatable that would be able to do this and return a nice friendly
string.

If you have something like

     typedef struct {
       D d;
       E e;
       F f;
     } C;

     c1 = newuserdata( sizeof( C ) );
     c2 = newuserdata( sizeof( C ) );

you'd need a separate metatable for all c1.d, c1.e, c1.f, c2.d, c2.e, and
c2.f. Basically, you would allocate a new metatable instead of a userdata
for every `__index` operation.

You wouldn't need to allocate a metatable for d, e, and f. The backend
code would be able to say "Oh, this lightuserdata points to a userdata
of type C and we're expecting an object of type E. But the offset says
we can (or can't) cast the pointer to E safely."

Basically it's RTTI.

So we are basically using the difference between the lightuserdata pointer and the full userdata pointer as tag value. Actually, you don't even need to point into the full userdata. You could emulate the user-defined tag proposal using something like:

    static char tagarray[ N_TAGS ];
    // ...
      lua_pushlightuserdata( L, tagarray+3 );  /* push tag number 4 */
      luaL_getmetatablesomehow( L );
      lua_setmetatable( L, -2 );

and get the full user data pointer from the metatable, and the tag value via `lua_topointer( L, 1 ) - tagarray)`.

I could work with that ...


/s/ Adam


Philipp