197 lines
6.8 KiB
JavaScript
197 lines
6.8 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.print = exports.toRecord = exports.remove = exports.findWithParents = exports.find = exports.insert = void 0;
|
|
const printTree_1 = require("../print/printTree");
|
|
const TrieNode_1 = require("../trie/TrieNode");
|
|
const util_1 = require("../util");
|
|
const stringify = JSON.stringify;
|
|
const getCommonPrefixLength = (a, b) => {
|
|
const len = Math.min(a.length, b.length);
|
|
let i = 0;
|
|
for (; i < len && a[i] === b[i]; i++)
|
|
;
|
|
return i;
|
|
};
|
|
const insert = (root, path, value) => {
|
|
let curr = root;
|
|
let k = path;
|
|
main: while (curr) {
|
|
let child = curr.children;
|
|
if (!child) {
|
|
curr.children = new TrieNode_1.TrieNode(k, value);
|
|
return 1;
|
|
}
|
|
const char = k[0];
|
|
let prevChild = undefined;
|
|
let cmp = false;
|
|
child: while (child) {
|
|
prevChild = child;
|
|
const childChar = child.k[0];
|
|
if (childChar === char) {
|
|
const commonPrefixLength = getCommonPrefixLength(child.k, k);
|
|
const isChildKContained = commonPrefixLength === child.k.length;
|
|
const isKContained = commonPrefixLength === k.length;
|
|
const areKeysEqual = isChildKContained && isKContained;
|
|
if (areKeysEqual) {
|
|
child.v = value;
|
|
return 0;
|
|
}
|
|
if (isChildKContained) {
|
|
k = k.substring(commonPrefixLength);
|
|
curr = child;
|
|
continue main;
|
|
}
|
|
if (isKContained) {
|
|
const newChild = new TrieNode_1.TrieNode(child.k.substring(commonPrefixLength), child.v);
|
|
newChild.children = child.children;
|
|
child.k = k.substring(0, commonPrefixLength);
|
|
child.v = value;
|
|
child.children = newChild;
|
|
return 1;
|
|
}
|
|
if (commonPrefixLength) {
|
|
const newChild = new TrieNode_1.TrieNode(child.k.substring(commonPrefixLength), child.v);
|
|
newChild.children = child.children;
|
|
child.k = child.k.substring(0, commonPrefixLength);
|
|
child.v = undefined;
|
|
child.children = newChild;
|
|
curr = child;
|
|
k = k.substring(commonPrefixLength);
|
|
continue main;
|
|
}
|
|
}
|
|
cmp = childChar > char;
|
|
if (cmp)
|
|
child = child.l;
|
|
else
|
|
child = child.r;
|
|
}
|
|
if (prevChild) {
|
|
const node = new TrieNode_1.TrieNode(k, value);
|
|
if (cmp)
|
|
(0, util_1.insertLeft)(node, prevChild);
|
|
else
|
|
(0, util_1.insertRight)(node, prevChild);
|
|
return 1;
|
|
}
|
|
break;
|
|
}
|
|
return 0;
|
|
};
|
|
exports.insert = insert;
|
|
const find = (node, key) => {
|
|
if (!key)
|
|
return node;
|
|
const len = key.length;
|
|
let offset = 0;
|
|
while (node) {
|
|
const child = (0, util_1.findOrNextLower)(node.children, key[offset], (cmp1, cmp2) => cmp1[0] > cmp2[0] ? 1 : -1);
|
|
if (!child)
|
|
return undefined;
|
|
const childKey = child.k;
|
|
const childKeyLength = childKey.length;
|
|
let commonPrefixLength = 0;
|
|
const limit = Math.min(childKeyLength, len - offset);
|
|
for (; commonPrefixLength < limit && childKey[commonPrefixLength] === key[offset + commonPrefixLength]; commonPrefixLength++)
|
|
;
|
|
if (!commonPrefixLength)
|
|
return undefined;
|
|
offset += commonPrefixLength;
|
|
if (offset === len)
|
|
return child;
|
|
if (commonPrefixLength < childKeyLength)
|
|
return undefined;
|
|
node = child;
|
|
}
|
|
return undefined;
|
|
};
|
|
exports.find = find;
|
|
const findWithParents = (node, key) => {
|
|
if (!key)
|
|
return undefined;
|
|
const list = [node];
|
|
const len = key.length;
|
|
let offset = 0;
|
|
while (node) {
|
|
const child = (0, util_1.findOrNextLower)(node.children, key[offset], (cmp1, cmp2) => cmp1[0] > cmp2[0] ? 1 : -1);
|
|
if (!child)
|
|
return undefined;
|
|
const childKey = child.k;
|
|
const childKeyLength = childKey.length;
|
|
let commonPrefixLength = 0;
|
|
const limit = Math.min(childKeyLength, len - offset);
|
|
for (; commonPrefixLength < limit && childKey[commonPrefixLength] === key[offset + commonPrefixLength]; commonPrefixLength++)
|
|
;
|
|
if (!commonPrefixLength)
|
|
return undefined;
|
|
offset += commonPrefixLength;
|
|
if (commonPrefixLength < childKeyLength)
|
|
return undefined;
|
|
list.push(child);
|
|
if (offset === len)
|
|
return list;
|
|
node = child;
|
|
}
|
|
return undefined;
|
|
};
|
|
exports.findWithParents = findWithParents;
|
|
const remove = (root, key) => {
|
|
if (!key) {
|
|
const deleted = root.v !== undefined;
|
|
root.v = undefined;
|
|
return deleted;
|
|
}
|
|
const list = (0, exports.findWithParents)(root, key);
|
|
if (!list)
|
|
return false;
|
|
const length = list.length;
|
|
const lastIndex = length - 1;
|
|
const last = list[lastIndex];
|
|
const deleted = last.v !== undefined;
|
|
last.v = undefined;
|
|
for (let i = lastIndex; i >= 1; i--) {
|
|
const child = list[i];
|
|
const parent = list[i - 1];
|
|
if (child.v || child.children)
|
|
break;
|
|
parent.children = (0, util_1.remove)(parent.children, child);
|
|
}
|
|
return deleted;
|
|
};
|
|
exports.remove = remove;
|
|
const toRecord = (node, prefix = '', record = {}) => {
|
|
if (!node)
|
|
return record;
|
|
prefix += node.k;
|
|
if (node.v !== undefined)
|
|
record[prefix] = node.v;
|
|
let child = (0, util_1.first)(node.children);
|
|
if (!child)
|
|
return record;
|
|
do
|
|
(0, exports.toRecord)(child, prefix, record);
|
|
while ((child = (0, util_1.next)(child)));
|
|
return record;
|
|
};
|
|
exports.toRecord = toRecord;
|
|
const print = (node, tab = '') => {
|
|
const detailedPrint = node.v && typeof node.v === 'object' && node.v.constructor !== Object;
|
|
const value = node.v && typeof node.v === 'object'
|
|
? Array.isArray(node.v)
|
|
? stringify(node.v)
|
|
: node.v.constructor === Object
|
|
? stringify(node.v)
|
|
: ''
|
|
: node.v === undefined
|
|
? ''
|
|
: stringify(node.v);
|
|
const childrenNodes = [];
|
|
node.forChildren((child) => childrenNodes.push(child));
|
|
return (`${node.constructor.name} ${JSON.stringify(node.k)}${value ? ' = ' + value : ''}` +
|
|
(0, printTree_1.printTree)(tab, [
|
|
!detailedPrint ? null : (tab) => node.v.toString(tab),
|
|
...childrenNodes.map((child) => (tab) => (0, exports.print)(child, tab)),
|
|
]));
|
|
};
|
|
exports.print = print;
|