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.
p>
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 }
};
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
>
p>
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.
p>
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
>