Reuse lua_newuserdata() returned pointer - c

¿Is posible reuse lua_newuserdata() returned pointer?
The idea is not allocate a new userdatum every time for the same object and allow equality check (example) done by lua.
obj1 = c_api__foobar();
obj2 = c_api__foobar();
if obj1 == obj2 then
print("equal")
else
print("they are supposed to be equal")
end

well look is not possible, attemping to reuse the pointer will throw something like calling 'c_api__foobar' on bad self (FOOBAR expected, found FOOBAR) error.
static int expose_foobar(lua_State* L) {
void* existing_userdata = /* previous value returned by lua_newuserdata() */;
LUA.luaL_getmetatable(L, "FOOBAR")
LUA.lua_setmetatable(L, -2);
return 1;
}
tested in lua 5.4

Related

Splint warns undefined storage. Sanity check please?

I'm working on a game at the moment, and I'm having an issue with splint on the following code to add new enemy structs to my linked list.
void generate_enemy(enemy_struct* enemy)
{
enemy_struct* new_enemy;
// Make sure the incoming enemy isn't null.
if(enemy == NULL)
{
return;
}
// Run through till we find the last enemy in the list.
while(NULL != enemy->next_enemy)
{
enemy = enemy->next_enemy;
}
// Create a new enemy and point the last enemy to it.
new_enemy = malloc(sizeof(enemy_struct));
// If we're out of memory, don't bother making the new enemy.
if(NULL == new_enemy)
{
return;
}
else
{
// Initialise the new enemy.
new_enemy->location = 1;
new_enemy->motion = ENEMY_STATIC;
new_enemy->dead = false;//true;
// Ensure it carries the last enemy flag.
new_enemy->next_enemy = NULL;
// Put new enemy in previous enemy.
enemy->next_enemy = new_enemy;
}
return;
}
Splint gives the warning:
enemy.c: (in function generate_enemy)
enemy.c:57:12: Storage *(enemy->next_enemy) reachable from parameter contains 4
undefined fields: location, motion, dead, next_enemy
Storage derivable from a parameter, return value or global is not defined.
Use /*#out#*/ to denote passed or returned storage which need not be defined.
(Use -compdef to inhibit warning)
Line 57 is the last return in the function.
Now, I'm fairly confident my code cannot return undefined values, as I either set all fields, or don't change anything and drop out.
Is there some case I'm missing out where I send back stuff undefined? If not, what's the best way to stop splint giving this warning?

Kotlin: For-loop must have an iterator method - is this a bug?

I have the following code:
public fun findSomeLikeThis(): ArrayList<T>? {
val result = Db4o.objectContainer()!!.queryByExample<T>(this as T) as Collection<T>
if (result == null) return null
return ArrayList(result)
}
If I call this like:
var list : ArrayList<Person>? = p1.findSomeLikeThis()
for (p2 in list) {
p2.delete()
p2.commit()
}
It would give me the error:
For-loop range must have an 'iterator()' method
Am I missing something here?
Your ArrayList is of nullable type. So, you have to resolve this. There are several options:
for (p2 in list.orEmpty()) { ... }
or
list?.let {
for (p2 in it) {
}
}
or you can just return an empty list
public fun findSomeLikeThis(): List<T> //Do you need mutable ArrayList here?
= (Db4o.objectContainer()!!.queryByExample<T>(this as T) as Collection<T>)?.toList().orEmpty()
try
for(p2 in 0 until list.count()) {
...
...
}
I also face this problem when I loop on some thing it is not an array.
Example
fun maximum(prices: Array<Int>){
val sortedPrices = prices.sort()
for(price in sortedPrices){ // it will display for-loop range must have iterator here (because `prices.sort` don't return Unit not Array)
}
}
This is different case to this question but hope it help
This can also happen in Android when you read from shared preferences and are getting a (potentially) nullable iterable object back like StringSet. Even when you provide a default, the compiler is not able to determine that the returned value will never actually be null. The only way I've found around this is by asserting that the returned expression is not null using !! operator, like this:
val prefs = PreferenceManager.getDefaultSharedPreferences(appContext)
val searches = prefs.getStringSet("saved_searches", setOf())!!
for (search in searches){
...
}

LuaJit - Get metatable from module/package and assign it to userdata

Say I have this metatable for a custom struct vector2_t which is inside a module mymod like this:
local mymod = {}
local ffi = require("ffi")
local C = ffi.C
ffi.cdef[[
typedef struct
{
double x;
double y;
} vector2_t;
]]
local vector2_t
vector2_t = ffi.metatype("vector2_t", {
__eq = function(lhs, rhs)
if lhs.x == rhs.x and lhs.y == rhs.y
then return true else return false end
end
-- Member functions follow...
})
vcmp.vector2 = vector2_t
-- I use this method because the script is integrated in C/C++ as a string and not
-- as a file and I need a constant name that isn't decided by the file name
package.preload["mymod"] = function(mod) return mymod end
And in another script I have this callback/event listener function which must receive a vector2_t as it's argument:
local mymod = require "mymod"
local some_pos = mymod.vector2(32, 29.7)
-- That pos argument must be an instance of mymod.vector2_t
function position_update(pos)
print("New Pos: " .. pos.x .. ", " .. pos.y .. "\n")
some_pos.x = pos.x
some_pos.y = pos.y
end
Now, I must call that callback/event listener function from C/C++ and pass an instance of that vector2_t (along with it's associated metatable) as the parameter to that function.
typedef struct
{
double x;
double y;
} vector2_t;
void call_position_update(lua_State* L, double x, double y)
{
// Retrieve the function
lua_getglobal(L, "position_update");
// Validate it
if (!lua_isfunction(L, lua_gettop(L)))
{
lua_pop(L, 1);
return;
}
// Create an instance of vector2_t
vector2_t *pos = (vector2_t *)lua_newuserdata(L, sizeof(vector2_t));
// Assign the values to the new instance
pos->x = x;
pos->y = y;
// How do I get the meta table vector2_t on to the stack?
// Reach to the module somehow...
// Get the meta table from the module
luaL_getmetatable(L, "vector2_t");
// Assign the meta table to the vector2_t instance already on the stack
lua_setmetatable(L, -2);
// I'm assuming that the vector2_t instance is already on the stack so there's nothing else to push
// Call the function with 1 argument which should be that vector2_t onto the stack
if (!lua_pcall(L, 1, 0, 0))
{
printf("Error calling function 'position_update': %s\n", lua_tostring(_Lua, -1));
}
}
I'm a bit lost and I don't know how to pas an instance of that vector2_t as the function parameter. I'm sorry for posting so much code bu I wanted to be sure that I explained correctly.
cdata and userdata are completely different things. The only interaction they have is that you can get an FFI void* pointer to userdata. Notably, there is no C API for cdata objects. Mixing them is sure to cause you a lot of headaches.
Pick either the Lua C API or the FFI, and stick to it as much as possible.
To directly answer your question:
how to pas [sic] an instance of that vector2_t as the function parameter
To a Lua C API function, it gets passed on the stack, just like other values. Note that it will be a cdata typed object, not a userdata object. Notably, you can't get a pointer to it.
How do I get the meta table vector2_t on to the stack?
You can't, since you don't make the metatable accessible to outside scripts in your first script. luaL_getmetatable only works with metatables created with luaL_newmetatable

lua userdata with array access and object oriented access?

I'm writing a "C" userdata array structure.
As setter and getter i want normal array access (u[0] = 1 u[0]) like it's discussed here:
[c array share][1]Share Array between lua and C.
For that i need to set __index and __newindex to the set and get functions in c.
Additional i want object-oriented access, too, "like u:mymethod()". My trouble is, that i need to set now __index to the metatable itself.
Is there a way, to achieve both?
Just one of many possible ways to achieve this:
local userdata = { _array = { "A", "B", "C" } }
local mt = { }
local methods = { }
function mt.__index(userdata, k)
if methods[k] then
return methods[k]
else
return rawget(userdata, "_array")[k]
end
end
function mt.__newindex(userdata, k, v)
if methods[k] then
error "can't assign to method!"
else
rawget(userdata, "_array")[k] = v
end
end
function methods.count(userdata)
return #rawget(userdata, "_array")
end
setmetatable(userdata, mt)
userdata[3] = "Z"
print(userdata[1])
print(userdata[2])
print(userdata[3])
print(userdata:count())
userdata.count = 0
edit: As lhf pointed in his comment, it is not dangerous to use metatable as it's __index table at all, because c-methods should always check on what self they operate.

Can generic list utilities use Vectors (AS3)?

Using Object or * as a type for a Vector doesn't provide generic functionality (like List in Java). Witness:
public static function someGenericVectorUtil (value:Vector.<*>) :void {
// do stuff to/with the Vector
}
var someVector:Vector.<Number>;
someGenericVectorUtil(someVector); // compile-time implicit coercion error
So, perhaps we redefine the utility method to accept an Array. But there's no easy way to convert Vectors going into the utility to Arrays, nor an easy way to pack them back in afterwards, resulting in code like this:
public static function someGenericArrayUtil (value:Array) :void {
// do stuff to/with the formerly-known-as-Vector
}
var someVector:Vector.<Number>;
var tempArray:Array = new Array(someVector.length);
for (var i:uint=0; i<someVector.length; i++) {
tempArray[i] = someVector[i];
}
someGenericVectorUtil(tempArray);
someVector = Vector.<Number>([tempArray]);
Needless to say, that's pretty hideous. Okay, so let's move the Vector-Array-Vector nonsense into a utility:
public static function vectorToArray (Vector.<*>) :Array {
// oh wait....that Vector.<*> param is useless,
// as demonstrated earlier.
}
Any way to straighten out this mess? Or should I just stop using Vectors when I think I might need to run them through generic utilities? (Obviously, also not really much of an option...)
public static function someGenericVectorUtil (value:Vector.<*>) :void {
// do stuff to/with the Vector
}
var someVector:Vector.<Number>;
someGenericVectorUtil(Vector.<*>(someVector));
^ it works. Also try with Array.
This is not an answer but more a long comment to #Lukasz's answer.
The problem with his answer is that you're actually creating a new Vector, so you need to return the Vector from someGenericVectorUtil and re-cast it. E.g. try:
var v:Vector.<int> = Vector.<int>([1,2,3]);
trace( v == Vector.<int>( Vector.<*>( v ) ) ); // traces false
That code just creates a simple Vector of ints, then compares it with a version of itself casted (first to *, then back to int). If you trace the Vectors out, they'll trace identical, but the actual Vectors references themselves aren't the same object. Thus if you have a utility function that modifies the Vector (e.g. a shuffle or randomise function), nothing will change.
E.g:
var v:Vector.<int> = Vector.<int>([1,2,3]);
trace( v ); // traces "1,2,3"
// shuffle() randomises the elements in a vector - this first call won't work
// as the cast creates a new vector
VectorUtil.shuffle( Vector.<*>( v ) );
trace( v ); // traces "1,2,3"
// we need to recast it back, and change shuffle() to return the vector
v = Vector.<int>( VectorUtil.shuffle( Vector.<*>( v ) ) );
trace( v ); // traces "3,1,2"
As you can see, it starts to get a bit ugly towards the end, and if you're keeping track of the Vector anywhere else, you'll need to update the references, but it's the only solution that I've found so far :S

Resources