lua-users home
lua-l archive

Re: Iterate over vararg

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


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.
>

AltStyle によって変換されたページ (->オリジナル) /