/*jshint esversion: 6 */ "use strict"; const assert = require('assert'); const defs = require('./defs.js'); const ldebug = require('./ldebug.js'); const lobject = require('./lobject.js'); const lstring = require('./lstring.js'); const CT = defs.constant_types; const table_hash = function(key) { switch(key.type) { case CT.LUA_TBOOLEAN: case CT.LUA_TLIGHTUSERDATA: /* XXX: if user pushes conflicting lightuserdata then the table will do odd things */ case CT.LUA_TNUMFLT: case CT.LUA_TNUMINT: case CT.LUA_TTABLE: case CT.LUA_TLCL: case CT.LUA_TLCF: case CT.LUA_TCCL: case CT.LUA_TUSERDATA: case CT.LUA_TTHREAD: return key.value; case CT.LUA_TSHRSTR: case CT.LUA_TLNGSTR: return lstring.luaS_hashlongstr(key.tsvalue()); default: throw new Error("unknown key type: " + key.type); } }; class Table { constructor(L) { this.id = L.l_G.id_counter++; this.strong = new Map(); this.dead_hashes = []; this.f = void 0; /* first entry */ this.l = void 0; /* last entry */ this.metatable = null; } } const add = function(t, hash, key, value) { clean_dead_keys(t); let prev; let entry = { key: key, value: value, p: prev = t.l, n: void 0 }; if (!t.f) t.f = entry; if (prev) prev.n = entry; t.strong.set(hash, entry); t.l = entry; }; const remove = function(t, hash) { let entry = t.strong.get(hash); if (entry) { let next = entry.n; let prev = entry.p; if(prev) prev.n = next; if(next) next.p = prev; if(t.f === entry) t.f = next; if(t.l === entry) t.l = prev; t.strong.delete(hash); } }; /* Can't remove from table immediately due to next() */ const mark_dead = 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 clean_dead_keys = function(t) { for (let i=0; i 1) { let m = Math.floor((i+j)/2); if (luaH_getint(t, m).ttisnil()) j = m; else i = m; } return i; }; const luaH_next = function(L, table, keyI) { let keyO = L.stack[keyI]; let entry; if (keyO.type === CT.LUA_TNIL) { entry = table.f; } else { /* First find current key */ let hash = table_hash(keyO); entry = table.strong.get(hash); if (!entry) /* item not in table */ return ldebug.luaG_runerror(L, defs.to_luastring("invalid key to 'next'")) entry = entry.n; } /* Iterate until either out of keys, or until finding a non-dead key */ while (1) { if (!entry) return false; if (!entry.key.ttisdeadkey()) break; entry = entry.n; } L.stack[keyI] = new lobject.TValue(entry.key.type, entry.key.value); L.stack[keyI+1] = new lobject.TValue(entry.value.type, entry.value.value); return true; }; module.exports.luaH_delete = luaH_delete; module.exports.luaH_get = luaH_get; module.exports.luaH_getint = luaH_getint; module.exports.luaH_getn = luaH_getn; module.exports.luaH_getstr = luaH_getstr; module.exports.luaH_set = luaH_set; module.exports.luaH_setint = luaH_setint; module.exports.luaH_new = luaH_new; module.exports.luaH_next = luaH_next;