Repository navigation
feat: support back-references in byte mode - #602
Omkar-Wagholikar wants to merge 5 commits into
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #602 +/- ##
==========================================
+ Coverage 94.85% 94.98% +0.12%
==========================================
Files 14 14
Lines 7230 7357 +127
Branches 432 433 +1
==========================================
+ Hits 6858 6988 +130
+ Misses 371 368 -3
Partials 1 1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Merging this PR will regress 1 benchmark
|
| Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|
| ❌ | access_log_append |
1 s | 1.1 s | -2.64% |
| ⚡ | number_fix |
1,293.4 ms | 635.5 ms | ×2 |
| ⚡ | access_log_no_del |
900 ms | 831.5 ms | +8.23% |
| ⚡ | access_log_all_del |
932.2 ms | 863.8 ms | +7.92% |
| ⚡ | remove_cr |
432.7 ms | 407.4 ms | +6.19% |
| ⚡ | access_log_subst |
2.2 s | 2.1 s | +5.86% |
| ⚡ | access_log_no_subst |
908.8 ms | 861.9 ms | +5.45% |
| ⚡ | genome_subst |
389.9 ms | 381.2 ms | +2.28% |
Tip
Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.
Comparing Omkar-Wagholikar:fix/543-byte-mode-backrefs (b046ee3) with main (3b464d1)
|
Will look into the performance regression |
| predicates = "3.1.3" | ||
| rand = { version = "0.10.0" } | ||
| regex = "1.10.4" | ||
| regex = { version = "1.10.4", features = ["perf-dfa-full"] } |
There was a problem hiding this comment.
perf-dfa-full is unrelated to back-references, please split that into another pr.
it also impacts the binary size, please give numbers there
There was a problem hiding this comment.
This isn't exactly unrelated, the fancy-regex 0.19 dropped regex-automata/dfa (0.18 enabled it), so the bump essentially disables regex's full DFA.
Without adding the perf-dfa-full flag, a 1M+line long s/[0-9]+.[0-9]+…/IP/ run goes from ~0.75s to ~10s.
Binary size (release, x86_64 Linux): main 3,214,528 B; this PR without the flag 3,128,960 B; with the flag 3,302,656 B (+88 KB vs main which is ~3% bigger).
Along with the test func renaming, I also improved the coverage a little
92509d2 to
17a83d8
Compare
…e-mode-backrefs
|
The CodSpeed regression you said you'd look into: please post what you found, or a fix. :) |
|
@codspeedbot fix this regression |
I fixed the regression and pushed two commits to this branch: a merge of CauseThe The per-line copy was already expensive before this PR. For Fix (
|
| Benchmark | main |
this PR | Change |
|---|---|---|---|
number_fix |
574.7 ms | 269.9 ms | ×2.1 |
access_log_no_del |
426.8 ms | 392.4 ms | +8.8% |
access_log_all_del |
443.5 ms | 409.3 ms | +8.4% |
remove_cr |
207.0 ms | 191.3 ms | +8.2% |
access_log_no_subst |
429.9 ms | 398.8 ms | +7.8% |
genome_subst |
194.7 ms | 187.7 ms | +3.7% |
access_log_subst |
1,015 ms | 984.9 ms | +3.1% |
The other 4 benchmarks are unchanged, and none regressed.
cargo test, cargo clippy --all-targets -D warnings, cargo fmt and cargo check in fuzz/ all pass. I also checked that the empty regex picks up the right regex across several commands and matches GNU sed.
The earlier CodSpeed report also compared runs on different CPUs, which makes small differences less reliable. The CI run on this push should show the new numbers.
If you'd rather have the Rc change in its own PR, comment @codspeedbot move the Rc change to a separate PR and I'll do it.
Summary
- Warming up the performance wizard...
- Investigate genome_subst regression — Cause: the per-line Regex clone in re_or_saved_re got more expensive and was no longer inlined once the FancyBytes variant was added
- Fix the regression — Merged main and changed script REs to Rc, so saving the last RE is now a reference count increment
- Validate with CodSpeed simulation — Compared with main: 7 benchmarks faster (number_fix ×2.1, genome_subst +3.7%), 0 regressions
- Push and report — Pushed b046ee3
- Handling comment — Comment handling finished successfully
Was this response helpful? React with 👍 or 👎 to help us improve CodSpeedBot.
|
Hi @sylvestre! I was wondering if you’d be comfortable chatting a bit more informally on Discord, Twitter, or another platform you prefer. I hope you don’t mind me asking! |
|
Sure I am on discord uutils or element |
re_or_saved_re() deep-copied the current RE into context.saved_regex for every input line. For regex::bytes::Regex that clone allocates a new matcher cache pool, and the extra FancyBytes variant made the copy and its drop glue more expensive on the hot path. Storing script REs as Rc<Regex> turns the per-line copy into a reference count increment.
|
Hi @sylvestre , messaged you on discord under the username: sylvestre__ |
Fixes #543.
Problem
In the C/POSIX locale sed uses byte mode, which rejected every regex containing a back-reference:
GNU sed prints
aba.Fix
As @keith-hall suggested on #545, this uses the bytes support added in fancy-regex 0.19 instead of mapping bytes to chars and translating offsets:
Captures<'t, S>/CaptureMatches<'r, 't, S>(this is why Update Rust crate fancy-regex to 0.19.0 #503 fails CI).Regex::FancyBytesvariant compiled withBytesMode::Asciiand searched onchunk.as_bytes().Asciimode (.= any byte, ASCII-only classes) matches the semantics of the existingregex::bytes+unicode(false)byte path, so behaviour is consistent with or without back-references.Limitation
fancy-regex currently has no syntax for a raw non-ASCII byte: in bytes mode
\xE9is read as U+00E9 and matched as its UTF-8 encoding, and[\x80-\xFF]fails to parse inAsciimode. So a back-reference pattern that also contains bytes ≥ 0x80 still errors in byte mode, now with an explicit message ("back-references combined with non-ASCII bytes are not supported in byte mode") rather than producing wrong matches. ASCII patterns work on any input, including invalid UTF-8. I'm happy to raise this upstream.Testing
FancyBytes(is_match,findoffsets,captureswith an unmatched optional group,captures_iter, and the non-ASCII rejection).subst_backref_rejected_in_c_locale.cargo test,cargo clippy --all-targets -D warnings,cargo fmt --check, andcargo checkinfuzz/all pass.LC_ALL=C(back-references in addresses and substitutions,g/N-th/Iflags, multi-line pattern space, invalid UTF-8 input): all identical.