You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
82 lines
2.6 KiB
82 lines
2.6 KiB
5 months ago
|
// A [trie](https://en.wikipedia.org/wiki/Trie) data structure that holds
|
||
|
// object keys weakly, yet can also hold non-object keys, unlike the
|
||
|
// native `WeakMap`.
|
||
|
// If no makeData function is supplied, the looked-up data will be an empty,
|
||
|
// null-prototype Object.
|
||
|
const defaultMakeData = () => Object.create(null);
|
||
|
// Useful for processing arguments objects as well as arrays.
|
||
|
const { forEach, slice } = Array.prototype;
|
||
|
const { hasOwnProperty } = Object.prototype;
|
||
|
export class Trie {
|
||
|
constructor(weakness = true, makeData = defaultMakeData) {
|
||
|
this.weakness = weakness;
|
||
|
this.makeData = makeData;
|
||
|
}
|
||
|
lookup() {
|
||
|
return this.lookupArray(arguments);
|
||
|
}
|
||
|
lookupArray(array) {
|
||
|
let node = this;
|
||
|
forEach.call(array, key => node = node.getChildTrie(key));
|
||
|
return hasOwnProperty.call(node, "data")
|
||
|
? node.data
|
||
|
: node.data = this.makeData(slice.call(array));
|
||
|
}
|
||
|
peek() {
|
||
|
return this.peekArray(arguments);
|
||
|
}
|
||
|
peekArray(array) {
|
||
|
let node = this;
|
||
|
for (let i = 0, len = array.length; node && i < len; ++i) {
|
||
|
const map = node.mapFor(array[i], false);
|
||
|
node = map && map.get(array[i]);
|
||
|
}
|
||
|
return node && node.data;
|
||
|
}
|
||
|
remove() {
|
||
|
return this.removeArray(arguments);
|
||
|
}
|
||
|
removeArray(array) {
|
||
|
let data;
|
||
|
if (array.length) {
|
||
|
const head = array[0];
|
||
|
const map = this.mapFor(head, false);
|
||
|
const child = map && map.get(head);
|
||
|
if (child) {
|
||
|
data = child.removeArray(slice.call(array, 1));
|
||
|
if (!child.data && !child.weak && !(child.strong && child.strong.size)) {
|
||
|
map.delete(head);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
data = this.data;
|
||
|
delete this.data;
|
||
|
}
|
||
|
return data;
|
||
|
}
|
||
|
getChildTrie(key) {
|
||
|
const map = this.mapFor(key, true);
|
||
|
let child = map.get(key);
|
||
|
if (!child)
|
||
|
map.set(key, child = new Trie(this.weakness, this.makeData));
|
||
|
return child;
|
||
|
}
|
||
|
mapFor(key, create) {
|
||
|
return this.weakness && isObjRef(key)
|
||
|
? this.weak || (create ? this.weak = new WeakMap : void 0)
|
||
|
: this.strong || (create ? this.strong = new Map : void 0);
|
||
|
}
|
||
|
}
|
||
|
function isObjRef(value) {
|
||
|
switch (typeof value) {
|
||
|
case "object":
|
||
|
if (value === null)
|
||
|
break;
|
||
|
// Fall through to return true...
|
||
|
case "function":
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
//# sourceMappingURL=index.js.map
|