From 748861bd2b43c4fdcd99baf88116537060c26422 Mon Sep 17 00:00:00 2001 From: SukkaW Date: Sat, 11 May 2024 00:28:41 +0800 Subject: [PATCH] Prefer TimSort --- Build/build-internal-cdn-rules.ts | 3 +- Build/build-public.ts | 3 +- Build/build-reject-domainset.ts | 3 +- Build/build-speedtest-domainset.ts | 2 ++ Build/lib/create-file.ts | 51 ++++++++++++++++-------------- Build/lib/timsort.ts | 8 +++-- 6 files changed, 40 insertions(+), 30 deletions(-) diff --git a/Build/build-internal-cdn-rules.ts b/Build/build-internal-cdn-rules.ts index 841df8e3..87815a2a 100644 --- a/Build/build-internal-cdn-rules.ts +++ b/Build/build-internal-cdn-rules.ts @@ -6,6 +6,7 @@ import { task } from './trace'; import { compareAndWriteFile } from './lib/create-file'; import { getGorhillPublicSuffixPromise } from './lib/get-gorhill-publicsuffix'; import { domainDeduper } from './lib/domain-deduper'; +import { sort } from './lib/timsort'; const escapeRegExp = (string = '') => string.replaceAll(/[$()*+.?[\\\]^{|}]/g, '\\$&'); @@ -54,7 +55,7 @@ export const buildInternalCDNDomains = task(import.meta.path, async (span) => { span, [ ...sortDomains(domainDeduper(Array.from(proxySet)), gorhill).map(i => `SUFFIX,${i}`), - ...Array.from(proxyKeywords).sort().map(i => `REGEX,${i}`) + ...sort(Array.from(proxyKeywords)).map(i => `REGEX,${i}`) ], path.resolve(import.meta.dir, '../Internal/cdn.txt') ); diff --git a/Build/build-public.ts b/Build/build-public.ts index 82e7733f..9048e446 100644 --- a/Build/build-public.ts +++ b/Build/build-public.ts @@ -3,6 +3,7 @@ import { task } from './trace'; import { treeDir } from './lib/tree-dir'; import type { TreeType, TreeTypeArray } from './lib/tree-dir'; import listDir from '@sukka/listdir'; +import { sort } from './lib/timsort'; const rootPath = path.resolve(import.meta.dir, '../'); const publicPath = path.resolve(import.meta.dir, '../public'); @@ -68,7 +69,7 @@ const prioritySorter = (a: TreeType, b: TreeType) => { }; const walk = (tree: TreeTypeArray) => { let result = ''; - tree.sort(prioritySorter); + sort(tree, prioritySorter); for (let i = 0, len = tree.length; i < len; i++) { const entry = tree[i]; if (entry.type === 'directory') { diff --git a/Build/build-reject-domainset.ts b/Build/build-reject-domainset.ts index 519e8d51..57e0d7ef 100644 --- a/Build/build-reject-domainset.ts +++ b/Build/build-reject-domainset.ts @@ -18,6 +18,7 @@ import { getPhishingDomains } from './lib/get-phishing-domains'; import * as SetHelpers from 'mnemonist/set'; import { setAddFromArray } from './lib/set-add-from-array'; +import { sort } from './lib/timsort'; export const buildRejectDomainSet = task(import.meta.path, async (span) => { const gorhill = await getGorhillPublicSuffixPromise(); @@ -155,7 +156,7 @@ export const buildRejectDomainSet = task(import.meta.path, async (span) => { return acc; }, new Map()); - return Array.from(statMap.entries()).filter(a => a[1] > 9).sort((a, b) => (b[1] - a[1])); + return sort(Array.from(statMap.entries()).filter(a => a[1] > 9), (a, b) => (b[1] - a[1])); }); const description = [ diff --git a/Build/build-speedtest-domainset.ts b/Build/build-speedtest-domainset.ts index 5ea33271..5c63dc4a 100644 --- a/Build/build-speedtest-domainset.ts +++ b/Build/build-speedtest-domainset.ts @@ -158,6 +158,8 @@ export const buildSpeedtestDomainSet = task(import.meta.path, async (span) => { '.speedtest.aarnet.net.au', '.ookla.rcp.net', '.ookla-speedtests.e2ro.com', + '.speedtest.com.sg', + '.ookla.ddnsgeek.com', // Cloudflare '.speed.cloudflare.com', // Wi-Fi Man diff --git a/Build/lib/create-file.ts b/Build/lib/create-file.ts index f0373cd0..f031a65a 100644 --- a/Build/lib/create-file.ts +++ b/Build/lib/create-file.ts @@ -4,6 +4,7 @@ import { surgeDomainsetToClashDomainset, surgeRulesetToClashClassicalTextRuleset import picocolors from 'picocolors'; import type { Span } from '../trace'; import path from 'path'; +import { sort } from './timsort'; export async function compareAndWriteFile(span: Span, linesA: string[], filePath: string) { let isEqual = true; @@ -122,33 +123,35 @@ const sortTypeOrder: Record = { 'IP-CIDR6': 400 }; // sort DOMAIN-SUFFIX and DOMAIN first, then DOMAIN-KEYWORD, then IP-CIDR and IP-CIDR6 if any -export const sortRuleSet = (ruleSet: string[]) => ruleSet - .map((rule) => { - const type = collectType(rule); - if (!type) { - return [10, rule] as const; - } - if (!(type in sortTypeOrder)) { - return [sortTypeOrder[defaultSortTypeOrder], rule] as const; - } - if (type === 'URL-REGEX') { - let extraWeight = 0; - if (rule.includes('.+') || rule.includes('.*')) { - extraWeight += 10; +export const sortRuleSet = (ruleSet: string[]) => { + return sort( + ruleSet.map((rule) => { + const type = collectType(rule); + if (!type) { + return [10, rule] as const; } - if (rule.includes('|')) { - extraWeight += 1; + if (!(type in sortTypeOrder)) { + return [sortTypeOrder[defaultSortTypeOrder], rule] as const; } + if (type === 'URL-REGEX') { + let extraWeight = 0; + if (rule.includes('.+') || rule.includes('.*')) { + extraWeight += 10; + } + if (rule.includes('|')) { + extraWeight += 1; + } - return [ - sortTypeOrder[type] + extraWeight, - rule - ] as const; - } - return [sortTypeOrder[type], rule] as const; - }) - .sort((a, b) => a[0] - b[0]) - .map(c => c[1]); + return [ + sortTypeOrder[type] + extraWeight, + rule + ] as const; + } + return [sortTypeOrder[type], rule] as const; + }), + (a, b) => a[0] - b[0] + ).map(c => c[1]); +}; const MARK = 'this_ruleset_is_made_by_sukkaw.ruleset.skk.moe'; diff --git a/Build/lib/timsort.ts b/Build/lib/timsort.ts index 53463135..9ff4d0e3 100644 --- a/Build/lib/timsort.ts +++ b/Build/lib/timsort.ts @@ -895,7 +895,7 @@ class TimSort { * @param hi - Last element in the range. * comparator. */ -export function sort(array: T[], compare: Comparator | undefined = alphabeticalCompare, lo = 0, hi: number = array.length) { +export function sort(array: T[], compare: Comparator | undefined = alphabeticalCompare, lo = 0, hi: number = array.length): T[] { // if (!Array.isArray(array)) { // throw new TypeError('Can only sort arrays'); // } @@ -914,7 +914,7 @@ export function sort(array: T[], compare: Comparator | undefined = alphabe // The array is already sorted if (remaining < 2) { - return; + return array; } let runLength = 0; @@ -922,7 +922,7 @@ export function sort(array: T[], compare: Comparator | undefined = alphabe if (remaining < DEFAULT_MIN_MERGE) { runLength = makeAscendingRun(array, lo, hi, compare); binaryInsertionSort(array, lo, hi, lo + runLength, compare); - return; + return array; } const ts = new TimSort(array, compare); @@ -951,4 +951,6 @@ export function sort(array: T[], compare: Comparator | undefined = alphabe // Force merging of remaining runs ts.forceMergeRuns(); + + return array; }