From ecda72a9a750d63924965ead6870a2244e2575fd Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 8 Jul 2026 10:25:58 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=20Optimize=20string=20lowercasing=20i?= =?UTF-8?q?n=20registry=20loop?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Extracted multiple `.toLowerCase()` calls on identical characters during unit concatenation and phrase generation * Cached the lowercased strings in parallel arrays during `csPhrases` initialization * Preserves all functional string behavior Co-authored-by: Horizontal42 <75383519+Horizontal42@users.noreply.github.com> --- .jules/bolt.md | 3 +++ src/engine/registry.ts | 20 ++++++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 .jules/bolt.md 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);