[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: linking tables to C++ objects?
- From: Graham Wakefield <lists@...>
- Date: Sun, 25 Feb 2007 22:37:59 -0800
Hi all,
I would like to be able to create a 'special' kind of table in Lua,
which behind the scenes is bound to a C++ instance object. The C++
object (userdata or lightuserdata) itself should not be visible in
Lua. The reason is that I need to trigger table-specific callback
functions in Lua at deferred times determined by C++ code (after the
main Lua chunk has run).
My needs are:
1. To be able to access the table from the C++ instance pointer (via
callbacks in C API, but not in Lua code)
2. To be able to access the C++ instance pointer from the table (via
metatable methods in C API, but not in Lua code).
3. To have a callback into C++ when the table is garbage collected
4. To be efficient (minimal cpu use), and use a custom allocator for
any C++ data (memory pool)
I have looked at using combinations of metatables, boxed pointers,
userdata environments, the registry, weak keys, etc. but so far I
can't find a solution that satisfies all the requirements.
For 1.
I can use the userdata environment if I don't use boxed pointers
(set the userdata env to be the associated table)
The problem with boxed pointers is that I can't get from the
pointer that is boxed to the userdata object.
I can use the registry, but have to automatically remove the
userdata when the table is garbage collected
For 2.
I could use the registry, but have to be careful to remove the table
when the instance is deleted.
I could create a closure for each table that retrieves the userdata
pointer from the upvalue; a kind of __getptr metamethod. This seems
a little obscure.
For 3.
It seems the only way I can do this is to use a userdata with a __gc
method referenced by the table somewhere. Since I don't want the
userdata to be available to Lua code, it seems the only place to do
it is in the registry. REGISTRY[table] = udata. But actually I
can't directly use the registry, since this will prevent the table
ever getting collected; so I need to insert a weak-valued table of
references into the registry and use that instead. REGISTRY
[WEAKVALUEDREFS][table] = udata. Right?
For 4.
This pretty much demands that I use boxed pointers.
So (in minimal pseudocode):
udata = lua_newuserdata() // boxed or unboxed?
table = lua_newtable()
REGISTRY[WEAKVALUEDREFS][table] = udata
setfenv(udata, table) ?? // only for unboxed userdata
udata.__gc() { // do whatever gc callback here }
getUdata(table) {
return REGISTRY[WEAKVALUEDREFS][table]
}
getTable(udata) {
?? getfenv(udata) // only for unboxed userdata
}
Is there a way to achieve the same using a boxed pointer? Is there
another way I haven't thought of yet?
Is it a bad idea in terms of efficiency to use the registry for every
object (I may have thousands)?