perf(gsub-reachable): type1 fmt1 + type3 条件反转遍历方向

延续 9d6e982(type1 fmt2 反转)的思路,对 SingleSubst format1 与
AlternateSubst(type3)同样反转遍历方向:遍历 reachable 二分查 covGids
(按 gid 升序)得 index,替代遍历 covGids 逐个查 reachable。

初夏明朝纯标点实测 fmt1 covLen 405、type3 covLen 987(命中率 2.3%),
均属「展开全量命中极少」模式,反转后遍历量从 covGids.length 降到
reachable.size。

关键:加条件 covGids.length > reachable.size 才反转。无条件反转在
霞鹜/FiraCode 上负优化(covGids 短,FiraCode type1 avg 5.5,二分开销
> Set.has 遍历)。条件反转使短 covGids 走原 Set.has 路径。

type4(Ligature)不反转:firstHit 判定反转后遍历 reachable(53)× 18
calls = 954 次二分 > 原 684 次 Set.has,必负。

A/B vs 9d6e982(3000 次 p50,reachable sha 全一致):
- 初夏标点 102→92μs(-10%)
- 初夏8字 54→51μs(-5%)
- 霞鹜标点 12→10μs(-12%,无条件版 +8% 已修正)
- 霞鹜8字 6.8→6.4μs(-7%)
- FiraCode 标点 70→69μs(-1%,无条件版 +2% 已修正)

相比最初 baseline(fee9e49 前)初夏标点 129→92μs(-29%)。基准测试
SSIM 全不变。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
崮生(子虚) 2026-07-24 17:07:13 +08:00
parent 9d6e982682
commit f053112e44

View File

@ -271,25 +271,46 @@ function collectSubtableTargets(
const covGids = readCoverageGids(r, covOff, covCache);
if (format === 1) {
const delta = r.i16(off + 4);
for (const g of covGids) {
if (inSubset(g)) targets.push((g + delta) & 0xffff);
/** covGids reachable
* covGids FiraCode type1 avg 5.5 Set.has > */
if (covGids.length > reachable.size) {
const lim = covGids.length;
for (const g of reachable) {
let lo = 0, hi = lim;
while (lo < hi) {
const mid = (lo + hi) >> 1;
const mg = covGids[mid];
if (mg < g) lo = mid + 1;
else if (mg > g) hi = mid;
else { targets.push((g + delta) & 0xffff); break; }
}
}
} else {
for (const g of covGids) {
if (inSubset(g)) targets.push((g + delta) & 0xffff);
}
}
} else if (format === 2) {
/** coverageavg 103 gid <4% reachable 53
* covGids reachable 9180 Set.has/round reachable covGids index
/** coverage fmt2 covLen 9180/roundreachable 53<4%
* covGids reachable reachable covGids index Set.has
* covGids gid fmt1 list / fmt2 range */
const count = r.u16(off + 4);
const lim = covGids.length < count ? covGids.length : count;
const gidArrBase = off + 6;
for (const g of reachable) {
/** 二分 covGids[0..lim) 找 g 的 index */
let lo = 0, hi = lim;
while (lo < hi) {
const mid = (lo + hi) >> 1;
const mg = covGids[mid];
if (mg < g) lo = mid + 1;
else if (mg > g) hi = mid;
else { targets.push(r.u16(gidArrBase + mid * 2)); break; }
if (lim > reachable.size) {
for (const g of reachable) {
let lo = 0, hi = lim;
while (lo < hi) {
const mid = (lo + hi) >> 1;
const mg = covGids[mid];
if (mg < g) lo = mid + 1;
else if (mg > g) hi = mid;
else { targets.push(r.u16(gidArrBase + mid * 2)); break; }
}
}
} else {
for (let i = 0; i < lim; i++) {
if (inSubset(covGids[i])) targets.push(r.u16(gidArrBase + i * 2));
}
}
}
@ -304,14 +325,34 @@ function collectSubtableTargets(
for (let k = 0; k < glyphCount; k++) targets.push(r.u16(seqOff + 2 + k * 2));
}
} else if (type === LT_ALTERNATE) {
/** 条件反转:初夏 type3 covLen 987/3 callsavg 329命中率 2.3%covGids 短时走原路径。 */
const covOff = off + r.u16(off + 2);
const altCount = r.u16(off + 4);
const covGids = readCoverageGids(r, covOff, covCache);
for (let i = 0; i < covGids.length && i < altCount; i++) {
if (!inSubset(covGids[i])) continue;
const altOff = off + r.u16(off + 6 + i * 2);
const cnt = r.u16(altOff);
for (let k = 0; k < cnt; k++) targets.push(r.u16(altOff + 2 + k * 2));
const lim = covGids.length < altCount ? covGids.length : altCount;
if (covGids.length > reachable.size) {
for (const g of reachable) {
let lo = 0, hi = lim;
while (lo < hi) {
const mid = (lo + hi) >> 1;
const mg = covGids[mid];
if (mg < g) lo = mid + 1;
else if (mg > g) hi = mid;
else {
const altOff = off + r.u16(off + 6 + mid * 2);
const cnt = r.u16(altOff);
for (let k = 0; k < cnt; k++) targets.push(r.u16(altOff + 2 + k * 2));
break;
}
}
}
} else {
for (let i = 0; i < lim; i++) {
if (!inSubset(covGids[i])) continue;
const altOff = off + r.u16(off + 6 + i * 2);
const cnt = r.u16(altOff);
for (let k = 0; k < cnt; k++) targets.push(r.u16(altOff + 2 + k * 2));
}
}
} else if (type === LT_LIGATURE) {
/** LigatureSubst: 全部 component 在子集 → target gid */