Expand description
pat_cache submodule — global compiled-pattern cache (Rust-only opt).
Global compiled-pattern cache — a zshrs-only optimization with NO C
counterpart, so it lives here in src/extensions rather than in
src/ported.
Why it exists: C zsh recompiles a pattern on every match too, but its C
patcompile is ~40-75x faster than this Rust port. Shell code re-matches
identical patterns constantly — [[ x == pat ]], ${(M)a:#pat}, case,
${x//pat/…} — and p10k’s _p9k_param re-matches the SAME
(#b)prompt_([a-z0-9_]#)(*) thousands of times per precmd. At the port’s
compile cost that dominated interactive startup (the “hang before prompt”).
Caching the compiled program turns those repeats into a hash lookup + a
cheap clone of the bytecode, and lets zshrs actually beat zsh here.
Safety: the compiled Patprog is self-contained — matching (pattry*)
reads prog.0.flags / prog.0.globflags (never the global compile
statics) and borrows the prog by & (read-only). So a cached clone is
interchangeable with a freshly-compiled one.
Correctness of the key: the compiled output depends on the pattern text,
inflags, and exactly six options — EXTENDEDGLOB/KSHGLOB/SHGLOB (which
shape zpc_special in patcompcharsset) and CASEGLOB/CASEPATHS/MULTIBYTE
(which shape patglobflags in patcompstart). All are folded into the
key, so any option change yields a distinct key rather than a stale hit.
GLOBAL (not thread-local): the VM dispatches [[ … ]]/pattern work across
zshrs’s worker threads, so a per-thread cache would miss on every worker.
A single RwLock<HashMap> is shared: reads (the common case, a hit) take
the read lock and run concurrently; only a miss’s store takes the write
lock. The check runs BEFORE patcompile’s own compile mutex, so hits never
serialise on the compiler.