Skip to content

Commit e85a7cd

Browse files
hanhan761tnaum-ms
authored andcommitted
Perf: Convert keyword/operator arrays to Sets in Monarch tokenizer (fixes #582)
- Added lazy WeakMap<MonarchLanguageRules, Map<string, Set<string>>> cache - resolveCases now uses Set.has() (O(1)) instead of Array.includes() (O(n)) - Sets are created lazily on first access per rules object
1 parent 75d3058 commit e85a7cd

1 file changed

Lines changed: 24 additions & 3 deletions

File tree

src/documentdb/shell/highlighting/monarchRunner.ts

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,20 +181,41 @@ 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 {
188195
for (const [key, tokenType] of Object.entries(cases)) {
189196
if (key === '@default') {
190197
continue;
191198
}
192199

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

197-
if (Array.isArray(array) && (array as string[]).includes(matchedText)) {
202+
// Lazily convert the named array to a Set on first access
203+
let arrayMap = rulesSetCache.get(rules);
204+
if (!arrayMap) {
205+
arrayMap = new Map();
206+
rulesSetCache.set(rules, arrayMap);
207+
}
208+
209+
let set = arrayMap.get(arrayName);
210+
if (!set) {
211+
const array = rules[arrayName as keyof MonarchLanguageRules];
212+
if (Array.isArray(array)) {
213+
set = new Set(array as readonly string[]);
214+
arrayMap.set(arrayName, set);
215+
}
216+
}
217+
218+
if (set?.has(matchedText)) {
198219
return resolveAction(tokenType);
199220
}
200221
}

0 commit comments

Comments
 (0)