Do a lot of cleanup on module table/vector
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user