summaryrefslogtreecommitdiff
path: root/library/LuaWrapper.cpp
diff options
context:
space:
mode:
authorAlexander Gavrilov2012-03-28 15:28:42 +0800
committerPetr Mrázek2012-03-28 17:00:07 +0800
commit929657bed4e1300537a88401de9e3b14f2e1dc72 (patch)
treec9f6f8fe6a6a316eb61ca0ff5c74c04a92463611 /library/LuaWrapper.cpp
parentfe091de0b23791a7a76382e66b2c923edeea19cb (diff)
downloaddfhack-929657bed4e1300537a88401de9e3b14f2e1dc72.tar.gz
dfhack-929657bed4e1300537a88401de9e3b14f2e1dc72.tar.bz2
dfhack-929657bed4e1300537a88401de9e3b14f2e1dc72.tar.xz
Disable pointer auto-vivification unless new is specified.
Since it is essentially allocating non-gc managed objects, it can lead to memory leaks and shouldn't happen invisibly. Also support using the 'assign' key to request assign() from another object before processing the current map.
Diffstat (limited to 'library/LuaWrapper.cpp')
-rw-r--r--library/LuaWrapper.cpp58
1 files changed, 46 insertions, 12 deletions
diff --git a/library/LuaWrapper.cpp b/library/LuaWrapper.cpp
index 11db1487..36b24a40 100644
--- a/library/LuaWrapper.cpp
+++ b/library/LuaWrapper.cpp
@@ -616,20 +616,32 @@ static void invoke_resize(lua_State *state, int table, lua_Integer size)
lua_call(state, 2, 0);
}
-static void copy_table(lua_State *state, int dest, int src, int skipkey)
+static void copy_table(lua_State *state, int dest, int src, int skipbase)
{
+ // stack: (skipbase) skipkey skipkey |
+
+ int top = lua_gettop(state);
+
lua_pushnil(state);
while (lua_next(state, src))
{
- if (lua_equal(state, -2, skipkey))
- lua_pop(state, 1);
- else
+ for (int i = skipbase+1; i <= top; i++)
+ {
+ if (lua_rawequal(state, -2, i))
+ {
+ lua_pop(state, 1);
+ goto next_outer;
+ }
+ }
+
{
lua_pushvalue(state, -2);
lua_swap(state);
lua_settable(state, dest);
}
+
+ next_outer:;
}
}
@@ -655,18 +667,40 @@ static int meta_assign(lua_State *state)
{
type_identity *id = get_object_identity(state, 1, "df.assign()", false);
+ int base = lua_gettop(state);
+
+ // x:assign{ assign = foo } => x:assign(foo)
+ bool has_assign = false;
+
+ lua_pushstring(state, "assign");
+ lua_dup(state);
+ lua_rawget(state, 2);
+
+ if (!lua_isnil(state,-1))
+ {
+ has_assign = true;
+ lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_ASSIGN_NAME);
+ lua_pushvalue(state, 1);
+ lua_pushvalue(state, base+2);
+ lua_call(state, 2, 0);
+ }
+
+ lua_pop(state, 1);
+
+ // new is used by autovivification and should be skipped
+ lua_pushstring(state, "new");
+
if (id->isContainer())
{
+ // check resize field
lua_pushstring(state, "resize");
- int resize_str = lua_gettop(state);
-
lua_dup(state);
lua_rawget(state, 2);
- if (lua_isnil(state,-1))
+ if (lua_isnil(state,-1) && !has_assign)
{
/*
- * nil or missing resize field => 1-based lua array
+ * no assign && nil or missing resize field => 1-based lua array
*/
int size = lua_objlen(state, 2);
@@ -682,7 +716,7 @@ static int meta_assign(lua_State *state)
}
else
{
- if (lua_isboolean(state, -1))
+ if (lua_isboolean(state, -1) || lua_isnil(state, -1))
{
// resize=false => just assign
// resize=true => find the largest index
@@ -711,13 +745,13 @@ static int meta_assign(lua_State *state)
}
lua_pop(state, 1);
- copy_table(state, 1, 2, resize_str);
+ copy_table(state, 1, 2, base);
}
}
else
{
- lua_pushstring(state, "new");
- copy_table(state, 1, 2, lua_gettop(state));
+
+ copy_table(state, 1, 2, base);
}
}