summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lobject.js12
-rw-r--r--src/ltable.js23
-rw-r--r--tests/ltablib.js10
3 files changed, 37 insertions, 8 deletions
diff --git a/src/lobject.js b/src/lobject.js
index e4ef380..f926e85 100644
--- a/src/lobject.js
+++ b/src/lobject.js
@@ -13,6 +13,8 @@ const llimit = require('./llimit.js');
const CT = defs.constant_types;
const char = defs.char;
+const LUA_TPROTO = CT.LUA_NUMTAGS;
+const LUA_TDEADKEY = CT.LUA_NUMTAGS+1;
class TValue {
@@ -108,7 +110,7 @@ class TValue {
}
ttisdeadkey() {
- return this.checktag(CT.LUA_TDEADKEY);
+ return this.checktag(LUA_TDEADKEY);
}
l_isfalse() {
@@ -150,6 +152,11 @@ class TValue {
this.value = x;
}
+ setdeadvalue() {
+ this.type = LUA_TDEADKEY;
+ this.value = null;
+ }
+
setfrom(tv) { /* in lua C source setobj2t is often used for this */
this.type = tv.type;
this.value = tv.value;
@@ -175,6 +182,7 @@ class TValue {
}
const luaO_nilobject = new TValue(CT.LUA_TNIL, null);
+Object.freeze(luaO_nilobject);
module.exports.luaO_nilobject = luaO_nilobject;
class LClosure {
@@ -539,6 +547,8 @@ const numarith = function(L, op, v1, v2) {
}
};
+module.exports.LUA_TPROTO = LUA_TPROTO;
+module.exports.LUA_TDEADKEY = LUA_TDEADKEY;
module.exports.CClosure = CClosure;
module.exports.LClosure = LClosure;
module.exports.LocVar = LocVar;
diff --git a/src/ltable.js b/src/ltable.js
index ce3ba77..0619efe 100644
--- a/src/ltable.js
+++ b/src/ltable.js
@@ -34,10 +34,17 @@ class Table {
constructor(L) {
this.id = L.l_G.id_counter++;
this.strong = new Map();
+ this.dead_hashes = [];
this.metatable = null;
}
}
+const clean_dead_keys = function(t) {
+ for (let i=0; i<t.dead_hashes.length; i++) {
+ t.strong.delete(t.dead_hashes[i]);
+ }
+};
+
const luaH_new = function(L) {
return new Table(L);
};
@@ -69,6 +76,7 @@ const setgeneric = function(t, hash, key) {
if (v)
return v.value;
+ clean_dead_keys(t);
let tv = new lobject.TValue(CT.LUA_TNIL, null);
t.strong.set(hash, {
key: key,
@@ -81,7 +89,7 @@ const luaH_setint = function(t, key, value) {
assert(typeof key == "number" && (key|0) === key && value instanceof lobject.TValue);
let hash = key; /* table_hash known result */
if (value.ttisnil()) {
- t.strong.delete(hash);
+ delete_hash(t, hash);
return;
}
let v = t.strong.get(hash);
@@ -89,6 +97,7 @@ const luaH_setint = function(t, key, value) {
let tv = v.value;
tv.setfrom(value);
} else {
+ clean_dead_keys(t);
t.strong.set(hash, {
key: new lobject.TValue(CT.LUA_TNUMINT, key),
value: new lobject.TValue(value.type, value.value)
@@ -102,10 +111,20 @@ const luaH_set = function(t, key) {
return setgeneric(t, hash, new lobject.TValue(key.type, key.value));
};
+/* Can't remove from table immediately due to next() */
+const delete_hash = function(t, hash) {
+ let e = t.strong.get(hash);
+ if (e) {
+ e.key.setdeadvalue();
+ e.value = new lobject.TValue(CT.LUA_TNIL, null);
+ t.dead_hashes.push(hash);
+ }
+};
+
const luaH_delete = function(t, key) {
assert(key instanceof lobject.TValue);
let hash = table_hash(key);
- t.strong.delete(hash);
+ return delete_hash(t, hash);
};
/*
diff --git a/tests/ltablib.js b/tests/ltablib.js
index e209db3..43e742b 100644
--- a/tests/ltablib.js
+++ b/tests/ltablib.js
@@ -14,7 +14,7 @@ const inttable2array = function(t) {
let a = [];
t.strong.forEach(function (v, k) {
- if (typeof k === 'number')
+ if (v.key.ttisnumber())
a[k - 1] = v.value;
});
@@ -73,7 +73,7 @@ test('table.pack', function (t) {
t.deepEqual(
[...lua.lua_topointer(L, -1).strong.entries()]
- .filter(e => typeof e[0] === 'number') // Filter out the 'n' field
+ .filter(e => e[1].key.ttisnumber()) // Filter out the 'n' field
.map(e => e[1].value.value).reverse(),
[1, 2, 3],
"Correct element(s) on the stack"
@@ -148,7 +148,7 @@ test('table.insert', function (t) {
t.deepEqual(
[...lua.lua_topointer(L, -1).strong.entries()]
- .filter(e => typeof e[0] === 'number')
+ .filter(e => e[1].key.ttisnumber())
.map(e => e[1].value.value).sort(),
[1, 2, 3, 4, 5],
"Correct element(s) on the stack"
@@ -182,7 +182,7 @@ test('table.remove', function (t) {
t.deepEqual(
[...lua.lua_topointer(L, -1).strong.entries()]
- .filter(e => typeof e[0] === 'number')
+ .filter(e => e[1].key.ttisnumber())
.map(e => e[1].value.value).sort(),
[1, 2, 3, 4],
"Correct element(s) on the stack"
@@ -215,7 +215,7 @@ test('table.move', function (t) {
t.deepEqual(
[...lua.lua_topointer(L, -1).strong.entries()]
- .filter(e => typeof e[0] === 'number')
+ .filter(e => e[1].key.ttisnumber())
.map(e => e[1].value.value).sort(),
[1, 2, 3, 4, 5, 6],
"Correct element(s) on the stack"