perf(regex): cache compiled RE2 patterns across UserRegex constructions (#399)
* perf(regex): cache compiled RE2 patterns across UserRegex constructions createUserRegex() recompiled its pattern on every construction. Commands that build a UserRegex inside a per-row loop therefore recompiled the same pattern once per row -- jq's test/match/capture/scan/splits/sub/gsub, awk's ~ and sub/gsub/match/split, and sed's s/// (twice per line, for the g and Nth-occurrence paths). Compiling costs ~23us against ~1.5us to match with an already-compiled pattern, so compilation dominated those workloads. Memoize the compiled RE2JS in a 256-entry cache keyed on the pattern and the numeric RE2 flags, with insertion-order eviction, mirroring the glob regex cache in src/utils/glob.ts. Only the compiled pattern is shared; lastIndex, the reusable Matcher, result limits and the abort signal stay on the UserRegex instance, which is still constructed per call. Over 100k rows: jq test() 8.96s -> 4.26s, awk ~ 4.15s -> 2.55s, awk gsub 7.16s -> 6.10s, sed s///g 10.46s -> 8.29s. Commands that already hoisted compilation out of their loop (grep, rg) are unchanged. * perf(regex): skip caching patterns longer than 1024 characters Patterns are user-controlled and unbounded in length, so a count-only cap let 256 large distinct patterns pin their source and compiled programs for the host process lifetime. Oversized patterns are now compiled but not retained, bounding retained pattern source at 256 KiB.
W
Wei Tao committed
108c5ccf028e82bdcaabb2a5fd6b2640e56168f5
Parent: 2d9d41f
Committed by GitHub <noreply@github.com>
on 9/7/2026, 8:00:54 PM