From c6f3a67711829fa76c4a04af0bc75104859b5a42 Mon Sep 17 00:00:00 2001 From: SukkaW Date: Thu, 21 Nov 2024 21:51:05 +0800 Subject: [PATCH] Perf: repalce `String#localeCompare` w/ simple ASCII-only compare --- Build/build-public.ts | 4 ++-- Build/lib/misc.ts | 20 ++++++++++++++++++++ Build/lib/rules/domainset.ts | 3 ++- Build/lib/stable-sort-domain.ts | 3 ++- Build/lib/trie.ts | 4 ++-- 5 files changed, 28 insertions(+), 6 deletions(-) diff --git a/Build/build-public.ts b/Build/build-public.ts index 8c35756a..e71d596e 100644 --- a/Build/build-public.ts +++ b/Build/build-public.ts @@ -7,7 +7,7 @@ import { treeDir } from './lib/tree-dir'; import type { TreeType, TreeTypeArray } from './lib/tree-dir'; import { OUTPUT_MOCK_DIR, OUTPUT_MODULES_DIR, PUBLIC_DIR, ROOT_DIR } from './constants/dir'; -import { mkdirp, writeFile } from './lib/misc'; +import { fastStringCompare, mkdirp, writeFile } from './lib/misc'; import picocolors from 'picocolors'; import { compareAndWriteFile } from './lib/create-file'; @@ -90,7 +90,7 @@ const priorityOrder: Record<'default' | string & {}, number> = { LICENSE: 70, default: Number.MAX_VALUE }; -const prioritySorter = (a: TreeType, b: TreeType) => ((priorityOrder[a.name] || priorityOrder.default) - (priorityOrder[b.name] || priorityOrder.default)) || a.name.localeCompare(b.name); +const prioritySorter = (a: TreeType, b: TreeType) => ((priorityOrder[a.name] || priorityOrder.default) - (priorityOrder[b.name] || priorityOrder.default)) || fastStringCompare(a.name, b.name); const html = (string: TemplateStringsArray, ...values: any[]) => string.reduce((acc, str, i) => acc + str + (values[i] ?? ''), ''); diff --git a/Build/lib/misc.ts b/Build/lib/misc.ts index d2a106e3..0db5c4e2 100644 --- a/Build/lib/misc.ts +++ b/Build/lib/misc.ts @@ -21,6 +21,26 @@ export function fastStringArrayJoin(arr: string[], sep: string) { return result; } +export function fastStringCompare(a: string, b: string) { + const lenA = a.length; + const lenB = b.length; + const minLen = lenA < lenB ? lenA : lenB; + + for (let i = 0; i < minLen; ++i) { + const ca = a.charCodeAt(i); + const cb = b.charCodeAt(i); + + if (ca > cb) return 1; + if (ca < cb) return -1; + } + + if (lenA === lenB) { + return 0; + } + + return lenA > lenB ? 1 : -1; +}; + interface Write { ( destination: string, diff --git a/Build/lib/rules/domainset.ts b/Build/lib/rules/domainset.ts index be70afb1..624fcb78 100644 --- a/Build/lib/rules/domainset.ts +++ b/Build/lib/rules/domainset.ts @@ -5,6 +5,7 @@ import type { SingboxSourceFormat } from '../singbox'; import * as tldts from 'tldts-experimental'; import { looseTldtsOpt } from '../../constants/loose-tldts-opt'; +import { fastStringCompare } from '../misc'; type Preprocessed = string[]; @@ -89,7 +90,7 @@ export class DomainsetOutput extends RuleOutput { ) .entries()) .filter(a => a[1] > 9) - .sort((a, b) => (b[1] - a[1]) || a[0].localeCompare(b[0])) + .sort((a, b) => (b[1] - a[1]) || fastStringCompare(a[0], b[0])) .map(([domain, count]) => `${domain}${' '.repeat(100 - domain.length)}${count}`); } diff --git a/Build/lib/stable-sort-domain.ts b/Build/lib/stable-sort-domain.ts index 7f7094f2..84777ff0 100644 --- a/Build/lib/stable-sort-domain.ts +++ b/Build/lib/stable-sort-domain.ts @@ -3,10 +3,11 @@ // enough when sorting. import * as tldts from 'tldts-experimental'; import { looseTldtsOpt } from '../constants/loose-tldts-opt'; +import { fastStringCompare } from './misc'; export function compare(a: string, b: string) { if (a === b) return 0; - return (a.length - b.length) || a.localeCompare(b); + return (a.length - b.length) || fastStringCompare(a, b); } export function buildParseDomainMap(inputs: string[]) { diff --git a/Build/lib/trie.ts b/Build/lib/trie.ts index 8d16fca9..36ecb580 100644 --- a/Build/lib/trie.ts +++ b/Build/lib/trie.ts @@ -2,7 +2,7 @@ * Hostbane-Optimized Trie based on Mnemonist Trie */ -import { fastStringArrayJoin } from './misc'; +import { fastStringArrayJoin, fastStringCompare } from './misc'; import util from 'node:util'; import { noop } from 'foxact/noop'; import FIFO from './fifo'; @@ -251,7 +251,7 @@ abstract class Triebase { static compare(this: void, a: string, b: string) { if (a === b) return 0; - return (a.length - b.length) || a.localeCompare(b); + return (a.length - b.length) || fastStringCompare(a, b); } private walkWithSort(