ソースを参照

Perf: a few improvements to trie

SukkaW 1 年間 前
コミット
3bd0ebe36e
2 ファイル変更31 行追加29 行削除
  1. 3 3
      Build/lib/create-file.ts
  2. 28 26
      Build/lib/trie.ts

+ 3 - 3
Build/lib/create-file.ts

@@ -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 flag = unpackSecond(dumped[i][1]);
+    const originalIndex = unpackFirst(dumped[i]);
+    const flag = unpackSecond(dumped[i]);
 
 
     const type = flag === flagDomain ? 'DOMAIN' : 'DOMAIN-SUFFIX';
     const type = flag === flagDomain ? 'DOMAIN' : 'DOMAIN-SUFFIX';
 
 

+ 28 - 26
Build/lib/trie.ts

@@ -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;
+};