Given a vararg ... like 1, 2, 3, nil, 5, I would like to write a function reverse, such that reverse(...) returns the vararg 5, nil, 3, 2, 1.
2 Answers
Using a temporary table:
local function reverse(...)
local n = select("#", ...)
local t = {...}
-- Reverse the table
for i = 1, n/2 do
local j = n - i + 1
t[i], t[j] = t[j], t[i]
end
return unpack(t, 1, n)
end
or using a helper function which picks the n-th element, prepends that to a new vararg, and recurses until n = 0:
local function h(n, ...)
if n == 0 then return end
return select(n, ...), h(n - 1, ...)
end
local function reverse(...)
return h(select("#", ...), ...)
end
Comments
If you are interested in dropping down a level, the Lua C API provides lua_insert and lua_rotate (5.3+), both of which can be used to manipulate the stack directly.
An example using the former:
#include <lua.h>
static int reverse(lua_State *L)
{
int n = lua_gettop(L);
for (int i = 1; i < n; i++)
lua_insert(L, i);
return n;
}
int luaopen_reverse(lua_State *L)
{
lua_pushcfunction(L, reverse);
return 1;
}
local reverse = require 'reverse'
print(reverse(1, 2, 3, 4))
4 3 2 1
(The following focuses on the Lua 5.4 API, but should be applicable to Lua 5.3 as well. Note that in Lua 5.3+, lua_insert is a macro around lua_rotate.)
Interestingly, there is an internal API function called reverse, used by lua_rotate, which performs this task very efficiently across a stack segment.
If one has the ability to change the source code for their installation, then it is possible to modify src/lapi.c with the following function,
/* reverse the entire stack segment */
LUA_API void lua_reverse (lua_State *L)
{
lua_lock(L);
int n = lua_gettop(L);
if (n > 1)
reverse(L, index2stack(L, 1), index2stack(L, n));
lua_unlock(L);
}
src/lua.h with the following protoype,
LUA_API void (lua_reverse) (lua_State *L);
src/lbaselib.c with the following function,
static int luaB_reverse (lua_State *L) {
lua_reverse(L);
return lua_gettop(L);
}
and add
{"reverse", luaB_reverse},
to the base_funcs array in src/lbaselib.c, to get access to an efficient, global reverse function:
Lua 5.4.6 Copyright (C) 1994-2023 Lua.org, PUC-Rio
> reverse('hello', 'world', 42)
42 world hello
(and a lua_reverse C API function, of course.)