Do a lot of cleanup on module table/vector

This commit is contained in:
2023-04-13 16:55:48 -04:00
parent 7078d1243d
commit 8ea6c47e4c
4 changed files with 217 additions and 76 deletions

View File

@@ -459,6 +459,10 @@ int LuaCoreStack::rawlen(LuaSlot obj) const {
return lua_rawlen(L_, obj.index());
}
int LuaCoreStack::nkeys(LuaSlot obj) const {
return lua_nkeys(L_, obj.index());
}
int LuaCoreStack::gettabletype(LuaSlot tab) const {
uint16_t bits = lua_getflagbits(L_, tab.index());
return LUA_TT_GENERAL + (bits & 0x000F);

View File

@@ -410,6 +410,8 @@ public:
int rawlen(LuaSlot val) const;
int nkeys(LuaSlot tab) const;
int next(LuaSlot tab, LuaSlot key, LuaSlot value) const;
// Return true if the classname is legal.

View File

@@ -4,6 +4,24 @@
#include "table.hpp"
#include "source.hpp"
// A quick check to see if a table appears to be a vector.
// Does not thoroughly verify the vector. Returns the size
// of the vector.
static int check_vector_quick(LuaCoreStack &LS, LuaSlot vector, LuaSlot tmp) {
LS.checktable(vector, "vector");
int nkeys = LS.nkeys(vector);
if (nkeys > 0) {
LS.rawget(tmp, vector, nkeys);
if (LS.isnil(tmp)) {
luaL_error(LS.state(), "Not a valid vector");
}
LS.rawget(tmp, vector, nkeys + 1);
if (!LS.isnil(tmp)) {
luaL_error(LS.state(), "Not a valid vector");
}
}
return nkeys;
}
bool table_equal(LuaCoreStack &LS, LuaSlot t1, LuaSlot t2) {
lua_State *L = LS.state();
@@ -30,7 +48,11 @@ bool table_equal(LuaCoreStack &LS, LuaSlot t1, LuaSlot t2) {
return true;
}
LuaDefine(table_equal, "table1,table2", "return true if two tables contain the same keys and values") {
LuaDefine(table_equal, "table1,table2",
"|Return true if two tables contain the same keys and values."
"|"
"|This works on arbitrary tables. Metatables are ignored."
"|") {
LuaArg t1, t2;
LuaRet eql;
LuaDefStack LS(L, t1, t2, eql);
@@ -38,87 +60,179 @@ LuaDefine(table_equal, "table1,table2", "return true if two tables contain the s
return LS.result();
}
LuaDefine(table_findremove, "vector,value", "remove all occurrences of value from vector") {
luaL_checktype(L, -2, LUA_TTABLE);
int src = 1;
int dst = 1;
while (true) {
lua_pushinteger(L, src);
lua_rawget(L, -3);
if (lua_rawequal(L, -1, -2)) {
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++;
static int check_isvector(lua_State *L) {
LuaArg table;
LuaRet result;
LuaVar tmp;
LuaDefStack LS(L, table, result, tmp);
if (!LS.istable(table)) {
LS.set(result, false);
return LS.result();
}
int nkeys = lua_nkeys(L, table.index());
for (int i = 1; i <= nkeys; i++) {
LS.rawget(tmp, table, i);
if (LS.isnil(tmp)) {
LS.set(result, false);
return LS.result();
}
}
LS.set(result, true);
return LS.result();
}
LuaDefine(table_push, "vector,value", "push a value onto the end of a vector") {
luaL_checktype(L, -2, LUA_TTABLE);
int len = lua_rawlen(L, -2);
lua_pushinteger(L, len+1);
lua_pushvalue(L, -2);
lua_rawset(L, -4);
lua_pop(L, 2);
return 0;
LuaDefine(table_isvector, "table",
"|Return true if the table is a valid vector."
"|"
"|A vector is a table that has keys starting with 1, and no gaps."
"|The empty table also counts as a valid vector."
"|"
"|This function is identical to vector.isvector"
"|") {
return check_isvector(L);
}
LuaDefine(table_find, "vector,value", "find the first occurrence of value in vector") {
luaL_checktype(L, -2, LUA_TTABLE);
for (int i = 1; ; i++) {
lua_pushinteger(L, i);
lua_rawget(L, -3);
if (lua_rawequal(L, -1, -2)) {
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);
LuaDefine(vector_isvector, "table",
"|Return true if the table is a valid vector."
"|"
"|A vector is a table that has keys starting with 1, and no gaps."
"|The empty table also counts as a valid vector."
"|"
"|This function is identical to table.isvector"
"|") {
return check_isvector(L);
}
LuaDefine(vector_removeall, "vector,value",
"|Remove all occurrences of value from vector."
"|"
"|For example, if you remove the number 3 from the vector"
"|{1,2,3,4,5,4,3,2,1} you get {1,2,4,5,4,2,1}."
"|"
"|Returns true if it removed something, false otherwise."
"|") {
LuaArg vector, value;
LuaRet result;
LuaVar tmp;
LuaDefStack LS(L, vector, value, result, tmp);
int nkeys = check_vector_quick(LS, vector, tmp);
int dest = 1;
for (int i = 1; i <= nkeys; i++) {
LS.rawget(tmp, vector, i);
if (LS.isnil(tmp)) {
luaL_error(L, "not a valid vector");
return LS.result();
}
if (!LS.rawequal(tmp, value)) {
if (dest < i) {
LS.rawset(vector, dest, tmp);
}
dest += 1;
}
}
LS.set(result, (dest < nkeys));
while (dest <= nkeys) {
LS.rawset(vector, dest, LuaNil);
dest += 1;
}
return LS.result();
}
LuaDefine(table_empty, "table", "return true if the table has zero keys") {
LuaDefine(vector_push, "vector,value",
"|Push a value onto the end of a vector."
"|"
"|Argument must be a valid vector. Appends the value to"
"|the end of the vector."
"|") {
LuaArg vector, value;
LuaVar tmp;
LuaDefStack LS(L, vector, value, tmp);
int nkeys = check_vector_quick(LS, vector, tmp);
LS.rawset(vector, nkeys + 1, value);
return LS.result();
}
LuaDefine(vector_pop, "vector,value",
"|Pop a value from the end of a vector."
"|"
"|Argument must be a valid vector. Returns the last value"
"|from the vector. If the vector is empty, returns nil."
"|") {
LuaArg vector;
LuaRet value;
LuaVar tmp;
LuaDefStack LS(L, vector, value, tmp);
int nkeys = check_vector_quick(LS, vector, tmp);
if (nkeys == 0) {
LS.set(value, LuaNil);
} else {
LS.rawget(value, vector, nkeys);
LS.rawset(vector, nkeys, LuaNil);
}
return LS.result();
}
LuaDefine(vector_find, "vector,value",
"|Find the first occurence of value in vector."
"|"
"|Argument must be a valid vector. Returns the index of the"
"|first occurrence of value in vector. If the value is not"
"|found, returns nil."
"|"
"|Searching for 'nil' in a vector is explicitly disallowed, since"
"|a valid vector cannot contain nil."
"|") {
LuaArg vector, value;
LuaRet index;
LuaVar tmp;
LuaDefStack LS(L, vector, value, index, tmp);
int nkeys = check_vector_quick(LS, vector, tmp);
if (LS.isnil(value)) {
luaL_error(L, "cannot search for nil in a vector");
return 0;
}
for (int i = 1; i <= nkeys; i++) {
LS.rawget(tmp, vector, i);
if (LS.rawequal(tmp, value)) {
LS.set(index, i);
return LS.result();
}
}
LS.set(index, LuaNil);
return LS.result();
}
LuaDefine(table_empty, "table",
"|Return true if the table is empty."
"|"
"|Empty means the table has no key-value pairs stored."
"|Metatables and metavalues are ignored."
"|") {
luaL_checktype(L, -1, LUA_TTABLE);
int total = lua_nkeys(L, -1);
lua_pushboolean(L, (total == 0)?1:0);
return 1;
}
LuaDefine(table_count, "table", "return the number of keys in table") {
LuaDefine(table_count, "table",
"|Return the number of key-value pairs in the table."
"|"
"|Returns the number of key-value pairs that have been"
"|explicitly stored. Metatables and metavalues don't count."
"|") {
luaL_checktype(L, -1, LUA_TTABLE);
int total = lua_nkeys(L, -1);
lua_pushinteger(L, total);
return 1;
}
LuaDefine(table_clear, "table,metaflag", "clear all keys, and optionally the metatable") {
LuaDefine(table_clear, "table,metaflag",
"|Clear the table key-value pairs, and optionally the metatable"
"|"
"|This removes all key-value pairs from the table. If the metaflag"
"|is set, it also removes the metatable. If you try to clear the"
"|metatable when the metatable is locked, this will throw an error."
"|") {
LuaArg tab, clearmeta;
LuaVar metatable, metafield;
LuaDefStack LS(L, tab, clearmeta, metatable, metafield);