aho-corasick.bench.ts 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. import { fetchRemoteTextByLine } from './fetch-text-by-line';
  2. import { processLineFromReadline } from './process-line';
  3. import createKeywordFilter from './aho-corasick';
  4. import ModernAhoCorasick from 'modern-ahocorasick';
  5. import { AhoCorasick as MonyoneAhoCorasick } from '@monyone/aho-corasick';
  6. // @ts-expect-error -- no types
  7. import FastScanner from 'fastscan';
  8. import { AhoCorasick as RustAhoCorasick } from '@blackglory/aho-corasick';
  9. function runKeywordFilter(data: string[], testFn: (line: string) => boolean) {
  10. for (let i = 0, len = data.length; i < len; i++) {
  11. testFn(data[i]);
  12. }
  13. }
  14. export function getFns(keywordsSet: string[] | readonly string[]) {
  15. const tmp1 = new ModernAhoCorasick(keywordsSet.slice());
  16. const tmp2 = new MonyoneAhoCorasick(keywordsSet.slice());
  17. const scanner = new FastScanner(keywordsSet.slice());
  18. const tmp3 = new RustAhoCorasick(keywordsSet.slice(), { caseSensitive: true });
  19. return [
  20. ['createKeywordFilter', createKeywordFilter(keywordsSet.slice())],
  21. ['modern-ahocorasick', (line: string) => tmp1.search(line).length > 0],
  22. ['@monyone/aho-corasick', (line: string) => tmp2.hasKeywordInText(line)],
  23. ['fastscan', (line: string) => scanner.search(line).length > 0],
  24. ['@blackglory/aho-corasick', (line: string) => tmp3.isMatch(line)]
  25. ] as const;
  26. }
  27. if (require.main === module) {
  28. (async () => {
  29. const { bench, group, run } = await import('mitata');
  30. const data = await processLineFromReadline(await fetchRemoteTextByLine('https://easylist.to/easylist/easylist.txt'));
  31. console.log({ dataLen: data.length });
  32. const keywordsSet = [
  33. '!',
  34. '?',
  35. '*',
  36. '[',
  37. '(',
  38. ']',
  39. ')',
  40. ',',
  41. '#',
  42. '%',
  43. '&',
  44. '=',
  45. '~',
  46. // special modifier
  47. '$popup',
  48. '$removeparam',
  49. '$popunder',
  50. '$cname',
  51. '$frame',
  52. // some bad syntax
  53. '^popup'
  54. ];
  55. const fns = getFns(keywordsSet);
  56. group(() => {
  57. fns.forEach(([name, fn]) => {
  58. bench(name, () => runKeywordFilter(data, fn));
  59. });
  60. });
  61. run();
  62. })();
  63. }