Lua UserData array access and method

I wrote a userdata type for Lua in C language. It has some array type attributes and various methods. Now, if you are of this type, I use you: set (k,v)resp. u: Get (k) access data, such as u: sort() as a method. For this, I set __index to the table containing these methods. Now, if I want to use u[k] = v or u [k] To access data, I need to set __newindex and __index to set resp get. But other methods can no longer be accessed…

To deal with this problem in C What is the best way? I guess I need to write a function in C to register as __index and handle it in some way. Maybe check if the key belongs to the Lua method table, and if it is, call it.

Any help/ Tips would be greatly appreciated. I did not find such an example, although it seems to be a natural thing to me.

Edit: Added my C version solution in Lua, in the answer below Published in. This is more or less a direct translation, so all the credit goes to @gilles-gregoire.

The following C functions are registered as __index metamethods.

static int permL_index(lua_State *L) {
struct perm **pp = luaL_checkudata(L, 1, PERM_MT);
int i;

luaL_getmetatable( L, PERM_MT);
lua_pushvalue(L, 2);
lua_rawget(L, -2);

if (lua_isnil(L, -1)) {
/* found no method, so get value from userdata. */
i = luaL_checkint(L, 2);
luaL_argcheck(L, 1 <= i && i <= (*pp)-> n, 2, "index out of range");

lua_pushinteger(L, (*pp)->v[i-1]);
};

return 1;
};

This is the code to perform this operation,

int luaopen_perm(lua_State *L) {

luaL_newmetatable(L, PERM_MT);
luaL_setfuncs(L, permL_methods, 0);
luaL_setfuncs(L, permL_functions, 0);
lua_pop(L, 1);

luaL_newlib (L, permL_functions);

return 1;
};

Where permL_methods is

static const struct luaL_Reg permL_methods[] = {
{"__index", permL_index },
{"__eq", permL_equal },
{"__tostring", permL_tostring },
{"__gc" , permL_destroy },
[...]
{NULL, NULL }
};

and permL_functions are

< pre>static const struct luaL_Reg permL_functions[] = {
{“inverse”, permL_new_inverse },
{“product”, permL_new_product },
{“composition”, permL_new_composition },
[…]
{NULL, NULL }
};

This looks like a problem that can be solved with nested metatables. You need a metatable for methods (such as your sort() method) and the second for index operations. The second metatable is actually a metatable method Metatable.

Let me write it as Lua code. You need 3 tables:

-- the userdata object. I'm using a table here,
-- but it will work the same with a C userdata
u = {}

-- the "methods" metatable:
mt = {sort = function() print('sorting...') end}

-- the "operators" metatable:
op_mt = {__index = function() print('get') end }

Now, the tricky part is here: when you call a method, Lua will look for you first.
If it can’t find it, it will be in the __index field of your metatable Look up in the table pointed to… and Lua will repeat the process of that table!

-- first level metatable
mt.__index = mt
setmetatable(u, mt)

-- second level metatable
setmetatable(mt, op_mt)

You can now use yours like this:

> u:sort()
sorting...
> = u[1]
get
nil

Edit: a better solution by using the function of the __index meta method

The function using the __index metamethod may be the correct way:

u = {}
mt = {sort = function() print(' sorting...') end)
setmetatable(u, mt)
mt.__index = function(t, key)
- use rawget to avoid recursion
local mt_val = rawget(mt, key)
if mt_val ~=nil then
return mt_val
else
print('this is a get on object', t)
end< br />end

Usage:

> print(u)
table: 0x7fb1eb601c30
> u:sort()< br />sorting...
> = u[1]
this is a get on object table: 0x7fb1eb601c30
nil
>

I wrote a userdata type for Lua in C language. It has some array type attributes and various methods. Now, if you are of this type, I use you: set(k,v)resp . u: Get (k) access data, such as u: sort() as a method For this, I set __index to the table containing these methods. Now, if I want to use u[k] = v or u[k] to access the data, I need to set __newindex and __index to set resp get. But The other methods are no longer accessible…

What is the best way to deal with this problem in C? I guess I need to write a function in C to register as __index and handle it in some way. Maybe check if the key belongs to the Lua method table, and if it is, call it.

Any help/ Tips would be greatly appreciated. I did not find such an example, although it seems to be a natural thing to me.

Edit: Added my C version solution in Lua, in the answer below Published in. This is more or less a direct translation, so all the credit goes to @gilles-gregoire.

The following C functions are registered as __index metamethods.

static int permL_index(lua_State *L) {
struct perm **pp = luaL_checkudata(L, 1, PERM_MT);
int i;

luaL_getmetatable( L, PERM_MT);
lua_pushvalue(L, 2);
lua_rawget(L, -2);

if (lua_isnil(L, -1)) {
/* found no method, so get value from userdata. */
i = luaL_checkint(L, 2);
luaL_argcheck(L, 1 <= i && i <= (*pp)-> n, 2, "index out of range");

lua_pushinteger(L, (*pp)->v[i-1]);
};

return 1;
};

This is the code to perform this operation,

int luaopen_perm(lua_State *L) {

luaL_newmetatable(L, PERM_MT);
luaL_setfuncs(L, permL_methods, 0);
luaL_setfuncs(L, permL_functions, 0);
lua_pop(L, 1);

luaL_newlib(L, perm L_functions);

return 1;
};

where permL_methods is

static const struct luaL_Reg permL_methods[ ] = {
{"__index", permL_index },
{"__eq", permL_equal },
{"__tostring", permL_tostring },
{"__gc", permL_destroy} ,
[...]
{NULL, NULL }
};

and permL_functions are

static const struct luaL_Reg permL_functions[] = {
{"inverse", permL_new_inverse },
{"product", permL_new_product },
{"composition", permL_new_composition },
[. ..]
{NULL, NULL }
};

This looks like a problem that can be solved with nested metatables .You need a metatable for methods (such as your sort() method) and a second for index operations. The second metatable is actually a metatable for the metatable method.

let me Write it as Lua code. You need 3 tables:

-- the userdata object. I'm using a table here,
-- but it will work the same with a C userdata
u = {}

-- the "methods" metatable:
mt = {sort = function() print('sorting...') end}

- -the "operators" metatable:
op_mt = {__index = function() print('get') end}

Now, the tricky part is here: when you call a method, Lua will look for you first.
If it can’t find it, it will look in the table pointed to by the __index field of your metatable… and Lua will repeat the process of that table!

-- first level metatable
mt.__index = mt
setmetatable(u, mt)

-- second level metatable
setmetatable(mt, op_mt)

You can now use yours like this:

> u:sort()
sorting...
> = u[1]
get
nil

Edit: a better solution by using the function of the __index meta method

The function using the __index metamethod may be the correct way:

u = {}
mt = {sort = function() print(' sorting...') end)
setmetatable(u, mt)
mt.__index = function(t, key)
- use rawget to avoid recursion
local mt_val = rawget(mt, key)
if mt_val ~=nil then
return mt_val
else
print('this is a get on object', t)
end< br />end

Usage:

> print(u)
table: 0x7fb1eb601c30
> u:sort()< br />sorting...
> = u[1]
this is a get on object table: 0x7fb1eb601c30
nil
>

Leave a Comment

Your email address will not be published.