[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Iterate over vararg
- From: Gabriel Bertilson <arboreous.philologist@...>
- Date: Thu, 20 Dec 2018 02:07:51 -0600
I guess without a table, the arguments can be stored as upvalues. The
following makes an iterator generator that sets its arguments as
upvalues to a closure, with the total number of upvalues as the first
upvalue. (Is there a way to avoid that first upvalue?) Then the
closure receives an unused first argument and a second argument i, and
it returns the i-plus-one-th argument to the original function
(similar to the behavior of the function returned by ipairs). Not sure
if this is more or less efficient memory-wise than using a table.
#include <stdio.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
static int iter_varargs (lua_State * L) {
lua_Integer i = luaL_checkinteger(L, 2);
// Get total number of upvalues.
lua_Integer n = luaL_checkinteger(L, lua_upvalueindex(1));
if (i + 2 <= n) {
lua_pushinteger(L, i + 1);
// Return the i-th argument to gen_iter_varargs.
lua_pushvalue(L, lua_upvalueindex(i + 2));
return 2;
} else {
return 0;
}
}
static int gen_iter_varargs (lua_State * L) {
int n = lua_gettop(L);
if (n + 1 > 255) { // maximum number of upvalues
return luaL_error(L, "too many arguments");
}
// Insert total number of upvalues as first upvalue.
lua_pushinteger(L, (lua_Integer) n + 1);
lua_insert(L, 1);
// Set arguments as remaining upvalues.
lua_pushcclosure(L, iter_varargs, n + 1);
lua_pushnil(L);
lua_pushinteger(L, 0);
return 3;
}
int main (int argc, char * * argv) {
lua_State * L = luaL_newstate();
luaL_openlibs(L);
lua_register(L, "args", gen_iter_varargs);
if (luaL_dostring(L, "for i, val in args(1, 2, 3) do print(val * val) end"))
printf("failed to execute script\n");
lua_close(L);
return 0;
}
— Gabriel
On Thu, Dec 20, 2018 at 12:12 AM Dirk Laurie <dirk.laurie@gmail.com> wrote:
>
> The task is to write an iterator factory 'args' so that
>
> for k,v in args(...) do --[[whatever]] end
>
> does the same as
>
> for k=1,select('#',...) do local v = select(k,...) --[[whatever]] end
>
> It is quite easy by using a table, of course:
>
> ~~~~
> args = function(...)
> local t = table.pack(...)
> local n = t.n
> local i = 0
> return function()
> i=i+1
> if i<=n then return i,t[i] end
> end
> end
> ~~~~
>
> It seems to be quite hard to do, even in the C API, without creating a
> table. In fact, I have so far not succeeded.
>