aho-corasick.bench.ts 2.2 KB

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