mirror of
https://github.com/2234839/web-font.git
synced 2026-09-09 17:42:16 +08:00
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:
parent
9d6e982682
commit
f053112e44
@ -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) {
|
||||
/** 反转遍历方向:coverage(avg 103 gid,命中率 <4%)远大于 reachable(初夏标点 53)。
|
||||
* 遍历 covGids 查 reachable 是 9180 次 Set.has/round;改为遍历 reachable 二分查 covGids 得 index。
|
||||
/** 条件反转遍历方向:coverage 命中率低(初夏 fmt2 covLen 9180/round,reachable 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 calls(avg 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 */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user