diff --git a/.jules/bolt.md b/.jules/bolt.md new file mode 100644 index 0000000..7914300 --- /dev/null +++ b/.jules/bolt.md @@ -0,0 +1,3 @@ +## 2025-07-08 - Optimize string lowercasing in nested loops + **Learning:** In nested loops generating combinations of strings (like symbols and prefixes), repeated calls to `.toLowerCase()` on the concatenated string create an overhead. Caching the lowercase strings during concatenation using parallel arrays is an effective strategy to eliminate redundant operations, but extracting the loop variable correctly when restructuring the iteration pattern is crucial to maintain compile safety. + **Action:** Prioritize lowercasing loop variables at the earliest possible stage and ensure that when caching results in arrays, corresponding iteration logic consistently references the indexed values correctly. diff --git a/src/engine/registry.ts b/src/engine/registry.ts index b4b0166..8ab3c75 100644 --- a/src/engine/registry.ts +++ b/src/engine/registry.ts @@ -314,12 +314,24 @@ function registerUnits(reg: Registry): LengthPhrase[] { }; const phrases: string[] = []; const csPhrases: string[] = []; + const csPhrasesLower: string[] = []; if (d.id === "bit") { // no "kb" for bits — bare *b symbols mean bytes (common expectation) - csPhrases.push(`${pSym}bit`); + const bitPhrase = `${pSym}bit`; + csPhrases.push(bitPhrase); + csPhrasesLower.push(bitPhrase.toLowerCase()); } else { // symbol compositions in every locale: "km" and "км" - for (const ps of pSymsAll) for (const us of symbolsAll) csPhrases.push(ps + us); + const pSymsAllLower = pSymsAll.map((s) => s.toLowerCase()); + const symbolsAllLower = symbolsAll.map((s) => s.toLowerCase()); + for (let i = 0; i < pSymsAll.length; i++) { + const ps = pSymsAll[i]; + const psL = pSymsAllLower[i]; + for (let j = 0; j < symbolsAll.length; j++) { + csPhrases.push(ps + symbolsAll[j]); + csPhrasesLower.push(psL + symbolsAllLower[j]); + } + } } for (const pw of pWords) for (const wv of wordVariants) phrases.push(pw + wv); if (d.id === "byte" && pSym) { @@ -331,8 +343,8 @@ function registerUnits(reg: Registry): LengthPhrase[] { for (const ph of phrases) reg.addPhrase(ph, { t: "unit", unit: pUnit }, { caseSensitive: false }); // collect unambiguous lowercase forms: "KM"/"Km" should still mean km, // while "mm"/"Mm" stay strict (milli vs mega) - for (const ph of csPhrases) { - const lower = ph.toLowerCase(); + for (let i = 0; i < csPhrasesLower.length; i++) { + const lower = csPhrasesLower[i]; const prev = lenientSym.get(lower); if (prev === undefined) lenientSym.set(lower, pUnit); else if (prev && prev.id !== pUnit.id) lenientSym.set(lower, null);