Alternative export method of arrays from C to Lua

The patch is mainly to export client_array_t object to Lua,
but can be used to export any ..._array_t object.

The idea: export to Lua not a table, but userdata with
metamethods to get/set/define length of ..._array_t object
directly.

Now when I get clients field from tag object C code
creates full copy of client_array_t structure into Lua table.
It takes traversing a whole array of data.

I did it in other way: userdata is exported, with __index,
__newindex, and __len meta-methods defined, and Lua
script gains direct access to client_array_t C-array:
it can get client object, get length of array and assign
client objects to some index in C-array.

Pros:
No overhead of creation a copy of C-structure into Lua-table:
if I want just to test a number of clients for a tag, I don't need
a whole loop to build table, I just want to read clients->len field,
and I do so via __len meta-method.
Also if I want to get some client from tags.clients, I don't need
to create ALL clients Lua-objects, I just get client_t C-struct
and create Lua-object from it. Just in place.
So Lua-loop enuming all tag.clients is not 2 loops internally
(first create copy of tag.clients into Lua-table, then enum this table),
but only one, and if I break out of loop in the middle, I create
only some client Lua-objects, not all of them from tag.clients.

Contras:
As far as clients field is not a table, I cant use pairs/ipairs
and other table functions for it.
But it can be implemented in other way:
for k,c pairs(tag.clients) => for k = 1, #tag.clients,
table.insert(tag.clients, client) => tag.clients[#tag.clients+1] = client

etc.

One more Pro now:
As far as tag.clients in current implementation returns copy of data
table.insert doesn't do what's expected: it doesn't really add client
into tag.clients "array".
With my implementation client is added as expected, as we work with
client_array_t structure directly.

Signed-off-by: Julien Danjou <julien@danjou.info>
This commit is contained in:
Konstantin 2008-08-10 15:05:50 +03:00 committed by Julien Danjou
parent 8b5f6266da
commit 4ab499fe26
4 changed files with 66 additions and 12 deletions

View File

@ -51,6 +51,7 @@ int luaA_client_newindex(lua_State *);
int luaA_client_userdata_new(lua_State *, client_t *);
DO_SLIST(client_t, client, client_unref)
DO_LUA_EXPORT_ARRAY(client, "client_array", client_t, client_array_t, luaA_client_userdata_new)
#endif
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80

View File

@ -1052,9 +1052,10 @@ function widget.taglist.label.all(t, args)
if sel and sel.tags[t] then
background = "resize=\"true\" image=\"@AWESOME_ICON_PATH@/taglist/squarefw.png\""
elseif bg_urgent and fg_urgent then
for k, c in pairs(t.clients) do
local cli = t.clients
for k = 1, #cli do
background = "resize=\"true\" image=\"@AWESOME_ICON_PATH@/taglist/squarew.png\""
if c.urgent then
if cli[k].urgent then
bg_color = bg_urgent
fg_color = fg_urgent
break

61
lua.h
View File

@ -259,5 +259,66 @@ luaA_generic_pairs(lua_State *L)
return 3;
}
#define DO_LUA_EXPORT_ARRAY(pfx, typename, type, atype, ctor) \
static inline int \
luaA_##pfx##_array_index(lua_State *L) \
{ \
atype *value = lua_touserdata(L, 1); \
type **obj; \
int idx; \
\
if ((obj = lua_touserdata(L, 2))) \
{ \
for (idx = 0; idx < value->len; idx++) \
if (value->tab[idx] == *obj) \
return ctor(L, value->tab[idx]); \
return 0; \
} \
\
idx = luaL_checknumber(L, 2) - 1; \
if (idx < 0 || idx >= value->len) \
return 0; \
\
return ctor(L, value->tab[idx]); \
} \
static inline int \
luaA_##pfx##_array_newindex(lua_State *L) \
{ \
atype *value = lua_touserdata(L, 1); \
int idx = luaL_checknumber(L, 2); \
type **elem = luaL_checkudata(L, 3, #pfx); \
pfx##_array_splice(value, idx - 1, 1, elem, 1); \
return 0; \
} \
static inline int \
luaA_##pfx##_array_len(lua_State *L) \
{ \
atype *value = lua_touserdata(L, 1); \
lua_pushnumber(L, value->len); \
return 1; \
} \
static inline int \
luaA_##pfx##_array_tostring(lua_State *L) \
{ \
atype *value = lua_touserdata(L, 1); \
lua_pushfstring(L, "["typename" udata(%p)]", value); \
return 1; \
} \
static inline void \
luaA_##pfx##_array_export(lua_State *L, atype *arr) \
{ \
lua_pushlightuserdata(L, arr); \
lua_newtable(L); \
lua_pushcfunction(L, luaA_##pfx##_array_index); \
lua_setfield(L, -2, "__index"); \
lua_pushcfunction(L, luaA_##pfx##_array_tostring); \
lua_setfield(L, -2, "__tostring"); \
lua_pushcfunction(L, luaA_##pfx##_array_newindex); \
lua_setfield(L, -2, "__newindex"); \
lua_pushcfunction(L, luaA_##pfx##_array_len); \
lua_setfield(L, -2, "__len"); \
lua_setmetatable(L, -2); \
}
#endif
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80

11
tag.c
View File

@ -349,8 +349,6 @@ luaA_tag_index(lua_State *L)
size_t len;
tag_t **tag = luaA_checkudata(L, 1, "tag");
const char *attr;
client_array_t *clients;
int i;
if(luaA_usemetatable(L, 1, 2))
return 1;
@ -383,14 +381,7 @@ luaA_tag_index(lua_State *L)
lua_pushnumber(L, (*tag)->ncol);
break;
case A_TK_CLIENTS:
clients = &(*tag)->clients;
luaA_otable_new(L);
for(i = 0; i < clients->len; i++)
{
luaA_client_userdata_new(L, clients->tab[i]);
luaA_client_userdata_new(L, clients->tab[i]);
lua_rawset(L, -3);
}
luaA_client_array_export(L, &(*tag)->clients);
break;
default:
return 0;