Prefer TimSort

This commit is contained in:
SukkaW 2024-05-11 00:28:41 +08:00
parent f99d166c13
commit 748861bd2b
6 changed files with 40 additions and 30 deletions

View File

@ -6,6 +6,7 @@ import { task } from './trace';
import { compareAndWriteFile } from './lib/create-file'; import { compareAndWriteFile } from './lib/create-file';
import { getGorhillPublicSuffixPromise } from './lib/get-gorhill-publicsuffix'; import { getGorhillPublicSuffixPromise } from './lib/get-gorhill-publicsuffix';
import { domainDeduper } from './lib/domain-deduper'; import { domainDeduper } from './lib/domain-deduper';
import { sort } from './lib/timsort';
const escapeRegExp = (string = '') => string.replaceAll(/[$()*+.?[\\\]^{|}]/g, '\\$&'); const escapeRegExp = (string = '') => string.replaceAll(/[$()*+.?[\\\]^{|}]/g, '\\$&');
@ -54,7 +55,7 @@ export const buildInternalCDNDomains = task(import.meta.path, async (span) => {
span, span,
[ [
...sortDomains(domainDeduper(Array.from(proxySet)), gorhill).map(i => `SUFFIX,${i}`), ...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') path.resolve(import.meta.dir, '../Internal/cdn.txt')
); );

View File

@ -3,6 +3,7 @@ import { task } from './trace';
import { treeDir } from './lib/tree-dir'; import { treeDir } from './lib/tree-dir';
import type { TreeType, TreeTypeArray } from './lib/tree-dir'; import type { TreeType, TreeTypeArray } from './lib/tree-dir';
import listDir from '@sukka/listdir'; import listDir from '@sukka/listdir';
import { sort } from './lib/timsort';
const rootPath = path.resolve(import.meta.dir, '../'); const rootPath = path.resolve(import.meta.dir, '../');
const publicPath = path.resolve(import.meta.dir, '../public'); const publicPath = path.resolve(import.meta.dir, '../public');
@ -68,7 +69,7 @@ const prioritySorter = (a: TreeType, b: TreeType) => {
}; };
const walk = (tree: TreeTypeArray) => { const walk = (tree: TreeTypeArray) => {
let result = ''; let result = '';
tree.sort(prioritySorter); sort(tree, prioritySorter);
for (let i = 0, len = tree.length; i < len; i++) { for (let i = 0, len = tree.length; i < len; i++) {
const entry = tree[i]; const entry = tree[i];
if (entry.type === 'directory') { if (entry.type === 'directory') {

View File

@ -18,6 +18,7 @@ import { getPhishingDomains } from './lib/get-phishing-domains';
import * as SetHelpers from 'mnemonist/set'; import * as SetHelpers from 'mnemonist/set';
import { setAddFromArray } from './lib/set-add-from-array'; import { setAddFromArray } from './lib/set-add-from-array';
import { sort } from './lib/timsort';
export const buildRejectDomainSet = task(import.meta.path, async (span) => { export const buildRejectDomainSet = task(import.meta.path, async (span) => {
const gorhill = await getGorhillPublicSuffixPromise(); const gorhill = await getGorhillPublicSuffixPromise();
@ -155,7 +156,7 @@ export const buildRejectDomainSet = task(import.meta.path, async (span) => {
return acc; return acc;
}, new Map()); }, 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 = [ const description = [

View File

@ -158,6 +158,8 @@ export const buildSpeedtestDomainSet = task(import.meta.path, async (span) => {
'.speedtest.aarnet.net.au', '.speedtest.aarnet.net.au',
'.ookla.rcp.net', '.ookla.rcp.net',
'.ookla-speedtests.e2ro.com', '.ookla-speedtests.e2ro.com',
'.speedtest.com.sg',
'.ookla.ddnsgeek.com',
// Cloudflare // Cloudflare
'.speed.cloudflare.com', '.speed.cloudflare.com',
// Wi-Fi Man // Wi-Fi Man

View File

@ -4,6 +4,7 @@ import { surgeDomainsetToClashDomainset, surgeRulesetToClashClassicalTextRuleset
import picocolors from 'picocolors'; import picocolors from 'picocolors';
import type { Span } from '../trace'; import type { Span } from '../trace';
import path from 'path'; import path from 'path';
import { sort } from './timsort';
export async function compareAndWriteFile(span: Span, linesA: string[], filePath: string) { export async function compareAndWriteFile(span: Span, linesA: string[], filePath: string) {
let isEqual = true; let isEqual = true;
@ -122,33 +123,35 @@ const sortTypeOrder: Record<string | typeof defaultSortTypeOrder, number> = {
'IP-CIDR6': 400 'IP-CIDR6': 400
}; };
// sort DOMAIN-SUFFIX and DOMAIN first, then DOMAIN-KEYWORD, then IP-CIDR and IP-CIDR6 if any // sort DOMAIN-SUFFIX and DOMAIN first, then DOMAIN-KEYWORD, then IP-CIDR and IP-CIDR6 if any
export const sortRuleSet = (ruleSet: string[]) => ruleSet export const sortRuleSet = (ruleSet: string[]) => {
.map((rule) => { return sort(
const type = collectType(rule); ruleSet.map((rule) => {
if (!type) { const type = collectType(rule);
return [10, rule] as const; 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;
} }
if (rule.includes('|')) { if (!(type in sortTypeOrder)) {
extraWeight += 1; 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 [ return [
sortTypeOrder[type] + extraWeight, sortTypeOrder[type] + extraWeight,
rule rule
] as const; ] as const;
} }
return [sortTypeOrder[type], rule] as const; return [sortTypeOrder[type], rule] as const;
}) }),
.sort((a, b) => a[0] - b[0]) (a, b) => a[0] - b[0]
.map(c => c[1]); ).map(c => c[1]);
};
const MARK = 'this_ruleset_is_made_by_sukkaw.ruleset.skk.moe'; const MARK = 'this_ruleset_is_made_by_sukkaw.ruleset.skk.moe';

View File

@ -895,7 +895,7 @@ class TimSort<T> {
* @param hi - Last element in the range. * @param hi - Last element in the range.
* comparator. * comparator.
*/ */
export function sort<T>(array: T[], compare: Comparator<T> | undefined = alphabeticalCompare, lo = 0, hi: number = array.length) { export function sort<T>(array: T[], compare: Comparator<T> | undefined = alphabeticalCompare, lo = 0, hi: number = array.length): T[] {
// if (!Array.isArray(array)) { // if (!Array.isArray(array)) {
// throw new TypeError('Can only sort arrays'); // throw new TypeError('Can only sort arrays');
// } // }
@ -914,7 +914,7 @@ export function sort<T>(array: T[], compare: Comparator<T> | undefined = alphabe
// The array is already sorted // The array is already sorted
if (remaining < 2) { if (remaining < 2) {
return; return array;
} }
let runLength = 0; let runLength = 0;
@ -922,7 +922,7 @@ export function sort<T>(array: T[], compare: Comparator<T> | undefined = alphabe
if (remaining < DEFAULT_MIN_MERGE) { if (remaining < DEFAULT_MIN_MERGE) {
runLength = makeAscendingRun(array, lo, hi, compare); runLength = makeAscendingRun(array, lo, hi, compare);
binaryInsertionSort(array, lo, hi, lo + runLength, compare); binaryInsertionSort(array, lo, hi, lo + runLength, compare);
return; return array;
} }
const ts = new TimSort(array, compare); const ts = new TimSort(array, compare);
@ -951,4 +951,6 @@ export function sort<T>(array: T[], compare: Comparator<T> | undefined = alphabe
// Force merging of remaining runs // Force merging of remaining runs
ts.forceMergeRuns(); ts.forceMergeRuns();
return array;
} }