<commit_before>/*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.metatable = null;
    }
}

const luaH_new = function(L) {
    return new Table(L);
};

const getgeneric = function(t, hash) {
    let v = t.strong.get(hash);
    return v ? v.value : lobject.luaO_nilobject;
};

const luaH_getint = function(t, key) {
    assert(typeof key == "number" && (key|0) === key);
    return getgeneric(t, key);
};

const luaH_getstr = function(t, key) {
    assert(key instanceof lstring.TString);
    return getgeneric(t, lstring.luaS_hashlongstr(key));
};

const luaH_get = function(t, key) {
    assert(key instanceof lobject.TValue);
    if (key.ttisnil())
        return lobject.luaO_nilobject;
    return getgeneric(t, table_hash(key));
};

const setgeneric = function(t, hash, key) {
    let v = t.strong.get(hash);
    if (v)
        return v.value;

    let tv = new lobject.TValue(CT.LUA_TNIL, null);
    t.strong.set(hash, {
        key: key,
        value: tv
    });
    return tv;
};

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);
        return;
    }
    let v = t.strong.get(hash);
    if (v) {
        let tv = v.value;
        tv.setfrom(value);
    } else {
        t.strong.set(hash, {
            key: new lobject.TValue(CT.LUA_TNUMINT, key),
            value: new lobject.TValue(value.type, value.value)
        });
    }
};

const luaH_set = function(t, key) {
    assert(key instanceof lobject.TValue);
    let hash = table_hash(key);
    return setgeneric(t, hash, new lobject.TValue(key.type, key.value));
};

const luaH_delete = function(t, key) {
    assert(key instanceof lobject.TValue);
    let hash = table_hash(key);
    t.strong.delete(hash);
};

/*
** Try to find a boundary in table 't'. A 'boundary' is an integer index
** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil).
*/
const luaH_getn = function(t) {
    let i = 0;
    let j = t.strong.size + 1; /* use known size of Map to bound search */
    /* now do a binary search between them */
    while (j - i > 1) {
        let m = Math.floor((i+j)/2);<commit_msg>src/ltable.js: luaH_delete can't fully delete immediately as it might need dead keys for next()<commit_after>/*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.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);
};

const getgeneric = function(t, hash) {
    let v = t.strong.get(hash);
    return v ? v.value : lobject.luaO_nilobject;
};

const luaH_getint = function(t, key) {
    assert(typeof key == "number" && (key|0) === key);
    return getgeneric(t, key);
};

const luaH_getstr = function(t, key) {
    assert(key instanceof lstring.TString);
    return getgeneric(t, lstring.luaS_hashlongstr(key));
};

const luaH_get = function(t, key) {
    assert(key instanceof lobject.TValue);
    if (key.ttisnil())
        return lobject.luaO_nilobject;
    return getgeneric(t, table_hash(key));
};

const setgeneric = function(t, hash, key) {
    let v = t.strong.get(hash);
    if (v)
        return v.value;

    clean_dead_keys(t);
    let tv = new lobject.TValue(CT.LUA_TNIL, null);
    t.strong.set(hash, {
        key: key,
        value: tv
    });
    return tv;
};

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()) {
        delete_hash(t, hash);
        return;
    }
    let v = t.strong.get(hash);
    if (v) {
        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)
        });
    }
};

const luaH_set = function(t, key) {
    assert(key instanceof lobject.TValue);
    let hash = table_hash(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 = lobject.luaO_nilobject;
        t.dead_hashes.push(hash);
    }
};

const luaH_delete = function(t, key) {
    assert(key instanceof lobject.TValue);
    let hash = table_hash(key);
    return delete_hash(t, hash);
};

/*
** Try to find a boundary in table 't'. A 'boundary' is an integer index
** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil).
*/
const luaH_getn = function(t) {
    let i = 0;
    let j = t.strong.size + 1; /* use known size of Map to bound search */
    /* now do a binary search between them */
    while (j - i > 1) {
        let m = Math.floor((i+j)/2);
{'fraction_non_alphanumeric': 0.1418348361242307, 'fraction_numerical': 0.0030055817947617003, 'mean_word_length': 2.6973544973544974, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5471656', 'n_tokens_mistral': 2534, 'n_tokens_neox': 2498, 'n_words': 632}