2022-02-23 23:08:28 -05:00
|
|
|
|
|
|
|
|
#include "wrap-string.hpp"
|
|
|
|
|
|
2020-11-27 13:21:07 -05:00
|
|
|
#include "table.hpp"
|
2020-12-05 18:57:53 -05:00
|
|
|
#include "source.hpp"
|
2020-11-27 13:21:07 -05:00
|
|
|
|
2021-07-03 19:49:55 -04:00
|
|
|
|
2023-04-06 20:12:03 -04:00
|
|
|
bool table_equal(LuaCoreStack &LS, LuaSlot t1, LuaSlot t2) {
|
2021-09-07 17:37:23 -04:00
|
|
|
lua_State *L = LS.state();
|
2022-03-16 14:00:52 -04:00
|
|
|
int top = lua_gettop(L);
|
2022-07-22 16:00:37 -04:00
|
|
|
LS.checktable(t1, "table1");
|
|
|
|
|
LS.checktable(t2, "table2");
|
2022-03-16 14:00:52 -04:00
|
|
|
int nkeys1 = lua_nkeys(L, t1.index());
|
|
|
|
|
int nkeys2 = lua_nkeys(L, t2.index());
|
|
|
|
|
if (nkeys1 != nkeys2) return false;
|
|
|
|
|
int total = 0;
|
2021-01-02 13:31:18 -05:00
|
|
|
lua_pushnil(L);
|
|
|
|
|
while (lua_next(L, t1.index()) != 0) {
|
|
|
|
|
lua_pushvalue(L, -2); // k v1 k
|
|
|
|
|
lua_rawget(L, t2.index()); // k v1 v2
|
2021-02-28 14:45:09 -05:00
|
|
|
if (!lua_rawequal(L, -1, -2)) {
|
2022-03-16 14:00:52 -04:00
|
|
|
lua_settop(L, top);
|
2021-09-07 17:37:23 -04:00
|
|
|
return false;
|
2021-01-02 13:31:18 -05:00
|
|
|
}
|
|
|
|
|
lua_pop(L, 2);
|
2022-03-16 14:00:52 -04:00
|
|
|
total += 1;
|
2021-01-02 13:31:18 -05:00
|
|
|
}
|
2022-03-16 14:00:52 -04:00
|
|
|
assert(total == nkeys1);
|
|
|
|
|
lua_settop(L, top);
|
|
|
|
|
return true;
|
2021-09-07 17:37:23 -04:00
|
|
|
}
|
|
|
|
|
|
2021-12-15 23:03:43 -05:00
|
|
|
LuaDefine(table_equal, "table1,table2", "return true if two tables contain the same keys and values") {
|
2021-09-07 17:37:23 -04:00
|
|
|
LuaArg t1, t2;
|
|
|
|
|
LuaRet eql;
|
2023-04-07 12:58:05 -04:00
|
|
|
LuaDefStack LS(L, t1, t2, eql);
|
2021-09-07 17:37:23 -04:00
|
|
|
LS.set(eql, table_equal(LS, t1, t2));
|
2021-01-02 13:31:18 -05:00
|
|
|
return LS.result();
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-15 23:03:43 -05:00
|
|
|
LuaDefine(table_findremove, "vector,value", "remove all occurrences of value from vector") {
|
2021-01-02 13:31:18 -05:00
|
|
|
luaL_checktype(L, -2, LUA_TTABLE);
|
|
|
|
|
int src = 1;
|
|
|
|
|
int dst = 1;
|
|
|
|
|
while (true) {
|
|
|
|
|
lua_pushinteger(L, src);
|
|
|
|
|
lua_rawget(L, -3);
|
2021-02-28 14:45:09 -05:00
|
|
|
if (lua_rawequal(L, -1, -2)) {
|
2021-01-02 13:31:18 -05:00
|
|
|
src++;
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
} else if (lua_isnil(L, -1)) {
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
int removed = src - dst;
|
|
|
|
|
while (src > dst) {
|
|
|
|
|
lua_pushinteger(L, dst);
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
lua_rawset(L, -4);
|
|
|
|
|
dst++;
|
|
|
|
|
}
|
|
|
|
|
lua_pop(L, 2);
|
|
|
|
|
lua_pushinteger(L, removed);
|
|
|
|
|
return 1;
|
|
|
|
|
} else {
|
|
|
|
|
if (src > dst) {
|
|
|
|
|
lua_pushinteger(L, dst);
|
|
|
|
|
lua_insert(L, lua_gettop(L) - 1);
|
|
|
|
|
lua_rawset(L, -4);
|
|
|
|
|
} else {
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
}
|
|
|
|
|
src++;
|
|
|
|
|
dst++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-12 14:14:38 -05:00
|
|
|
|
2021-12-15 23:03:43 -05:00
|
|
|
LuaDefine(table_push, "vector,value", "push a value onto the end of a vector") {
|
2021-01-12 14:14:38 -05:00
|
|
|
luaL_checktype(L, -2, LUA_TTABLE);
|
2021-02-28 14:45:09 -05:00
|
|
|
int len = lua_rawlen(L, -2);
|
2021-01-12 14:14:38 -05:00
|
|
|
lua_pushinteger(L, len+1);
|
|
|
|
|
lua_pushvalue(L, -2);
|
|
|
|
|
lua_rawset(L, -4);
|
|
|
|
|
lua_pop(L, 2);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-15 23:03:43 -05:00
|
|
|
LuaDefine(table_find, "vector,value", "find the first occurrence of value in vector") {
|
2021-01-02 13:31:18 -05:00
|
|
|
luaL_checktype(L, -2, LUA_TTABLE);
|
|
|
|
|
for (int i = 1; ; i++) {
|
|
|
|
|
lua_pushinteger(L, i);
|
|
|
|
|
lua_rawget(L, -3);
|
2021-02-28 14:45:09 -05:00
|
|
|
if (lua_rawequal(L, -1, -2)) {
|
2021-01-02 13:31:18 -05:00
|
|
|
lua_pop(L, 3);
|
|
|
|
|
lua_pushinteger(L, i);
|
|
|
|
|
return 1;
|
|
|
|
|
} else if (lua_isnil(L, -1)) {
|
|
|
|
|
lua_pop(L, 3);
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
return 1;
|
|
|
|
|
} else {
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-16 14:00:52 -04:00
|
|
|
LuaDefine(table_empty, "table", "return true if the table has zero keys") {
|
2021-01-02 13:31:18 -05:00
|
|
|
luaL_checktype(L, -1, LUA_TTABLE);
|
2021-12-15 23:03:43 -05:00
|
|
|
int total = lua_nkeys(L, -1);
|
|
|
|
|
lua_pushboolean(L, (total == 0)?1:0);
|
|
|
|
|
return 1;
|
2021-01-02 13:31:18 -05:00
|
|
|
}
|
|
|
|
|
|
2021-12-15 23:03:43 -05:00
|
|
|
LuaDefine(table_count, "table", "return the number of keys in table") {
|
2021-01-02 13:31:18 -05:00
|
|
|
luaL_checktype(L, -1, LUA_TTABLE);
|
2021-07-09 13:52:03 -04:00
|
|
|
int total = lua_nkeys(L, -1);
|
2021-01-02 13:31:18 -05:00
|
|
|
lua_pushinteger(L, total);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-15 23:03:43 -05:00
|
|
|
LuaDefine(table_clear, "table,metaflag", "clear all keys, and optionally the metatable") {
|
2021-10-25 14:47:37 -04:00
|
|
|
LuaArg tab, clearmeta;
|
|
|
|
|
LuaVar metatable, metafield;
|
2023-04-07 12:58:05 -04:00
|
|
|
LuaDefStack LS(L, tab, clearmeta, metatable, metafield);
|
2022-07-22 16:00:37 -04:00
|
|
|
LS.checktable(tab, "table");
|
2021-10-25 14:47:37 -04:00
|
|
|
if (LS.ckboolean(clearmeta)) {
|
|
|
|
|
LS.getmetatable(metatable, tab);
|
|
|
|
|
if (LS.istable(metatable)) {
|
|
|
|
|
LS.rawget(metafield, metatable, "__metatable");
|
|
|
|
|
if (!LS.isnil(metafield)) {
|
|
|
|
|
luaL_error(L, "Cannot clear metatable.");
|
|
|
|
|
return LS.result();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
LS.cleartable(tab, true);
|
|
|
|
|
} else {
|
|
|
|
|
LS.cleartable(tab, false);
|
|
|
|
|
}
|
2020-11-27 13:21:07 -05:00
|
|
|
return LS.result();
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-15 23:03:43 -05:00
|
|
|
LuaDefine(table_getflagbits, "table", "get the table's flag bits (debugging only)") {
|
2021-07-25 20:34:57 -04:00
|
|
|
LuaArg tab;
|
|
|
|
|
LuaRet bits;
|
2023-04-07 12:58:05 -04:00
|
|
|
LuaDefStack LS(L, tab, bits);
|
2021-08-09 13:20:32 -04:00
|
|
|
uint16_t ubits = lua_getflagbits(L, tab.index());
|
2021-07-25 20:34:57 -04:00
|
|
|
LS.set(bits, ubits);
|
|
|
|
|
return LS.result();
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-15 23:03:43 -05:00
|
|
|
LuaDefine(table_setflagbits, "table,bits", "set the table's flag bits (debugging only)") {
|
2021-07-25 20:34:57 -04:00
|
|
|
LuaArg tab, bits;
|
2023-04-07 12:58:05 -04:00
|
|
|
LuaDefStack LS(L, tab, bits);
|
2021-08-09 13:20:32 -04:00
|
|
|
uint16_t ubits = LS.ckinteger(bits);
|
2021-07-25 20:34:57 -04:00
|
|
|
lua_setflagbits(L, tab.index(), ubits);
|
|
|
|
|
return LS.result();
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-09 18:07:06 -04:00
|
|
|
/////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
2021-07-12 00:37:07 -04:00
|
|
|
// Deque operators.
|
2021-07-09 18:07:06 -04:00
|
|
|
//
|
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
|
|
|
|
2021-07-12 00:37:07 -04:00
|
|
|
#define DEQUE_LEFT 1
|
|
|
|
|
#define DEQUE_FILL 2
|
|
|
|
|
#define DEQUE_MAX 3
|
|
|
|
|
#define DEQUE_BASE 4
|
2021-07-09 18:07:06 -04:00
|
|
|
|
2021-07-12 00:37:07 -04:00
|
|
|
void deque_checktype(lua_State *L, int slot, int type) {
|
|
|
|
|
if (lua_type(L, slot) != type) {
|
|
|
|
|
luaL_error(L, "object is not a valid deque");
|
2021-07-09 18:07:06 -04:00
|
|
|
}
|
2021-01-02 13:31:18 -05:00
|
|
|
}
|
|
|
|
|
|
2021-07-12 00:37:07 -04:00
|
|
|
void deque_get_info(lua_State *L, int deque, int *left, int *fill, int *max) {
|
|
|
|
|
luaL_checktype(L, deque, LUA_TTABLE);
|
|
|
|
|
if (left) {
|
|
|
|
|
lua_rawgeti(L, deque, DEQUE_LEFT);
|
|
|
|
|
deque_checktype(L, -1, LUA_TNUMBER);
|
|
|
|
|
*left = lua_tointeger(L, -1);
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
}
|
|
|
|
|
if (fill) {
|
|
|
|
|
lua_rawgeti(L, deque, DEQUE_FILL);
|
|
|
|
|
deque_checktype(L, -1, LUA_TNUMBER);
|
|
|
|
|
*fill = lua_tointeger(L, -1);
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
}
|
|
|
|
|
if (max) {
|
|
|
|
|
lua_rawgeti(L, deque, DEQUE_MAX);
|
|
|
|
|
deque_checktype(L, -1, LUA_TNUMBER);
|
|
|
|
|
*max = lua_tointeger(L, -1);
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-07-09 18:07:06 -04:00
|
|
|
|
2021-07-12 00:37:07 -04:00
|
|
|
void deque_put_info(lua_State *L, int deque, int *left, int *fill, int *max) {
|
|
|
|
|
if (left) {
|
|
|
|
|
lua_pushinteger(L, *left);
|
|
|
|
|
lua_rawseti(L, deque, DEQUE_LEFT);
|
|
|
|
|
}
|
|
|
|
|
if (fill) {
|
|
|
|
|
lua_pushinteger(L, *fill);
|
|
|
|
|
lua_rawseti(L, deque, DEQUE_FILL);
|
|
|
|
|
}
|
|
|
|
|
if (max) {
|
|
|
|
|
lua_pushinteger(L, *max);
|
|
|
|
|
lua_rawseti(L, deque, DEQUE_MAX);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int deque_make_room(lua_State *L, int deque, int left, int fill, int max) {
|
2021-07-09 18:07:06 -04:00
|
|
|
if (fill == max) {
|
2021-07-12 00:37:07 -04:00
|
|
|
for (int i = 0; i < left; i++) {
|
|
|
|
|
lua_rawgeti(L, deque, DEQUE_BASE + i);
|
|
|
|
|
lua_rawseti(L, deque, DEQUE_BASE + i + max);
|
2021-07-09 18:07:06 -04:00
|
|
|
lua_pushinteger(L, 0);
|
2021-07-12 00:37:07 -04:00
|
|
|
lua_rawseti(L, deque, DEQUE_BASE + i);
|
2021-07-09 18:07:06 -04:00
|
|
|
}
|
2021-07-12 00:37:07 -04:00
|
|
|
for (int i = left; i < max; i++) {
|
2021-07-09 18:07:06 -04:00
|
|
|
lua_pushinteger(L, 0);
|
2021-07-12 00:37:07 -04:00
|
|
|
lua_rawseti(L, deque, DEQUE_BASE + i + max);
|
2021-07-09 18:07:06 -04:00
|
|
|
}
|
|
|
|
|
max *= 2;
|
2021-07-12 00:37:07 -04:00
|
|
|
lua_pushinteger(L, max);
|
|
|
|
|
lua_rawseti(L, deque, DEQUE_MAX);
|
|
|
|
|
}
|
|
|
|
|
return max;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-15 23:03:43 -05:00
|
|
|
LuaDefine(deque_create, "", "create a deque") {
|
2021-07-12 00:37:07 -04:00
|
|
|
LuaRet rdeque;
|
2021-07-12 16:32:58 -04:00
|
|
|
LuaVar classobj;
|
2023-04-07 12:58:05 -04:00
|
|
|
LuaDefStack LS(L, rdeque, classobj);
|
2021-07-12 16:32:58 -04:00
|
|
|
const int imax = 4;
|
2022-02-24 02:17:41 -05:00
|
|
|
eng::string err = LS.getclass(classobj, "deque");
|
2021-12-27 16:44:12 -05:00
|
|
|
if (err != "") {
|
|
|
|
|
luaL_error(L, "Class deque has been corrupted");
|
|
|
|
|
}
|
2021-07-12 00:37:07 -04:00
|
|
|
LS.createtable(rdeque, DEQUE_BASE + imax - 1, 0);
|
2021-11-17 15:11:55 -05:00
|
|
|
LS.rawset(rdeque, DEQUE_LEFT, 0);
|
|
|
|
|
LS.rawset(rdeque, DEQUE_FILL, 0);
|
|
|
|
|
LS.rawset(rdeque, DEQUE_MAX, imax);
|
2021-07-12 00:37:07 -04:00
|
|
|
for (int i = 0; i < imax; i++) {
|
2021-11-17 15:11:55 -05:00
|
|
|
LS.rawset(rdeque, DEQUE_BASE + i, 0);
|
2021-07-09 18:07:06 -04:00
|
|
|
}
|
2021-07-12 16:32:58 -04:00
|
|
|
LS.setmetatable(rdeque, classobj);
|
2021-01-02 13:31:18 -05:00
|
|
|
return LS.result();
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-15 23:03:43 -05:00
|
|
|
LuaDefine(deque_pushl, "deque,value", "push onto the left end of a deque") {
|
2021-07-12 00:37:07 -04:00
|
|
|
LuaArg deque, elt;
|
2023-04-07 12:58:05 -04:00
|
|
|
LuaDefStack LS(L, deque, elt);
|
2021-07-12 00:37:07 -04:00
|
|
|
int left, fill, max;
|
|
|
|
|
deque_get_info(L, deque.index(), &left, &fill, &max);
|
|
|
|
|
max = deque_make_room(L, deque.index(), left, fill, max);
|
|
|
|
|
int target = (left - 1) & (max-1);
|
2021-11-17 15:11:55 -05:00
|
|
|
LS.rawset(deque, DEQUE_BASE + target, elt);
|
2021-07-12 00:37:07 -04:00
|
|
|
fill += 1;
|
|
|
|
|
left = (left - 1) & (max - 1);
|
|
|
|
|
deque_put_info(L, deque.index(), &left, &fill, NULL);
|
|
|
|
|
return LS.result();
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-15 23:03:43 -05:00
|
|
|
LuaDefine(deque_pushr, "deque,value", "push onto the right end of a deque") {
|
2021-07-12 00:37:07 -04:00
|
|
|
LuaArg deque, elt;
|
2023-04-07 12:58:05 -04:00
|
|
|
LuaDefStack LS(L, deque, elt);
|
2021-07-12 00:37:07 -04:00
|
|
|
int left, fill, max;
|
|
|
|
|
deque_get_info(L, deque.index(), &left, &fill, &max);
|
|
|
|
|
max = deque_make_room(L, deque.index(), left, fill, max);
|
|
|
|
|
int target = (left + fill) & (max-1);
|
2021-11-17 15:11:55 -05:00
|
|
|
LS.rawset(deque, DEQUE_BASE + target, elt);
|
2021-07-12 00:37:07 -04:00
|
|
|
fill += 1;
|
|
|
|
|
deque_put_info(L, deque.index(), NULL, &fill, NULL);
|
|
|
|
|
return LS.result();
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-15 23:03:43 -05:00
|
|
|
LuaDefine(deque_popl, "deque", "pop the left end of a deque") {
|
2021-07-12 00:37:07 -04:00
|
|
|
LuaArg deque;
|
2021-07-09 18:07:06 -04:00
|
|
|
LuaRet result;
|
2023-04-07 12:58:05 -04:00
|
|
|
LuaDefStack LS(L, deque, result);
|
2021-07-12 00:37:07 -04:00
|
|
|
int left, fill, max;
|
|
|
|
|
deque_get_info(L, deque.index(), &left, &fill, &max);
|
|
|
|
|
if (fill == 0) {
|
2021-07-09 18:07:06 -04:00
|
|
|
LS.set(result, LuaNil);
|
|
|
|
|
return LS.result();
|
2021-01-02 13:31:18 -05:00
|
|
|
}
|
2021-11-17 15:11:55 -05:00
|
|
|
LS.rawget(result, deque, DEQUE_BASE + left);
|
|
|
|
|
LS.rawset(deque, DEQUE_BASE + left, 0);
|
2021-07-12 00:37:07 -04:00
|
|
|
left = (left + 1) & (max - 1);
|
|
|
|
|
fill -= 1;
|
|
|
|
|
deque_put_info(L, deque.index(), &left, &fill, NULL);
|
2021-01-02 13:31:18 -05:00
|
|
|
return LS.result();
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-15 23:03:43 -05:00
|
|
|
LuaDefine(deque_popr, "deque", "pop the right end of a deque") {
|
2021-07-12 00:37:07 -04:00
|
|
|
LuaArg deque;
|
|
|
|
|
LuaRet result;
|
2023-04-07 12:58:05 -04:00
|
|
|
LuaDefStack LS(L, deque, result);
|
2021-07-12 00:37:07 -04:00
|
|
|
int left, fill, max;
|
|
|
|
|
deque_get_info(L, deque.index(), &left, &fill, &max);
|
|
|
|
|
if (fill == 0) {
|
|
|
|
|
LS.set(result, LuaNil);
|
|
|
|
|
return LS.result();
|
|
|
|
|
}
|
|
|
|
|
int target = (left + fill - 1) & (max - 1);
|
2021-11-17 15:11:55 -05:00
|
|
|
LS.rawget(result, deque, DEQUE_BASE + target);
|
|
|
|
|
LS.rawset(deque, DEQUE_BASE + target, 0);
|
2021-07-12 00:37:07 -04:00
|
|
|
fill -= 1;
|
|
|
|
|
deque_put_info(L, deque.index(), NULL, &fill, NULL);
|
2021-01-02 13:31:18 -05:00
|
|
|
return LS.result();
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-15 23:03:43 -05:00
|
|
|
LuaDefine(deque_nthl, "deque,n", "return the nth item from the left end of a deque") {
|
2021-07-12 00:37:07 -04:00
|
|
|
LuaArg deque, nn;
|
|
|
|
|
LuaRet result;
|
2023-04-07 12:58:05 -04:00
|
|
|
LuaDefStack LS(L, deque, nn, result);
|
2021-07-12 00:37:07 -04:00
|
|
|
int left, fill, max;
|
|
|
|
|
deque_get_info(L, deque.index(), &left, &fill, &max);
|
|
|
|
|
int n = LS.ckint(nn);
|
|
|
|
|
if ((n < 1) || (n > fill)) {
|
|
|
|
|
LS.set(result, LuaNil);
|
2021-07-09 18:07:06 -04:00
|
|
|
return LS.result();
|
2021-01-02 13:31:18 -05:00
|
|
|
}
|
2021-07-12 00:37:07 -04:00
|
|
|
int target = (left + n - 1) & (max - 1);
|
2021-11-17 15:11:55 -05:00
|
|
|
LS.rawget(result, deque, DEQUE_BASE + target);
|
2021-01-02 13:31:18 -05:00
|
|
|
return LS.result();
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-15 23:03:43 -05:00
|
|
|
LuaDefine(deque_nthr, "deque,n", "return the nth item from the right end of a deque") {
|
2021-07-12 00:37:07 -04:00
|
|
|
LuaArg deque, nn;
|
|
|
|
|
LuaRet result;
|
2023-04-07 12:58:05 -04:00
|
|
|
LuaDefStack LS(L, deque, nn, result);
|
2021-07-12 00:37:07 -04:00
|
|
|
int left, fill, max;
|
|
|
|
|
deque_get_info(L, deque.index(), &left, &fill, &max);
|
|
|
|
|
int n = LS.ckint(nn);
|
|
|
|
|
if ((n < 1) || (n > fill)) {
|
|
|
|
|
LS.set(result, LuaNil);
|
|
|
|
|
return LS.result();
|
|
|
|
|
}
|
|
|
|
|
int target = (left + fill - n) & (max - 1);
|
2021-11-17 15:11:55 -05:00
|
|
|
LS.rawget(result, deque, DEQUE_BASE + target);
|
2021-07-12 00:37:07 -04:00
|
|
|
return LS.result();
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-15 23:03:43 -05:00
|
|
|
LuaDefine(deque_setl, "deque,n,value", "set the nth item from the left end of a deque") {
|
2021-07-20 16:16:07 -04:00
|
|
|
LuaArg deque, nn, val;
|
2023-04-07 12:58:05 -04:00
|
|
|
LuaDefStack LS(L, deque, nn, val);
|
2021-07-20 16:16:07 -04:00
|
|
|
int left, fill, max;
|
|
|
|
|
deque_get_info(L, deque.index(), &left, &fill, &max);
|
|
|
|
|
int n = LS.ckint(nn);
|
|
|
|
|
if ((n < 1) || (n > fill)) {
|
|
|
|
|
luaL_error(L, "invalid index");
|
|
|
|
|
return LS.result();
|
|
|
|
|
}
|
|
|
|
|
int target = (left + n - 1) & (max - 1);
|
2021-11-17 15:11:55 -05:00
|
|
|
LS.rawset(deque, DEQUE_BASE + target, val);
|
2021-07-20 16:16:07 -04:00
|
|
|
return LS.result();
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-15 23:03:43 -05:00
|
|
|
LuaDefine(deque_setr, "deque,n,value", "set the nth item from the right end of a deque") {
|
2021-07-20 16:16:07 -04:00
|
|
|
LuaArg deque, nn, val;
|
2023-04-07 12:58:05 -04:00
|
|
|
LuaDefStack LS(L, deque, nn, val);
|
2021-07-20 16:16:07 -04:00
|
|
|
int left, fill, max;
|
|
|
|
|
deque_get_info(L, deque.index(), &left, &fill, &max);
|
|
|
|
|
int n = LS.ckint(nn);
|
|
|
|
|
if ((n < 1) || (n > fill)) {
|
|
|
|
|
luaL_error(L, "invalid index");
|
|
|
|
|
return LS.result();
|
|
|
|
|
}
|
|
|
|
|
int target = (left + fill - n) & (max - 1);
|
2021-11-17 15:11:55 -05:00
|
|
|
LS.rawset(deque, DEQUE_BASE + target, val);
|
2021-07-20 16:16:07 -04:00
|
|
|
return LS.result();
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-15 23:03:43 -05:00
|
|
|
LuaDefine(deque_findl, "deque,value", "find the first occurence of value in deque, starting from left") {
|
2021-07-20 14:48:53 -04:00
|
|
|
LuaArg deque, val;
|
|
|
|
|
LuaRet pos;
|
|
|
|
|
LuaVar check;
|
2023-04-07 12:58:05 -04:00
|
|
|
LuaDefStack LS(L, deque, val, pos, check);
|
2021-07-20 14:48:53 -04:00
|
|
|
int left, fill, max;
|
|
|
|
|
deque_get_info(L, deque.index(), &left, &fill, &max);
|
|
|
|
|
for (int i = 0; i < fill; i++) {
|
|
|
|
|
int index = (left + i) & (max - 1);
|
2021-11-17 15:11:55 -05:00
|
|
|
LS.rawget(check, deque, DEQUE_BASE + index);
|
2021-07-20 14:48:53 -04:00
|
|
|
if (LS.rawequal(check, val)) {
|
|
|
|
|
LS.set(pos, i + 1);
|
|
|
|
|
return LS.result();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
LS.set(pos, LuaNil);
|
|
|
|
|
return LS.result();
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-15 23:03:43 -05:00
|
|
|
LuaDefine(deque_findr, "deque,value", "find the first occurrence of value in deque, starting from right") {
|
2021-07-20 14:48:53 -04:00
|
|
|
LuaArg deque, val;
|
|
|
|
|
LuaRet pos;
|
|
|
|
|
LuaVar check;
|
2023-04-07 12:58:05 -04:00
|
|
|
LuaDefStack LS(L, deque, val, pos, check);
|
2021-07-20 14:48:53 -04:00
|
|
|
int left, fill, max;
|
|
|
|
|
deque_get_info(L, deque.index(), &left, &fill, &max);
|
|
|
|
|
int base = left + fill - 1;
|
|
|
|
|
for (int i = 0; i < fill; i++) {
|
|
|
|
|
int index = (base - i) & (max - 1);
|
2021-11-17 15:11:55 -05:00
|
|
|
LS.rawget(check, deque, DEQUE_BASE + index);
|
2021-07-20 14:48:53 -04:00
|
|
|
if (LS.rawequal(check, val)) {
|
|
|
|
|
LS.set(pos, i + 1);
|
|
|
|
|
return LS.result();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
LS.set(pos, LuaNil);
|
|
|
|
|
return LS.result();
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-15 23:03:43 -05:00
|
|
|
LuaDefine(deque_size, "deque", "return the number of items in the deque") {
|
2021-07-12 00:37:07 -04:00
|
|
|
LuaArg deque;
|
|
|
|
|
LuaRet size;
|
2023-04-07 12:58:05 -04:00
|
|
|
LuaDefStack LS(L, deque, size);
|
2022-07-22 16:00:37 -04:00
|
|
|
LS.checktable(deque, "deque");
|
2021-11-17 15:11:55 -05:00
|
|
|
LS.rawget(size, deque, DEQUE_FILL);
|
2022-07-22 16:00:37 -04:00
|
|
|
LS.checknumber(size, "deque size");
|
2021-07-12 00:37:07 -04:00
|
|
|
return LS.result();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2021-07-03 19:49:55 -04:00
|
|
|
/////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
2021-07-09 18:07:06 -04:00
|
|
|
// table_getpairs
|
2021-07-03 19:49:55 -04:00
|
|
|
//
|
|
|
|
|
// Given a table, return all the pairs in the table as a sequence.
|
|
|
|
|
// The resulting sequence contains a 1 in the first position,
|
|
|
|
|
// followed by the pairs, like so:
|
|
|
|
|
//
|
|
|
|
|
// sortedpairs({a=1,b=2,c=3}) => {1,"a",1,"b",2,"c",3}
|
|
|
|
|
//
|
|
|
|
|
// Note that this function is not directly exposed to lua.
|
2021-07-09 18:07:06 -04:00
|
|
|
// It's exposed only through the 'sortedpairs' iterator.
|
2021-07-03 19:49:55 -04:00
|
|
|
//
|
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
static void pushkey (lua_State *L, int tab, int i) {
|
|
|
|
|
lua_rawgeti(L, tab, i*2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void push2keys (lua_State *L, int tab, int i, int j) {
|
|
|
|
|
lua_rawgeti(L, tab, i*2);
|
|
|
|
|
lua_rawgeti(L, tab, j*2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void pop2keys (lua_State *L, int tab, int i, int j) {
|
|
|
|
|
lua_rawseti(L, tab, i*2);
|
|
|
|
|
lua_rawseti(L, tab, j*2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void swap2values (lua_State *L, int tab, int i, int j) {
|
|
|
|
|
lua_rawgeti(L, tab, i*2+1);
|
|
|
|
|
lua_rawgeti(L, tab, j*2+1);
|
|
|
|
|
lua_rawseti(L, tab, i*2+1);
|
|
|
|
|
lua_rawseti(L, tab, j*2+1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void auxsort (lua_State *L, int tab, int l, int u) {
|
|
|
|
|
while (l < u) { /* for tail recursion */
|
|
|
|
|
int i, j;
|
|
|
|
|
/* sort elements a[l], a[(l+u)/2] and a[u] */
|
|
|
|
|
push2keys(L, tab, l, u);
|
|
|
|
|
if (lua_genlt(L, -1, -2)) {
|
|
|
|
|
pop2keys(L, tab, l, u);
|
|
|
|
|
swap2values(L, tab, l, u);
|
|
|
|
|
} else {
|
|
|
|
|
lua_pop(L, 2);
|
|
|
|
|
}
|
|
|
|
|
if (u - l == 1) break; /* only 2 elements */
|
|
|
|
|
i = (l + u) / 2;
|
|
|
|
|
push2keys(L, tab, i, l);
|
|
|
|
|
if (lua_genlt(L, -2, -1)) {
|
|
|
|
|
pop2keys(L, tab, i, l);
|
|
|
|
|
swap2values(L, tab, i, l);
|
|
|
|
|
} else {
|
|
|
|
|
lua_pop(L, 1); /* remove a[l] */
|
|
|
|
|
pushkey(L, tab, u);
|
|
|
|
|
if (lua_genlt(L, -1, -2)) {
|
|
|
|
|
pop2keys(L, tab, i, u);
|
|
|
|
|
swap2values(L, tab, i, u);
|
|
|
|
|
} else {
|
|
|
|
|
lua_pop(L, 2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (u - l == 2) break; /* only 3 elements */
|
|
|
|
|
/* put the pivot value on top of the stack and keep it there */
|
|
|
|
|
pushkey(L, tab, i);
|
|
|
|
|
/* move the pivot from i to u-1 */
|
|
|
|
|
lua_pushvalue(L, -1);
|
|
|
|
|
pushkey(L, tab, u-1);
|
|
|
|
|
pop2keys(L, tab, i, u-1);
|
|
|
|
|
swap2values(L, tab, i, u-1);
|
|
|
|
|
/* a[l] <= P == a[u-1] <= a[u], only need to sort from l+1 to u-2 */
|
|
|
|
|
i = l;
|
|
|
|
|
j = u - 1;
|
|
|
|
|
for (;;) { /* invariant: a[l..i] <= P <= a[j..u] */
|
|
|
|
|
/* repeat ++i until a[i] >= P */
|
|
|
|
|
while (pushkey(L, tab, ++i), lua_genlt(L, -1, -2)) {
|
|
|
|
|
if (i >= u) luaL_error(L, "invalid order function for sorting");
|
|
|
|
|
lua_pop(L, 1); /* remove a[i] */
|
|
|
|
|
}
|
|
|
|
|
/* repeat --j until a[j] <= P */
|
|
|
|
|
while (pushkey(L, tab, --j), lua_genlt(L, -3, -1)) {
|
|
|
|
|
if (j <= l) luaL_error(L, "invalid order function for sorting");
|
|
|
|
|
lua_pop(L, 1); /* remove a[j] */
|
|
|
|
|
}
|
|
|
|
|
if (j < i) {
|
|
|
|
|
lua_pop(L, 3); /* pop pivot, a[i], a[j] */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
pop2keys(L, tab, i, j);
|
|
|
|
|
swap2values(L, tab, i, j);
|
|
|
|
|
}
|
|
|
|
|
push2keys(L, tab, u-1, i);
|
|
|
|
|
pop2keys(L, tab, u-1, i);
|
|
|
|
|
swap2values(L, tab, u-1, i);
|
|
|
|
|
/* a[l..i-1] <= a[i] == P <= a[i+1..u] */
|
|
|
|
|
/* adjust so that smaller half is in [j..i] and larger one in [l..u] */
|
|
|
|
|
if (i - l < u - i) {
|
|
|
|
|
j = l;
|
|
|
|
|
i = i - 1;
|
|
|
|
|
l = i + 2;
|
|
|
|
|
} else {
|
|
|
|
|
j = i + 1;
|
|
|
|
|
i = u;
|
|
|
|
|
u = j - 2;
|
|
|
|
|
}
|
|
|
|
|
auxsort(L, tab, j, i); /* call recursively the smaller one */
|
|
|
|
|
} /* repeat the routine for the larger one */
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-06 20:12:03 -04:00
|
|
|
bool table_getpairs(LuaCoreStack &LS0, LuaSlot tab, LuaSlot pairs, bool sort) {
|
2021-09-08 01:32:08 -04:00
|
|
|
lua_State *L = LS0.state();
|
2021-07-03 19:49:55 -04:00
|
|
|
LuaVar key, value;
|
2023-04-07 12:58:05 -04:00
|
|
|
LuaExtStack LS(L, key, value);
|
2021-09-08 01:32:08 -04:00
|
|
|
bool sorted = true;
|
2021-07-03 19:49:55 -04:00
|
|
|
// Create the table, store the initial 1.
|
2021-09-08 01:32:08 -04:00
|
|
|
int total = lua_nkeys(L, tab.index());
|
2021-07-03 19:49:55 -04:00
|
|
|
LS.createtable(pairs, total * 2 + 1, 0);
|
2021-11-17 15:11:55 -05:00
|
|
|
LS.rawset(pairs, 1, 1);
|
2021-07-03 19:49:55 -04:00
|
|
|
// Transfer the pairs into the sequence.
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
int offset = 2;
|
|
|
|
|
while (lua_next(L, tab.index()) != 0) {
|
|
|
|
|
int ktype = lua_type(L, -2);
|
2021-09-08 01:32:08 -04:00
|
|
|
if (ktype != LUA_TNUMBER && ktype != LUA_TSTRING && ktype != LUA_TBOOLEAN) {
|
|
|
|
|
sorted = false;
|
2021-07-03 19:49:55 -04:00
|
|
|
}
|
2021-09-08 01:32:08 -04:00
|
|
|
lua_pushvalue(L, -2); // K V K
|
|
|
|
|
lua_rawseti(L, pairs.index(), offset++);
|
|
|
|
|
lua_rawseti(L, pairs.index(), offset++);
|
2021-07-03 19:49:55 -04:00
|
|
|
}
|
2021-07-05 15:44:37 -04:00
|
|
|
if (sort) {
|
|
|
|
|
auxsort(L, pairs.index(), 1, total);
|
|
|
|
|
}
|
2021-09-08 01:32:08 -04:00
|
|
|
return sorted;
|
2021-07-03 19:49:55 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// Given a sortedpairs vector, return the (key, value) pairs
|
|
|
|
|
// one by one. The first element of the vector is used as a
|
|
|
|
|
// counter to keep track of our position.
|
|
|
|
|
//
|
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
|
|
|
|
2021-12-15 23:03:43 -05:00
|
|
|
LuaDefine(table_nextsortedpair, "sortedpairs,dummy", "next function used by sortedpairs") {
|
2021-07-03 19:49:55 -04:00
|
|
|
if (lua_gettop(L) < 2) {
|
|
|
|
|
luaL_error(L, "Not enough arguments to nextpair");
|
|
|
|
|
}
|
|
|
|
|
luaL_checktype(L, 1, LUA_TTABLE);
|
|
|
|
|
lua_rawgeti(L, 1, 1);
|
|
|
|
|
lua_Integer i = luaL_checkinteger(L, -1);
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
lua_pushinteger(L, i+1);
|
|
|
|
|
lua_rawseti(L, 1, 1);
|
|
|
|
|
lua_rawgeti(L, 1, i*2);
|
|
|
|
|
if (lua_isnil(L, -1)) {
|
|
|
|
|
return 1;
|
|
|
|
|
} else {
|
|
|
|
|
lua_rawgeti(L, 1, i*2+1);
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-01 17:35:06 -05:00
|
|
|
LuaDefine(table_sortedpairs, "table",
|
|
|
|
|
"|Iterate over table, sorting all keys"
|
|
|
|
|
"|"
|
|
|
|
|
"|Some keys can't be sorted. For example, you can use a closure"
|
|
|
|
|
"|as a table key. If you try to iterate over a table containing"
|
|
|
|
|
"|a non-sortable key, the error 'Cannot sort the table keys' will"
|
|
|
|
|
"|be generated."
|
|
|
|
|
"|"
|
|
|
|
|
"|See doc(genlt) for information about the sort order."
|
|
|
|
|
"|"
|
|
|
|
|
"|") {
|
2021-07-03 19:49:55 -04:00
|
|
|
LuaArg tab;
|
|
|
|
|
LuaRet closure, rtab, key;
|
2023-04-07 12:58:05 -04:00
|
|
|
LuaDefStack LS(L, tab, closure, rtab, key);
|
2021-09-08 01:32:08 -04:00
|
|
|
bool sorted = table_getpairs(LS, tab, rtab, true);
|
|
|
|
|
if (!sorted) {
|
2021-12-15 23:03:43 -05:00
|
|
|
luaL_error(L, "Cannot sort the table keys");
|
2021-07-03 19:49:55 -04:00
|
|
|
}
|
2021-09-08 01:32:08 -04:00
|
|
|
LS.set(closure, lfn_table_nextsortedpair);
|
|
|
|
|
LS.set(key, LuaNil);
|
|
|
|
|
return LS.result();
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-01 17:35:06 -05:00
|
|
|
LuaDefine(table_semisortedpairs, "table",
|
|
|
|
|
"|Iterate over table, sorting all the keys that can be sorted."
|
|
|
|
|
"|"
|
|
|
|
|
"|Some keys can't be sorted. For example, you can use a closure"
|
|
|
|
|
"|as a table key. If you try to iterate over a table containing"
|
|
|
|
|
"|a non-sortable key, the non-sortable elements will appear at"
|
|
|
|
|
"|the end of the iteration, after all the sortable elements. The"
|
|
|
|
|
"|non-sortable elements will be in an arbitrary order."
|
|
|
|
|
"|"
|
|
|
|
|
"|See doc(genlt) for information about the sort order."
|
|
|
|
|
"|") {
|
2021-09-08 01:32:08 -04:00
|
|
|
LuaArg tab;
|
|
|
|
|
LuaRet closure, rtab, key;
|
2023-04-07 12:58:05 -04:00
|
|
|
LuaDefStack LS(L, tab, closure, rtab, key);
|
2021-09-08 01:32:08 -04:00
|
|
|
table_getpairs(LS, tab, rtab, true);
|
2021-09-07 17:37:23 -04:00
|
|
|
LS.set(closure, lfn_table_nextsortedpair);
|
2021-07-03 19:49:55 -04:00
|
|
|
LS.set(key, LuaNil);
|
|
|
|
|
return LS.result();
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-01 17:35:06 -05:00
|
|
|
#define LUA_TNIL 0
|
|
|
|
|
#define LUA_TBOOLEAN 1
|
|
|
|
|
#define LUA_TLIGHTUSERDATA 2
|
|
|
|
|
#define LUA_TNUMBER 3
|
|
|
|
|
#define LUA_TSTRING 4
|
|
|
|
|
#define LUA_TTABLE 5
|
|
|
|
|
#define LUA_TFUNCTION 6
|
|
|
|
|
#define LUA_TUSERDATA 7
|
|
|
|
|
#define LUA_TTHREAD 8
|
|
|
|
|
|
|
|
|
|
#define LUA_NUMTAGS 9
|
|
|
|
|
|
|
|
|
|
LuaDefine(genlt, "obj1,obj2",
|
|
|
|
|
"|Generalized less-than function"
|
|
|
|
|
"|"
|
|
|
|
|
"|This comparison function can compare any two objects. The"
|
|
|
|
|
"|return value is as follows:"
|
|
|
|
|
"|"
|
|
|
|
|
"|* Numbers are compared in the obvious numeric manner."
|
|
|
|
|
"|* Strings are compared alphabetically."
|
|
|
|
|
"|* Booleans are compared with false being less than true."
|
|
|
|
|
"|* Tables are all considered equal to other tables."
|
|
|
|
|
"|* Functions are all considered equal to other functions."
|
|
|
|
|
"|* Coroutines are all considered equal to other coroutines."
|
|
|
|
|
"|"
|
|
|
|
|
"|* Numbers are less than strings."
|
|
|
|
|
"|* Strings are less than booleans."
|
|
|
|
|
"|* Booleans are less than functions."
|
|
|
|
|
"|* Functions are less than coroutines."
|
|
|
|
|
"|* Coroutines are less than tables."
|
|
|
|
|
"|") {
|
2021-07-03 19:49:55 -04:00
|
|
|
LuaArg o1,o2;
|
|
|
|
|
LuaRet lt;
|
2023-04-07 12:58:05 -04:00
|
|
|
LuaDefStack LS(L, o1, o2, lt);
|
2021-07-03 19:49:55 -04:00
|
|
|
int ltf = lua_genlt(L, o1.index(), o2.index());
|
|
|
|
|
LS.set(lt, ltf ? true:false);
|
2021-01-02 13:31:18 -05:00
|
|
|
return LS.result();
|
|
|
|
|
}
|