Skip to content

Commit 8fda157

Browse files
authored
Perf: Convert keyword/operator arrays to Sets in Monarch tokenizer (fixes #582) (#718)
2 parents 75d3058 + d235c07 commit 8fda157

1 file changed

Lines changed: 23 additions & 3 deletions

File tree

src/documentdb/shell/highlighting/monarchRunner.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,20 +181,40 @@ function resolveAction(action: string): string {
181181
return action;
182182
}
183183

184+
// ─── Lazy Set cache for O(1) keyword/operator lookups ────────────────────────
185+
186+
const rulesSetCache = new WeakMap<MonarchLanguageRules, Map<string, Set<string>>>();
187+
184188
/**
185189
* Resolve a `cases` lookup: check if the matched text is in a named array.
190+
*
191+
* Named arrays (keywords, bsonConstructors, shellCommands, operators) are
192+
* lazily converted to Sets on first lookup so subsequent `.has()` calls are O(1).
186193
*/
187194
function resolveCases(matchedText: string, cases: Record<string, string>, rules: MonarchLanguageRules): string {
195+
let arrayMap = rulesSetCache.get(rules);
196+
if (!arrayMap) {
197+
arrayMap = new Map();
198+
rulesSetCache.set(rules, arrayMap);
199+
}
200+
188201
for (const [key, tokenType] of Object.entries(cases)) {
189202
if (key === '@default') {
190203
continue;
191204
}
192205

193-
// Look up the named array in the rules object
194206
const arrayName = key.startsWith('@') ? key.slice(1) : key;
195-
const array = rules[arrayName as keyof MonarchLanguageRules];
196207

197-
if (Array.isArray(array) && (array as string[]).includes(matchedText)) {
208+
let set = arrayMap.get(arrayName);
209+
if (!set) {
210+
const array = rules[arrayName as keyof MonarchLanguageRules];
211+
if (Array.isArray(array)) {
212+
set = new Set(array as readonly string[]);
213+
arrayMap.set(arrayName, set);
214+
}
215+
}
216+
217+
if (set?.has(matchedText)) {
198218
return resolveAction(tokenType);
199219
}
200220
}

0 commit comments

Comments
 (0)