Files
Foundry-VTT-Docker/resources/app/node_modules/peggy/lib/compiler/intern.js

78 lines
1.8 KiB
JavaScript
Raw Normal View History

2025-01-04 00:34:03 +01:00
// @ts-check
"use strict";
/**
* Intern strings or objects, so there is only one copy of each, by value.
* Objects may need to be converted to another representation before storing.
* Each inputs corresponds to a number, starting with 0.
*
* @template [T=string],[V=T]
*/
class Intern {
/**
* @typedef {object} InternOptions
* @property {(input: V) => string} [stringify=String] Represent the
* converted input as a string, for value comparison.
* @property {(input: T) => V} [convert=(x) => x] Convert the input to its
* stored form. Required if type V is not the same as type T. Return
* falsy value to have this input not be added; add() will return -1 in
* this case.
*/
/**
* @param {InternOptions} [options]
*/
constructor(options) {
/** @type {Required<InternOptions>} */
this.options = {
stringify: String,
convert: x => /** @type {V} */ (/** @type {unknown} */ (x)),
...options,
};
/** @type {V[]} */
this.items = [];
/** @type {Record<string, number>} */
this.offsets = {};
}
/**
* Intern an item, getting it's asssociated number. Returns -1 for falsy
* inputs. O(1) with constants tied to the convert and stringify options.
*
* @param {T} input
* @return {number}
*/
add(input) {
const c = this.options.convert(input);
if (!c) {
return -1;
}
const s = this.options.stringify(c);
let num = this.offsets[s];
if (num === undefined) {
num = this.items.push(c) - 1;
this.offsets[s] = num;
}
return num;
}
/**
* @param {number} i
* @returns {V}
*/
get(i) {
return this.items[i];
}
/**
* @template U
* @param {(value: V, index: number, array: V[]) => U} fn
* @returns {U[]}
*/
map(fn) {
return this.items.map(fn);
}
}
module.exports = Intern;