mirror of
https://github.com/SukkaW/Surge.git
synced 2025-12-13 09:40:34 +08:00
Perf: strip more branches
This commit is contained in:
parent
e6e6c23495
commit
64317794b0
@ -13,10 +13,11 @@ const START = 1 << 1;
|
||||
const INCLUDE_ALL_SUBDOMAIN = 1 << 2;
|
||||
|
||||
type TrieNode<Meta = any> = [
|
||||
flag: number, /** end, includeAllSubdomain (.example.org, ||example.com) */
|
||||
TrieNode | null, /** parent */
|
||||
Map<string, TrieNode>, /** children */
|
||||
Meta /** meta */
|
||||
/** end, includeAllSubdomain (.example.org, ||example.com) */ flag: number,
|
||||
/** parent */ TrieNode | null,
|
||||
/** children */ Map<string, TrieNode>,
|
||||
/** token */ token: string,
|
||||
/** meta */ Meta
|
||||
];
|
||||
|
||||
function deepTrieNodeToJSON<Meta = unknown>(node: TrieNode,
|
||||
@ -25,11 +26,11 @@ function deepTrieNodeToJSON<Meta = unknown>(node: TrieNode,
|
||||
|
||||
obj['[start]'] = getBit(node[0], START);
|
||||
obj['[subdomain]'] = getBit(node[0], INCLUDE_ALL_SUBDOMAIN);
|
||||
if (node[3] != null) {
|
||||
if (node[4] != null) {
|
||||
if (unpackMeta) {
|
||||
obj['[meta]'] = unpackMeta(node[3]);
|
||||
obj['[meta]'] = unpackMeta(node[4]);
|
||||
} else {
|
||||
obj['[meta]'] = node[3];
|
||||
obj['[meta]'] = node[4];
|
||||
}
|
||||
}
|
||||
node[2].forEach((value, key) => {
|
||||
@ -38,7 +39,7 @@ function deepTrieNodeToJSON<Meta = unknown>(node: TrieNode,
|
||||
return obj;
|
||||
}
|
||||
|
||||
const createNode = <Meta = unknown>(parent: TrieNode | null = null): TrieNode => [1, parent, new Map<string, TrieNode>(), null] as TrieNode<Meta>;
|
||||
const createNode = <Meta = unknown>(token: string, parent: TrieNode | null = null): TrieNode => [1, parent, new Map<string, TrieNode>(), token, null] as TrieNode<Meta>;
|
||||
|
||||
function hostnameToTokens(hostname: string, hostnameFromIndex: number): string[] {
|
||||
const tokens = hostname.split('.');
|
||||
@ -90,7 +91,7 @@ interface FindSingleChildLeafResult<Meta> {
|
||||
}
|
||||
|
||||
abstract class Triebase<Meta = unknown> {
|
||||
protected readonly $root: TrieNode<Meta> = createNode();
|
||||
protected readonly $root: TrieNode<Meta> = createNode('$root');
|
||||
protected $size = 0;
|
||||
|
||||
get root() {
|
||||
@ -259,7 +260,7 @@ abstract class Triebase<Meta = unknown> {
|
||||
|
||||
// If the node is a sentinel, we push the suffix to the results
|
||||
if (getBit(node[0], START)) {
|
||||
onMatches(suffix, getBit(node[0], INCLUDE_ALL_SUBDOMAIN), node[3]);
|
||||
onMatches(suffix, getBit(node[0], INCLUDE_ALL_SUBDOMAIN), node[4]);
|
||||
}
|
||||
} while (nodeStack.length);
|
||||
};
|
||||
@ -303,7 +304,7 @@ abstract class Triebase<Meta = unknown> {
|
||||
|
||||
// If the node is a sentinel, we push the suffix to the results
|
||||
if (getBit(node[0], START)) {
|
||||
onMatches(suffix, getBit(node[0], INCLUDE_ALL_SUBDOMAIN), node[3]);
|
||||
onMatches(suffix, getBit(node[0], INCLUDE_ALL_SUBDOMAIN), node[4]);
|
||||
}
|
||||
} while (nodeStack.length);
|
||||
};
|
||||
@ -317,19 +318,16 @@ abstract class Triebase<Meta = unknown> {
|
||||
|
||||
const child = node[2];
|
||||
|
||||
// console.log({
|
||||
// child, parent, token
|
||||
// });
|
||||
// console.log(this.inspect(0));
|
||||
const childSize = child.size + (getBit(node[0], INCLUDE_ALL_SUBDOMAIN) ? 1 : 0);
|
||||
|
||||
if (toPrune !== null) { // the most near branch that could potentially being pruned
|
||||
if (child.size > 1) {
|
||||
if (childSize >= 1) {
|
||||
// The branch has some children, the branch need retain.
|
||||
// And we need to abort prune that parent branch, so we set it to null
|
||||
toPrune = null;
|
||||
tokenToPrune = null;
|
||||
}
|
||||
} else if (child.size < 1) {
|
||||
} else if (childSize < 1) {
|
||||
// There is only one token child, or no child at all, we can prune it safely
|
||||
// It is now the top-est branch that could potentially being pruned
|
||||
toPrune = parent;
|
||||
@ -534,7 +532,7 @@ export class HostnameSmolTrie<Meta = unknown> extends Triebase<Meta> {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
const newNode = createNode(node);
|
||||
const newNode = createNode(token, node);
|
||||
curNodeChildren.set(token, newNode);
|
||||
node = newNode;
|
||||
}
|
||||
@ -571,7 +569,7 @@ export class HostnameSmolTrie<Meta = unknown> extends Triebase<Meta> {
|
||||
} else {
|
||||
node[0] = deleteBit(node[0], INCLUDE_ALL_SUBDOMAIN);
|
||||
}
|
||||
node[3] = meta!;
|
||||
node[4] = meta!;
|
||||
}
|
||||
|
||||
public whitelist(suffix: string, includeAllSubdomain = suffix[0] === '.', hostnameFromIndex = suffix[0] === '.' ? 1 : 0) {
|
||||
@ -585,25 +583,43 @@ export class HostnameSmolTrie<Meta = unknown> extends Triebase<Meta> {
|
||||
if (includeAllSubdomain) {
|
||||
// If there is a `[start]sub.example.com` here, remove it
|
||||
node[0] = deleteBit(node[0], INCLUDE_ALL_SUBDOMAIN);
|
||||
node[0] = deleteBit(node[0], START);
|
||||
// Removing all the child nodes by empty the children
|
||||
node[2].clear();
|
||||
// we do not remove sub.example.com for now, we will do that later
|
||||
} else {
|
||||
// Trying to whitelist `example.com` when there is already a `.example.com` in the trie
|
||||
node[0] = deleteBit(node[0], INCLUDE_ALL_SUBDOMAIN);
|
||||
}
|
||||
|
||||
// return early if not found
|
||||
if (missingBit(node[0], START)) return;
|
||||
if (includeAllSubdomain) {
|
||||
node[1]?.[2].delete(node[3]);
|
||||
} else if (missingBit(node[0], START) && node[1]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (toPrune && tokenToPrune) {
|
||||
toPrune[2].delete(tokenToPrune);
|
||||
} else {
|
||||
node[0] = deleteBit(node[0], START);
|
||||
}
|
||||
|
||||
cleanUpEmptyNode(node);
|
||||
};
|
||||
}
|
||||
|
||||
function cleanUpEmptyNode(node: TrieNode<unknown>) {
|
||||
if (
|
||||
missingBit(node[0], START)
|
||||
&& node[2].size === 0
|
||||
&& missingBit(node[0], INCLUDE_ALL_SUBDOMAIN)
|
||||
&& node[1]
|
||||
) {
|
||||
node[1][2].delete(node[3]);
|
||||
|
||||
cleanUpEmptyNode(node[1]);
|
||||
}
|
||||
}
|
||||
|
||||
export class HostnameTrie<Meta = unknown> extends Triebase<Meta> {
|
||||
get size() {
|
||||
return this.$size;
|
||||
@ -618,7 +634,7 @@ export class HostnameTrie<Meta = unknown> extends Triebase<Meta> {
|
||||
if (child.has(token)) {
|
||||
node = child.get(token)!;
|
||||
} else {
|
||||
const newNode = createNode(node);
|
||||
const newNode = createNode(token, node);
|
||||
child.set(token, newNode);
|
||||
node = newNode;
|
||||
}
|
||||
@ -644,7 +660,7 @@ export class HostnameTrie<Meta = unknown> extends Triebase<Meta> {
|
||||
} else {
|
||||
node[0] = deleteBit(node[0], INCLUDE_ALL_SUBDOMAIN);
|
||||
}
|
||||
node[3] = meta!;
|
||||
node[4] = meta!;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user