Perf: a few improvements to trie

This commit is contained in:
SukkaW 2024-09-18 14:05:07 +08:00
parent a004ffb960
commit 3bd0ebe36e
2 changed files with 31 additions and 29 deletions

View File

@ -160,11 +160,11 @@ const processRuleSet = (ruleSet: string[]) => {
} }
} }
const dumped = trie.dumpWithMeta(); const dumped = trie.dumpMeta();
for (let i = 0, len = dumped.length; i < len; i++) { for (let i = 0, len = dumped.length; i < len; i++) {
const originalIndex = unpackFirst(dumped[i][1]); const originalIndex = unpackFirst(dumped[i]);
const flag = unpackSecond(dumped[i][1]); const flag = unpackSecond(dumped[i]);
const type = flag === flagDomain ? 'DOMAIN' : 'DOMAIN-SUFFIX'; const type = flag === flagDomain ? 'DOMAIN' : 'DOMAIN-SUFFIX';

View File

@ -63,7 +63,7 @@ const walkHostnameTokens = (hostname: string, onToken: (token: string) => boolea
const l = tokens.length - 1; const l = tokens.length - 1;
for (let i = l; i >= 0; i--) { for (let i = l; i >= 0; i--) {
if ( if (
i < l i < l // when i === l, we are at the first of hostname, no splitor there
// when onToken returns true, we should skip the rest of the loop // when onToken returns true, we should skip the rest of the loop
&& onToken('.') && onToken('.')
) { ) {
@ -304,7 +304,10 @@ export const createTrie = <Meta = any>(from?: string[] | Set<string> | null, smo
/** /**
* Method used to retrieve every item in the trie with the given prefix. * Method used to retrieve every item in the trie with the given prefix.
*/ */
const find = (inputSuffix: string, /** @default true */ includeEqualWithSuffix = true): string[] => { const find = (
inputSuffix: string,
/** @default true */ includeEqualWithSuffix = true
): string[] => {
if (smolTree) { if (smolTree) {
throw new Error('A Trie with smolTree enabled cannot perform find!'); throw new Error('A Trie with smolTree enabled cannot perform find!');
} }
@ -316,9 +319,11 @@ export const createTrie = <Meta = any>(from?: string[] | Set<string> | null, smo
const matches: string[][] = []; const matches: string[][] = [];
const onMatches = includeEqualWithSuffix const onMatches = includeEqualWithSuffix
// fast path (default option)
? (suffix: string[]) => matches.push(suffix) ? (suffix: string[]) => matches.push(suffix)
// slow path
: (suffix: string[]) => { : (suffix: string[]) => {
if (suffix.some((t, i) => t !== inputTokens[i])) { if (!deepEqualArray(suffix, inputTokens)) {
matches.push(suffix); matches.push(suffix);
} }
}; };
@ -332,28 +337,6 @@ export const createTrie = <Meta = any>(from?: string[] | Set<string> | null, smo
return matches.map((m) => fastStringArrayJoin(m, '')); return matches.map((m) => fastStringArrayJoin(m, ''));
}; };
/**
* Works like trie.find, but instead of returning the matches as an array, it removes them from the given set in-place.
*/
const substractSetInPlaceFromFound = (inputSuffix: string, set: Set<string>) => {
if (smolTree) {
throw new Error('A Trie with smolTree enabled cannot perform substractSetInPlaceFromFound!');
}
const inputTokens = hostnameToTokens(inputSuffix);
const res = walkIntoLeafWithTokens(inputTokens);
if (res === null) return;
const onMatches = (suffix: string[]) => set.delete(fastStringArrayJoin(suffix, ''));
walk(
onMatches,
res.node, // Performing DFS from prefix
inputTokens
);
};
/** /**
* Method used to delete a prefix from the trie. * Method used to delete a prefix from the trie.
*/ */
@ -396,6 +379,16 @@ export const createTrie = <Meta = any>(from?: string[] | Set<string> | null, smo
return results; return results;
}; };
const dumpMeta = () => {
const results: Meta[] = [];
walk((suffix, meta) => {
results.push(meta);
});
return results;
};
const dumpWithMeta = () => { const dumpWithMeta = () => {
const results: Array<[string, Meta]> = []; const results: Array<[string, Meta]> = [];
@ -463,11 +456,11 @@ export const createTrie = <Meta = any>(from?: string[] | Set<string> | null, smo
add, add,
contains, contains,
find, find,
substractSetInPlaceFromFound,
remove, remove,
delete: remove, delete: remove,
has, has,
dump, dump,
dumpMeta,
dumpWithMeta, dumpWithMeta,
get size() { get size() {
if (smolTree) { if (smolTree) {
@ -486,3 +479,12 @@ export const createTrie = <Meta = any>(from?: string[] | Set<string> | null, smo
}; };
export type Trie = ReturnType<typeof createTrie>; export type Trie = ReturnType<typeof createTrie>;
function deepEqualArray(a: string[], b: string[]) {
let len = a.length;
if (len !== b.length) return false;
while (len--) {
if (a[len] !== b[len]) return false;
}
return true;
};