I want to add some static fields to my Lua userdata objects coming from C++. The objects in question are vectors, they're created in C++ land and they work as they are but I've tried lua_setfield on my userdata but I get a attempt to index a Vector value error and I don't really want to have to use .x(), .y(), .z() due to the cost of having to call a function, push to stack and then read on the Lua side.
Is there any way to register fields on userdata for Lua access?
Userdata doesn't have "fields". What it can have is a metatable, for which you can define the __index and __newindex metamethods. Given such a metatable, the former function is called when reading the value of a field of the userdata, while the latter is called when assigning a value to a field from the outside (ud.some_field = 4 or an equivalent). If you want fields to be read only (to some degree), you can just implement __index, and attempts by the user to use __newindex will fail.
So in your C++ code, after creating the userdata, you can use lua_setmetatable to assign it a table that has these methods defined within it. Of course, these functions will need to access the actual C++ object from the userdata and fetch the specific values you're interested in.
Related
So with the Lua C API you can save a Lua value in the registry and retrieve it later. There are different ways to do it, you can create a variable and use it's pointer as the key in the registry as it's always unique. You would push the pointer as light userdata.
You can also create a reference using LuaL_ref(L, LUA_REGISTRYINDEX). What is the advantage of one over the other? When to use references and when to use pointers?
Also with references, as it is called a reference, if the Lua garbage collector collects the Lua value, will the value in the registry be nil? What if Lua updates the Lua value, will the value in the registry also change?
Lua registry is just another lua table, easily accessible via predefined "special" index. I guess you don't need explanations on how Lua table is different from light userdata.
It doesn't really matter how you will index registry table, as long as you can store that key on C/C++ side. For your convenience there's already functions (luaL_ref/luaL_unref) giving you integer key that is easy to store and move around.
About garbage collection - rules are always the same. As long as value is stored in table that wasn't marked as weak table (registry is not weak table), that value won't be cleared. You must explicitly remove value from the registry.
Changing value will obey normal Lua rules. Assigning new immutable value to some variable won't change value stored in registry, i.e. registry won't follow updates to some variable. But changing content of mutable value (table etc) is ok, since registry and variable will refer same value.
In addition to previous answer:
Differences between Lua lightuserdata and userdata
lightuserdata is a special Lua type (as well as nil, boolean, number, string, table, thread etc.) containing C pointer. Nothing more. You can't assign metatable to lightuserdata. On the contrary, you can assign metatable to userdata type. For example see Lua File operations, where file handle is userdata with methods. f:read("*all") f is userdata the command is equivalent to f.read(f, "*all")
Indexing LUA_REGISTRYINDEX with integer or C pointer
There are two methods that are widely used on registry table.
Create new reference to Lua value with luaL_ref and store the return integer value somewhere in your code. I.e. to access the Lua value you'll need to read C variable holding the reference and index registry table with lua_rawgeti(L, LUA_REGISTRYINDEX, i) where is that integer value. lua_rawseti(L, LUA_REGISTRYINDEX, i) is also possible, but don't try rewrite to a nil value with this method!
You creating a static C variable static int myvar; and then use lua_rawgetp(L, LUA_REGISTRYINDEX, &myvar) and lua_rawsetp(L, LUA_REGISTRYINDEX, &myvar) for manipulation of stored Lua value straight-forward.
Unfortunately I can't compare the performance of both methods. I think they are almost the same.
A simple example of producing.
protocol.onConnect(function() end, function () end, ...)
Now in c, i want to get the functions which are in args #1, #2.
In strings, numbers,... we can get them using (lua_getstring,..), But I at-least didn't found how to get a function.
int luaProtocolOnConnect(lua_State* L)
{
int base_func // func #1
int call_func // func #2
....
}
You cannot really "get" a Lua function. Lua functions, like Lua tables, are pure-Lua objects. As such, they have no C or C++ analog. If you want to call a Lua function, that's done through lua_call, lua_pcall or similar functions. This is done in-situ on the Lua stack.
So you can't take a Lua function and turn it into a C++ value. What you can do is take a Lua function and manipulate it in the various ways that all Lua objects can be manipulated.
For example, let's say you want to store a Lua function in a C++ object, then later call whatever Lua function was stored there. Well obviously, you can't convert the Lua function directly into a C++ value. What you can do is store that Lua function in a place which C++ can access. You use some value which does have a C++ analog to reference that stored Lua function. The value must be unique for every object you want to store like this. The value you get when storing the object will be saved in your C++ object. When the time comes to retrieve the Lua function, you simply use the stored value to retrieve it.
Because this is an exceedingly common operation, Lua has ways to facilitate this. The first is the Lua registry, a table that C++ can access but Lua code cannot (not unless you give it access).
The second is the luaL_ref series of functions. luaL_ref takes whatever is at the top of the stack and sticks it in a table you provide, returning to you an integer key that can be used to retrieve it later. lua_rawgeti can be used to retrieve the function from the table by the key, and luaL_unref takes the table and the integer key, removing the referenced function from the table when you're done with it.
So if you want to store such functions, you simply need to create such a table, stick it in a known place in the registry (so that you can fetch it whenever you need to), and then use luaL_ref to store those functions. When it comes time to call them, retrieve them with lua_rawgeti. When you're finished using them, destroy them with luaL_unref.
You can use lua_isfunction to check if it's a function, use lua_pushvalue to push its value on top of the stack and then use luaL_ref (luaL_ref(L,LUA_REGISTRYINDEX);) to turn it into a unique key you can later reference to retrieve the value (lua_rawgeti(L,LUA_REGISTRYINDEX,ref)) and call the function.
I would like to know is there a way to pass a struct pointer to a lua script,
and reach it's members from lua without copy (for read and write purposes).
So, for example is it possible to overwrite a member of a c struct directly through of its pointer?
(I am using luajit)
In addition to Tim's answer, you can also go for light userdata. You don't end up with a copy of your data in the Lua stack, all you push to Lua is a pointer.
Lua has no understanding of what is in this pointer, whether it still points to valid memory, or how to access any objects in this pointer, so you'll have to handle all of this yourself in C. I am usually sending a pointer to an item on a list, so if there's any risk that entry has been deleted from the list, I first iterate over the list to validate the pointer (not a big deal if your lists are short). To access items within the pointer in Lua, you need to write get/set functions in C that you can call from Lua.
To get started, here are the entries on pushing and retrieving the lightuserdata:
lua_pushlightuserdata - push an entry on the stack
lua_touserdata - retrieve the pointer value
lua_islightuserdata - validate entry is light userdata
Programming in Lua entry on light userdata
Seeing as you have tagged this for luajit, you can combine the light userdata (as mentioned by others) with FFI for direct struct member access, see the tutorial here: http://luajit.org/ext_ffi_tutorial.html
The way to do this is with a lua userdata. Here are a couple examples: link, another link.
I am writing for a simulation that uses an old 3D model file format (Carbon Graphics' GEO, if you're interested), and the way the OpenSceneGraph plugin for this model format updates its internal variables is by you registering a callback method for the model to call when it's time to update its values. The callback has the simulation time, the variable name, and its current value. You are to return back the new value for that variable.
So, in my code, I set the callback as follows:
headerNode->setUserUpdate(&FlightDriver::updateGeoVariable);
The class headerNode belongs to has the following variable:
double (* uvarupdate)(const double t, const double val, const std::string name);
Every interval, it will call uvarupdate which I have set to:
updateGeoVariable(const double time, const double val, const std::string name)
{
return flightData->getValue(name);
}
for each variable inside the model, one at a time. I can't make the method or the flightData member static, as they need to be unique per instance.
I have a hunch that this callback is possibly being called from C code, because when I break, it seems to have no knowledge that it is inside a class, and if I change the signature, the same three values get passed and shoehorned into whatever parameters are first.
However, I really need access to the members of the class, to avoid a really dirty kludge. Since the class itself is what drives a model in the 3D world, having 2 or more of these means that I get callbacks that say: "234, pitch, 90" and I have no way of knowing which model's variable that data belongs to.
I could possibly recompile the DLL (as it is an OSG plugin) to take additionally a pointer to that instance, or an id, or something, and return it in the callback, but I'd really like to avoid that if possible.
I've read about thunking, but it looks like that and most other ideas require access to the code that creates the callback. Any ideas?
You need to pass a pointer to method, but the uvarupdate is pointer to function, these are different types. Pointer to a method contains implicit pointer to this of an instance, it doesn't fit into function-pointer. You need to pass this in some another way.
If you do not change signature of the callback, you have to calculate an instance (this) somehow. If it can be determined from name parameter, well, it's easy. Another way is to create a trampoline for each instance you have. If there are only few instances, you can write a separate trampoline function for each instance. Creating trampolines dynamically (in run-time) is tricky and non-portable: in fact, you need to write some machine instructions into RAM so that they call your method with the correct this parameter. But that's also possible, that's what some libraries do (e.g. VCL in Delphi).
I am using swig-lua. I have a function in Lua which I call and it returns me a pointer (userdata). right now I know what this pointer is, but how can I tell Lua from within Lua?
From the Lua Reference Manual:
setmetatable (table, metatable)
Sets the metatable for the given
table. (You cannot change the
metatable of other types from Lua,
only from C.)
You cannot "tell Lua" what a userdata is within Lua. It must be given a metatable or manipulated through bound function calls using the C API. See chapter 28.1 of Programming in Lua (Pil) for more information.
The very definition of userdata is that Lua does not, can not, and doesn't want to know what it is. It's your data- what it is is your problem. If you want to manipulate it, then you must call C functions with it (operator overloads available by metatable setting).
Tell SWIG about the data type pointed at by that void pointer. If SWIG is aware of the type, then it will pass it to Lua as a userdata with a suitable metatable attached that allows the Lua side to access and modify the individual data fields, (and if it is a class, call call its methods).
This might mean telling SWIG about some data types that aren't otherwise required by the library, but is probably worth the effort in the long run.
All Lua knows about what type a userdata is is contained in its metatable. Two userdata values are the same type if they have the same metatable. That metatable is responsible for mediating all access to the its content from the Lua side, and is usually made up of methods implemented in C so that is possible to do. Without such a metatable, then the Lua side can only treat a userdata as an opaque blob.