perf(save_tt): vectorize style resolution and typst CSS builder - #663
Merged
vincentarelbundock merged 5 commits intoJul 7, 2026
Merged
Conversation
Two phases of build_tt() dominate save_tt() time on tables with many style_tt() calls (heat-map backgrounds, per-column alignment, etc.): 1. Resolving @Style into the rectangular @style_other/@style_lines grids. apply_style_to_rect() re-scanned the full cell grid for every style entry (O(N * cells * props)) and append_lines_to_rect() used rbind() in a loop (O(N^2)). 2. The typst style_eval() backend, where process_typst_other_styles() built CSS one cell at a time via regex typst_insert_field() calls, and typst_apply_styles() grew style_dict_entries with c(). Replace with batched/vectorized equivalents: - expand_style.R: new resolve_styles_batch() builds a single (i,j)->linear-index map and walks each property once. Old per-row functions kept for backwards compatibility. - build_tt.R: calls resolve_styles_batch() instead of the per-row loop. - typst_style.R: new .typst_build_css_vectorized() emits all key:value fragments in a single pass with matching output format; typst_apply_styles() uses a pre-allocated list + unlist(). Output is byte-identical across 6 fixtures x 4 formats (typst, html, latex, markdown) and the full tinytest suite passes. Benchmarks (median of 5 reps, 60x12 table with 170 style_tt() calls): typst: 1.091s -> 0.703s (1.55x) html: 1.442s -> 1.151s (1.25x) Style resolution phase: 0.451s -> 0.137s (3.3x)
Owner
|
Thanks a lot for taking the time to put this together! This seems like a clear improvement. I've added a few other things and a thank you in the NEWS. Merged. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
NOTE: This PR and the code changes are entirely "vibe coded" using GLM-5.2. So if that is a dealbreaker, please reject, I do understand. But this is a real-world issue I'm facing when generating lots of large typst-tables with lots of formatting. So I hope I can help. If wanted, I can provide further explanation and benchmark/test scripts.
Two phases of build_tt() dominate save_tt() time on tables with many style_tt() calls (heat-map backgrounds, per-column alignment, etc.):
Replace with batched/vectorized equivalents:
Output is byte-identical across 6 fixtures x 4 formats (typst, html, latex, markdown) and the full tinytest suite passes.
Benchmarks (median of 5 reps, 60x12 table with 170 style_tt() calls):
typst: 1.091s -> 0.703s (1.55x)
html: 1.442s -> 1.151s (1.25x)
Style resolution phase: 0.451s -> 0.137s (3.3x)