[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Feature request: userdata slice
- From: Philipp Janda <siffiejoe@...>
- Date: Wed, 19 Aug 2015 11:40:31 +0200
Am 19.08.2015 um 09:53 schröbte Tim Hill:
I’m not clear what your actual problem is, as you seem to be
suggesting a solution without really saying what the underlying
problem you are trying to solve is. What I *think* you are saying is
that you wish to expose two distinct userdata values that have the
same lifetime from a GC standpoint, but I’m not clear why you need to
do this.
Imagine you have a struct type in C that you want to manipulate from Lua
as a userdata:
typedef struct {
/* contents not really important here */
} A;
The C library can give you an object of that type in many different ways:
1. The "usual" way: You allocate the memory yourself (via
`lua_newuserdata` in this case) and the C library provides you with an
"A_init" and an "A_clear" function that you call at appropriate times.
2. As a pointer: The constructor C function (let's call it "A_new")
allocates the necessary memory itself and handles you an `A*`. "A_free"
takes that pointer and destroys the object. You could have multiple
"A_new"/"A_free" pairs (e.g. the `FILE*` type in the Lua io library).
3. As a preexisting C object: It could be a global variable in C or
just an object that outlives the Lua state. This is similar to 2. in
that you put a pointer in your userdata, but you don't have
constructor/destructor functions (and if you store the destructor in the
userdata, this case can be handled like 2. using a NULL pointer as the
destructor).
4. As part of another userdata:
typedef struct {
A a; /* could also be `A* a` */
} B;
This is similar to 3., but the lifetime of the A pointer depends on the
lifetime of the B userdata: The B userdata must not be collected as long
as the A userdata is still in use. You don't need
constructors/destructors, because the B userdata already handles this.
This can get complicated if you bind a function to Lua that may
indirectly invalidate the A userdata (e.g. if B is a tagged union and
changes type, or via a "close"-style function for B): Then all further
accesses to the A userdata should throw an error.
You could have all four cases *for one type* *in the same library*, and
you want to treat all those A userdata the same (only one metatable).
The current proposal tries to address the fourth case (one object
embedded in another), but ...
* It doesn't handle cases 2 and 3.
* It doesn't handle embedding via pointer (the offset approach fails
one level down).
* It doesn't handle invalidation of the container userdata.
* Just an offset is not enough (may be the same in unions anyway), you
also need different metatables, which means that you'll have extra
memory allocation for the embedded userdata anyway, because you can't
fit the handle, the offset, and the metatable pointer in one TValue.
—Tim
Philipp