perf(gsub): readClassDefMap 用 gidLookup 数组替代 Map.get

fmt2 ChainContext 的 ClassDef 重映射原用 origToNew.get() 逐 gid 查询,
FiraCode fmt2 ClassDef 展开后 9699 个 gid 每个 Map.get(~9ns) 是 fmt2 路径
热点。改用 gidLookup Int32Array 索引(~1ns),语义等价(gidLookup[g]>=0 ⟺
origToNew.has(g) 且值相同)。输出字节三字体 sha256 全一致,SSIM 不变
(FiraCode 0.9923)。writeChainFormat2 移除冗余 origToNew 参数。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
崮生(子虚) 2026-07-24 15:44:53 +08:00
parent f0a5ac175f
commit 7f983ff969

View File

@ -582,7 +582,7 @@ function serializeLigatureSubst(
* format1: gid classformat2: 区间赋 class
*/
/** 读取 ClassDef 表为 (新gid → classIndex) mapclass index 原样保留(不紧致重编号) */
function readClassDefMap(r: Reader, off: number, origToNew: Map<number, number>): Map<number, number> {
function readClassDefMap(r: Reader, off: number, gidLookup: GidLookup): Map<number, number> {
const result = new Map<number, number>();
if (off === 0) return result;
const format = r.u16(off);
@ -591,8 +591,11 @@ function readClassDefMap(r: Reader, off: number, origToNew: Map<number, number>)
const count = r.u16(off + 4);
for (let i = 0; i < count; i++) {
const origGid = startGid + i;
const newGid = origToNew.get(origGid);
if (newGid !== undefined) result.set(newGid, r.u16(off + 6 + i * 2));
/** 333gidLookupInt32Array ~1ns origToNew.getMap.get ~9ns
* FiraCode fmt2 ClassDef 9699 gid Map.get fmt2 86μs/11
* gidLookup[g] >= 0 origToNew.has(g) */
const newGid = gidLookup[origGid];
if (newGid >= 0) result.set(newGid, r.u16(off + 6 + i * 2));
}
} else if (format === 2) {
const rangeCount = r.u16(off + 2);
@ -602,8 +605,9 @@ function readClassDefMap(r: Reader, off: number, origToNew: Map<number, number>)
const end = r.u16(p + 2);
const cls = r.u16(p + 4);
for (let g = start; g <= end; g++) {
const newGid = origToNew.get(g);
if (newGid !== undefined) result.set(newGid, cls);
/** 同上gidLookup 数组索引替代 Map.get */
const newGid = gidLookup[g];
if (newGid >= 0) result.set(newGid, cls);
}
p += 6;
}
@ -735,7 +739,7 @@ function serializeChainedContextSubst(
}
}
if (classToRules.size === 0) return false;
writeChainFormat2(w, r, coverageOff, backtrackCDOff, inputCDOff, lookaheadCDOff, origToNew, classToRules, covCache, gidLookup);
writeChainFormat2(w, r, coverageOff, backtrackCDOff, inputCDOff, lookaheadCDOff, classToRules, covCache, gidLookup);
return true;
}
@ -864,7 +868,6 @@ function writeChainFormat2(
backtrackCDOff: number,
inputCDOff: number,
lookaheadCDOff: number,
origToNew: Map<number, number>,
classToRules: Map<number, Array<{ back: number[]; input: number[]; look: number[]; records: Array<{ seq: number; lookup: number }> }>>,
covCache: CoverageCache,
gidLookup: GidLookup,
@ -905,9 +908,9 @@ function writeChainFormat2(
coverageHolder[0] = emitCoverage(w, newCovGids);
/** 重映射三个 ClassDef 的 gidclass index 不变) */
const backMap = readClassDefMap(r, backtrackCDOff, origToNew);
const inputMap = readClassDefMap(r, inputCDOff, origToNew);
const lookMap = readClassDefMap(r, lookaheadCDOff, origToNew);
const backMap = readClassDefMap(r, backtrackCDOff, gidLookup);
const inputMap = readClassDefMap(r, inputCDOff, gidLookup);
const lookMap = readClassDefMap(r, lookaheadCDOff, gidLookup);
backHolder[0] = writeClassDefFromMap(w, backMap);
inputHolder[0] = writeClassDefFromMap(w, inputMap);
lookHolder[0] = writeClassDefFromMap(w, lookMap);