xref: /freebsd/sys/contrib/openzfs/module/lua/ltablib.c (revision 61145dc2b94f12f6a47344fb9aac702321880e43)
1*61145dc2SMartin Matuska // SPDX-License-Identifier: MIT
2eda14cbcSMatt Macy /*
3eda14cbcSMatt Macy ** $Id: ltablib.c,v 1.65.1.2 2014/05/07 16:32:55 roberto Exp $
4eda14cbcSMatt Macy ** Library for Table Manipulation
5eda14cbcSMatt Macy ** See Copyright Notice in lua.h
6eda14cbcSMatt Macy */
7eda14cbcSMatt Macy 
8eda14cbcSMatt Macy 
9eda14cbcSMatt Macy #define ltablib_c
10eda14cbcSMatt Macy #define LUA_LIB
11eda14cbcSMatt Macy 
12eda14cbcSMatt Macy #include <sys/lua/lua.h>
13eda14cbcSMatt Macy 
14eda14cbcSMatt Macy #include <sys/lua/lauxlib.h>
15eda14cbcSMatt Macy #include <sys/lua/lualib.h>
16eda14cbcSMatt Macy 
17eda14cbcSMatt Macy 
18eda14cbcSMatt Macy #define aux_getn(L,n)	(luaL_checktype(L, n, LUA_TTABLE), luaL_len(L, n))
19eda14cbcSMatt Macy 
20eda14cbcSMatt Macy 
21eda14cbcSMatt Macy 
22eda14cbcSMatt Macy #if defined(LUA_COMPAT_MAXN)
maxn(lua_State * L)23eda14cbcSMatt Macy static int maxn (lua_State *L) {
24eda14cbcSMatt Macy   lua_Number max = 0;
25eda14cbcSMatt Macy   luaL_checktype(L, 1, LUA_TTABLE);
26eda14cbcSMatt Macy   lua_pushnil(L);  /* first key */
27eda14cbcSMatt Macy   while (lua_next(L, 1)) {
28eda14cbcSMatt Macy     lua_pop(L, 1);  /* remove value */
29eda14cbcSMatt Macy     if (lua_type(L, -1) == LUA_TNUMBER) {
30eda14cbcSMatt Macy       lua_Number v = lua_tonumber(L, -1);
31eda14cbcSMatt Macy       if (v > max) max = v;
32eda14cbcSMatt Macy     }
33eda14cbcSMatt Macy   }
34eda14cbcSMatt Macy   lua_pushnumber(L, max);
35eda14cbcSMatt Macy   return 1;
36eda14cbcSMatt Macy }
37eda14cbcSMatt Macy #endif
38eda14cbcSMatt Macy 
39eda14cbcSMatt Macy 
tinsert(lua_State * L)40eda14cbcSMatt Macy static int tinsert (lua_State *L) {
41eda14cbcSMatt Macy   int e = aux_getn(L, 1) + 1;  /* first empty element */
42eda14cbcSMatt Macy   int pos;  /* where to insert new element */
43eda14cbcSMatt Macy   switch (lua_gettop(L)) {
44eda14cbcSMatt Macy     case 2: {  /* called with only 2 arguments */
45eda14cbcSMatt Macy       pos = e;  /* insert new element at the end */
46eda14cbcSMatt Macy       break;
47eda14cbcSMatt Macy     }
48eda14cbcSMatt Macy     case 3: {
49eda14cbcSMatt Macy       int i;
50eda14cbcSMatt Macy       pos = luaL_checkint(L, 2);  /* 2nd argument is the position */
51eda14cbcSMatt Macy       luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds");
52eda14cbcSMatt Macy       for (i = e; i > pos; i--) {  /* move up elements */
53eda14cbcSMatt Macy         lua_rawgeti(L, 1, i-1);
54eda14cbcSMatt Macy         lua_rawseti(L, 1, i);  /* t[i] = t[i-1] */
55eda14cbcSMatt Macy       }
56eda14cbcSMatt Macy       break;
57eda14cbcSMatt Macy     }
58eda14cbcSMatt Macy     default: {
59eda14cbcSMatt Macy       return luaL_error(L, "wrong number of arguments to " LUA_QL("insert"));
60eda14cbcSMatt Macy     }
61eda14cbcSMatt Macy   }
62eda14cbcSMatt Macy   lua_rawseti(L, 1, pos);  /* t[pos] = v */
63eda14cbcSMatt Macy   return 0;
64eda14cbcSMatt Macy }
65eda14cbcSMatt Macy 
66eda14cbcSMatt Macy 
tremove(lua_State * L)67eda14cbcSMatt Macy static int tremove (lua_State *L) {
68eda14cbcSMatt Macy   int size = aux_getn(L, 1);
69eda14cbcSMatt Macy   int pos = luaL_optint(L, 2, size);
70eda14cbcSMatt Macy   if (pos != size)  /* validate 'pos' if given */
71eda14cbcSMatt Macy     luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds");
72eda14cbcSMatt Macy   lua_rawgeti(L, 1, pos);  /* result = t[pos] */
73eda14cbcSMatt Macy   for ( ; pos < size; pos++) {
74eda14cbcSMatt Macy     lua_rawgeti(L, 1, pos+1);
75eda14cbcSMatt Macy     lua_rawseti(L, 1, pos);  /* t[pos] = t[pos+1] */
76eda14cbcSMatt Macy   }
77eda14cbcSMatt Macy   lua_pushnil(L);
78eda14cbcSMatt Macy   lua_rawseti(L, 1, pos);  /* t[pos] = nil */
79eda14cbcSMatt Macy   return 1;
80eda14cbcSMatt Macy }
81eda14cbcSMatt Macy 
82eda14cbcSMatt Macy 
addfield(lua_State * L,luaL_Buffer * b,int i)83eda14cbcSMatt Macy static void addfield (lua_State *L, luaL_Buffer *b, int i) {
84eda14cbcSMatt Macy   lua_rawgeti(L, 1, i);
85eda14cbcSMatt Macy   if (!lua_isstring(L, -1))
86eda14cbcSMatt Macy     luaL_error(L, "invalid value (%s) at index %d in table for "
87eda14cbcSMatt Macy                   LUA_QL("concat"), luaL_typename(L, -1), i);
88eda14cbcSMatt Macy   luaL_addvalue(b);
89eda14cbcSMatt Macy }
90eda14cbcSMatt Macy 
91eda14cbcSMatt Macy 
tconcat(lua_State * L)92eda14cbcSMatt Macy static int tconcat (lua_State *L) {
93eda14cbcSMatt Macy   luaL_Buffer b;
94eda14cbcSMatt Macy   size_t lsep;
95eda14cbcSMatt Macy   int i, last;
96eda14cbcSMatt Macy   const char *sep = luaL_optlstring(L, 2, "", &lsep);
97eda14cbcSMatt Macy   luaL_checktype(L, 1, LUA_TTABLE);
98eda14cbcSMatt Macy   i = luaL_optint(L, 3, 1);
99eda14cbcSMatt Macy   last = luaL_opt(L, luaL_checkint, 4, luaL_len(L, 1));
100eda14cbcSMatt Macy   luaL_buffinit(L, &b);
101eda14cbcSMatt Macy   for (; i < last; i++) {
102eda14cbcSMatt Macy     addfield(L, &b, i);
103eda14cbcSMatt Macy     luaL_addlstring(&b, sep, lsep);
104eda14cbcSMatt Macy   }
105eda14cbcSMatt Macy   if (i == last)  /* add last value (if interval was not empty) */
106eda14cbcSMatt Macy     addfield(L, &b, i);
107eda14cbcSMatt Macy   luaL_pushresult(&b);
108eda14cbcSMatt Macy   return 1;
109eda14cbcSMatt Macy }
110eda14cbcSMatt Macy 
111eda14cbcSMatt Macy 
112eda14cbcSMatt Macy /*
113eda14cbcSMatt Macy ** {======================================================
114eda14cbcSMatt Macy ** Pack/unpack
115eda14cbcSMatt Macy ** =======================================================
116eda14cbcSMatt Macy */
117eda14cbcSMatt Macy 
pack(lua_State * L)118eda14cbcSMatt Macy static int pack (lua_State *L) {
119eda14cbcSMatt Macy   int n = lua_gettop(L);  /* number of elements to pack */
120eda14cbcSMatt Macy   lua_createtable(L, n, 1);  /* create result table */
121eda14cbcSMatt Macy   lua_pushinteger(L, n);
122eda14cbcSMatt Macy   lua_setfield(L, -2, "n");  /* t.n = number of elements */
123eda14cbcSMatt Macy   if (n > 0) {  /* at least one element? */
124eda14cbcSMatt Macy     int i;
125eda14cbcSMatt Macy     lua_pushvalue(L, 1);
126eda14cbcSMatt Macy     lua_rawseti(L, -2, 1);  /* insert first element */
127eda14cbcSMatt Macy     lua_replace(L, 1);  /* move table into index 1 */
128eda14cbcSMatt Macy     for (i = n; i >= 2; i--)  /* assign other elements */
129eda14cbcSMatt Macy       lua_rawseti(L, 1, i);
130eda14cbcSMatt Macy   }
131eda14cbcSMatt Macy   return 1;  /* return table */
132eda14cbcSMatt Macy }
133eda14cbcSMatt Macy 
134eda14cbcSMatt Macy 
unpack(lua_State * L)135eda14cbcSMatt Macy static int unpack (lua_State *L) {
136eda14cbcSMatt Macy   int i, e;
137eda14cbcSMatt Macy   unsigned int n;
138eda14cbcSMatt Macy   luaL_checktype(L, 1, LUA_TTABLE);
139eda14cbcSMatt Macy   i = luaL_optint(L, 2, 1);
140eda14cbcSMatt Macy   e = luaL_opt(L, luaL_checkint, 3, luaL_len(L, 1));
141eda14cbcSMatt Macy   if (i > e) return 0;  /* empty range */
142eda14cbcSMatt Macy   n = (unsigned int)e - (unsigned int)i;  /* number of elements minus 1 */
143eda14cbcSMatt Macy   if (n > (INT_MAX - 10) || !lua_checkstack(L, ++n))
144eda14cbcSMatt Macy     return luaL_error(L, "too many results to unpack");
145eda14cbcSMatt Macy   lua_rawgeti(L, 1, i);  /* push arg[i] (avoiding overflow problems) */
146eda14cbcSMatt Macy   while (i++ < e)  /* push arg[i + 1...e] */
147eda14cbcSMatt Macy     lua_rawgeti(L, 1, i);
148eda14cbcSMatt Macy   return n;
149eda14cbcSMatt Macy }
150eda14cbcSMatt Macy 
151eda14cbcSMatt Macy /* }====================================================== */
152eda14cbcSMatt Macy 
153eda14cbcSMatt Macy 
154eda14cbcSMatt Macy 
155eda14cbcSMatt Macy /*
156eda14cbcSMatt Macy ** {======================================================
157eda14cbcSMatt Macy ** Quicksort
158eda14cbcSMatt Macy ** (based on `Algorithms in MODULA-3', Robert Sedgewick;
159eda14cbcSMatt Macy **  Addison-Wesley, 1993.)
160eda14cbcSMatt Macy ** =======================================================
161eda14cbcSMatt Macy */
162eda14cbcSMatt Macy 
163eda14cbcSMatt Macy 
set2(lua_State * L,int i,int j)164eda14cbcSMatt Macy static void set2 (lua_State *L, int i, int j) {
165eda14cbcSMatt Macy   lua_rawseti(L, 1, i);
166eda14cbcSMatt Macy   lua_rawseti(L, 1, j);
167eda14cbcSMatt Macy }
168eda14cbcSMatt Macy 
sort_comp(lua_State * L,int a,int b)169eda14cbcSMatt Macy static int sort_comp (lua_State *L, int a, int b) {
170eda14cbcSMatt Macy   if (!lua_isnil(L, 2)) {  /* function? */
171eda14cbcSMatt Macy     int res;
172eda14cbcSMatt Macy     lua_pushvalue(L, 2);
173eda14cbcSMatt Macy     lua_pushvalue(L, a-1);  /* -1 to compensate function */
174eda14cbcSMatt Macy     lua_pushvalue(L, b-2);  /* -2 to compensate function and `a' */
175eda14cbcSMatt Macy     lua_call(L, 2, 1);
176eda14cbcSMatt Macy     res = lua_toboolean(L, -1);
177eda14cbcSMatt Macy     lua_pop(L, 1);
178eda14cbcSMatt Macy     return res;
179eda14cbcSMatt Macy   }
180eda14cbcSMatt Macy   else  /* a < b? */
181eda14cbcSMatt Macy     return lua_compare(L, a, b, LUA_OPLT);
182eda14cbcSMatt Macy }
183eda14cbcSMatt Macy 
auxsort(lua_State * L,int l,int u)184eda14cbcSMatt Macy static void auxsort (lua_State *L, int l, int u) {
185eda14cbcSMatt Macy   while (l < u) {  /* for tail recursion */
186eda14cbcSMatt Macy     int i, j;
187eda14cbcSMatt Macy     /* sort elements a[l], a[(l+u)/2] and a[u] */
188eda14cbcSMatt Macy     lua_rawgeti(L, 1, l);
189eda14cbcSMatt Macy     lua_rawgeti(L, 1, u);
190eda14cbcSMatt Macy     if (sort_comp(L, -1, -2))  /* a[u] < a[l]? */
191eda14cbcSMatt Macy       set2(L, l, u);  /* swap a[l] - a[u] */
192eda14cbcSMatt Macy     else
193eda14cbcSMatt Macy       lua_pop(L, 2);
194eda14cbcSMatt Macy     if (u-l == 1) break;  /* only 2 elements */
195eda14cbcSMatt Macy     i = (l+u)/2;
196eda14cbcSMatt Macy     lua_rawgeti(L, 1, i);
197eda14cbcSMatt Macy     lua_rawgeti(L, 1, l);
198eda14cbcSMatt Macy     if (sort_comp(L, -2, -1))  /* a[i]<a[l]? */
199eda14cbcSMatt Macy       set2(L, i, l);
200eda14cbcSMatt Macy     else {
201eda14cbcSMatt Macy       lua_pop(L, 1);  /* remove a[l] */
202eda14cbcSMatt Macy       lua_rawgeti(L, 1, u);
203eda14cbcSMatt Macy       if (sort_comp(L, -1, -2))  /* a[u]<a[i]? */
204eda14cbcSMatt Macy         set2(L, i, u);
205eda14cbcSMatt Macy       else
206eda14cbcSMatt Macy         lua_pop(L, 2);
207eda14cbcSMatt Macy     }
208eda14cbcSMatt Macy     if (u-l == 2) break;  /* only 3 elements */
209eda14cbcSMatt Macy     lua_rawgeti(L, 1, i);  /* Pivot */
210eda14cbcSMatt Macy     lua_pushvalue(L, -1);
211eda14cbcSMatt Macy     lua_rawgeti(L, 1, u-1);
212eda14cbcSMatt Macy     set2(L, i, u-1);
213eda14cbcSMatt Macy     /* a[l] <= P == a[u-1] <= a[u], only need to sort from l+1 to u-2 */
214eda14cbcSMatt Macy     i = l; j = u-1;
215eda14cbcSMatt Macy     for (;;) {  /* invariant: a[l..i] <= P <= a[j..u] */
216eda14cbcSMatt Macy       /* repeat ++i until a[i] >= P */
217eda14cbcSMatt Macy       while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) {
218eda14cbcSMatt Macy         if (i>=u) luaL_error(L, "invalid order function for sorting");
219eda14cbcSMatt Macy         lua_pop(L, 1);  /* remove a[i] */
220eda14cbcSMatt Macy       }
221eda14cbcSMatt Macy       /* repeat --j until a[j] <= P */
222eda14cbcSMatt Macy       while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) {
223eda14cbcSMatt Macy         if (j<=l) luaL_error(L, "invalid order function for sorting");
224eda14cbcSMatt Macy         lua_pop(L, 1);  /* remove a[j] */
225eda14cbcSMatt Macy       }
226eda14cbcSMatt Macy       if (j<i) {
227eda14cbcSMatt Macy         lua_pop(L, 3);  /* pop pivot, a[i], a[j] */
228eda14cbcSMatt Macy         break;
229eda14cbcSMatt Macy       }
230eda14cbcSMatt Macy       set2(L, i, j);
231eda14cbcSMatt Macy     }
232eda14cbcSMatt Macy     lua_rawgeti(L, 1, u-1);
233eda14cbcSMatt Macy     lua_rawgeti(L, 1, i);
234eda14cbcSMatt Macy     set2(L, u-1, i);  /* swap pivot (a[u-1]) with a[i] */
235eda14cbcSMatt Macy     /* a[l..i-1] <= a[i] == P <= a[i+1..u] */
236eda14cbcSMatt Macy     /* adjust so that smaller half is in [j..i] and larger one in [l..u] */
237eda14cbcSMatt Macy     if (i-l < u-i) {
238eda14cbcSMatt Macy       j=l; i=i-1; l=i+2;
239eda14cbcSMatt Macy     }
240eda14cbcSMatt Macy     else {
241eda14cbcSMatt Macy       j=i+1; i=u; u=j-2;
242eda14cbcSMatt Macy     }
243eda14cbcSMatt Macy     auxsort(L, j, i);  /* call recursively the smaller one */
244eda14cbcSMatt Macy   }  /* repeat the routine for the larger one */
245eda14cbcSMatt Macy }
246eda14cbcSMatt Macy 
tsort(lua_State * L)247eda14cbcSMatt Macy static int tsort (lua_State *L) {
248eda14cbcSMatt Macy   int n = aux_getn(L, 1);
249eda14cbcSMatt Macy   luaL_checkstack(L, 40, "");  /* assume array is smaller than 2^40 */
250eda14cbcSMatt Macy   if (!lua_isnoneornil(L, 2))  /* is there a 2nd argument? */
251eda14cbcSMatt Macy     luaL_checktype(L, 2, LUA_TFUNCTION);
252eda14cbcSMatt Macy   lua_settop(L, 2);  /* make sure there is two arguments */
253eda14cbcSMatt Macy   auxsort(L, 1, n);
254eda14cbcSMatt Macy   return 0;
255eda14cbcSMatt Macy }
256eda14cbcSMatt Macy 
257eda14cbcSMatt Macy /* }====================================================== */
258eda14cbcSMatt Macy 
259eda14cbcSMatt Macy 
260eda14cbcSMatt Macy static const luaL_Reg tab_funcs[] = {
261eda14cbcSMatt Macy   {"concat", tconcat},
262eda14cbcSMatt Macy #if defined(LUA_COMPAT_MAXN)
263eda14cbcSMatt Macy   {"maxn", maxn},
264eda14cbcSMatt Macy #endif
265eda14cbcSMatt Macy   {"insert", tinsert},
266eda14cbcSMatt Macy   {"pack", pack},
267eda14cbcSMatt Macy   {"unpack", unpack},
268eda14cbcSMatt Macy   {"remove", tremove},
269eda14cbcSMatt Macy   {"sort", tsort},
270eda14cbcSMatt Macy   {NULL, NULL}
271eda14cbcSMatt Macy };
272eda14cbcSMatt Macy 
273eda14cbcSMatt Macy 
luaopen_table(lua_State * L)274eda14cbcSMatt Macy LUAMOD_API int luaopen_table (lua_State *L) {
275eda14cbcSMatt Macy   luaL_newlib(L, tab_funcs);
276eda14cbcSMatt Macy #if defined(LUA_COMPAT_UNPACK)
277eda14cbcSMatt Macy   /* _G.unpack = table.unpack */
278eda14cbcSMatt Macy   lua_getfield(L, -1, "unpack");
279eda14cbcSMatt Macy   lua_setglobal(L, "unpack");
280eda14cbcSMatt Macy #endif
281eda14cbcSMatt Macy   return 1;
282eda14cbcSMatt Macy }
283eda14cbcSMatt Macy 
284eda14cbcSMatt Macy #if defined(_KERNEL)
285eda14cbcSMatt Macy 
286eda14cbcSMatt Macy EXPORT_SYMBOL(luaopen_table);
287eda14cbcSMatt Macy 
288eda14cbcSMatt Macy #endif
289