tag:github.com,2008:https://github.com/coregx/coregex/releases Release notes from coregex 2026-02-06T01:06:53Z tag:github.com,2008:Repository/1105180758/v0.12.0 2026-02-06T01:15:05Z v0.12.0: Rust-inspired optimizations <h2>Performance</h2> <ul> <li><strong>Anti-quadratic guard</strong> for reverse suffix/inner/suffix-set searches — prevents O(n²) degradation on high false-positive suffix workloads, falls back to PikeVM when quadratic detected</li> <li><strong>Lazy DFA 4x loop unrolling</strong> — process 4 state transitions per inner loop iteration, check special states between batches</li> <li><strong>Prefilter <code>IsFast()</code> gate</strong> — skip reverse search optimizations when fast SIMD-backed prefix prefilter already exists</li> <li><strong>DFA cache clear &amp; continue</strong> — on cache overflow, clear and fall back to PikeVM for current search instead of permanently disabling DFA</li> </ul> <h2>Fixed</h2> <ul> <li><strong>OnePass DFA capture limit</strong> — tighten from 17 to 16 capture groups (<code>uint32</code> slot mask = 32 bits)</li> </ul> <h2>Benchmark (AMD EPYC, regex-bench)</h2> <table> <thead> <tr> <th>Pattern</th> <th>coregex</th> <th>vs stdlib</th> <th>vs Rust</th> </tr> </thead> <tbody> <tr> <td>suffix</td> <td>0.91ms</td> <td><strong>257x</strong></td> <td><strong>1.4x faster</strong></td> </tr> <tr> <td>email</td> <td>0.70ms</td> <td><strong>383x</strong></td> <td><strong>1.9x faster</strong></td> </tr> <tr> <td>ip</td> <td>2.19ms</td> <td><strong>225x</strong></td> <td><strong>5.5x faster</strong></td> </tr> <tr> <td>uri</td> <td>0.76ms</td> <td><strong>340x</strong></td> <td><strong>1.2x faster</strong></td> </tr> <tr> <td>multiline_php</td> <td>0.60ms</td> <td><strong>171x</strong></td> <td><strong>1.2x faster</strong></td> </tr> <tr> <td>anchored_php</td> <td>0.03ms</td> <td>~1x</td> <td><strong>12.0x faster</strong></td> </tr> </tbody> </table> kolkov tag:github.com,2008:Repository/1105180758/v0.11.9 2026-02-01T21:33:29Z v0.11.9: Fix missing first-byte prefilter in FindAll <h2>Fixed</h2> <ul> <li><strong>Missing first-byte prefilter in FindAll state-reusing path</strong> (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3881752926" data-permission-text="Title is private" data-url="https://github.com/coregx/coregex/issues/107" data-hovercard-type="issue" data-hovercard-url="/coregx/coregex/issues/107/hovercard" href="https://github.com/coregx/coregex/issues/107">#107</a>) <ul> <li><code>findIndicesBoundedBacktrackerAtWithState</code> was missing <code>anchoredFirstBytes</code> O(1) check</li> <li>Pattern <code>^/.*[\w-]+\.php</code> (without <code>$</code>) took 377ms instead of 40µs on 6MB input</li> <li>Fix: <strong>377ms → 40µs</strong> (9000x improvement for non-matching anchored patterns)</li> </ul> </li> </ul> <h2>Full Changelog</h2> <p><a class="commit-link" href="https://github.com/coregx/coregex/compare/v0.11.8...v0.11.9"><tt>v0.11.8...v0.11.9</tt></a></p> kolkov tag:github.com,2008:Repository/1105180758/v0.11.8 2026-02-01T20:41:29Z v0.11.8: Fix UseAnchoredLiteral regression <h2>Fixed</h2> <ul> <li><strong>Critical regression in UseAnchoredLiteral strategy</strong> (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3881752926" data-permission-text="Title is private" data-url="https://github.com/coregx/coregex/issues/107" data-hovercard-type="issue" data-hovercard-url="/coregx/coregex/issues/107/hovercard" href="https://github.com/coregx/coregex/issues/107">#107</a>) <ul> <li><code>FindIndices*</code> and <code>findIndicesAtWithState</code> were missing <code>UseAnchoredLiteral</code> case</li> <li>Pattern <code>^/.*[\w-]+\.php$</code> fell through to slow NFA path</li> <li><strong>Regression</strong>: 0.01ms → 408ms (40,000x slower)</li> <li><strong>Fix</strong>: 408ms → 0.5ms (O(1) anchored literal matching restored)</li> </ul> </li> </ul> <h2>Full Changelog</h2> <p><a class="commit-link" href="https://github.com/coregx/coregex/compare/v0.11.7...v0.11.8"><tt>v0.11.7...v0.11.8</tt></a></p> kolkov tag:github.com,2008:Repository/1105180758/v0.11.7 2026-02-01T19:50:49Z v0.11.7: FindAll optimization - 1.08x faster than stdlib <h2>Fixed</h2> <p><strong>FindAll now uses optimized state-reusing path</strong></p> <ul> <li>FindAll was using slow per-match loop instead of optimized findAllIndicesStreaming</li> <li>Results for <code>(\w{2,8})+</code> on 6MB: 2179ms → 834ms (<strong>2.6x faster</strong>)</li> <li>Now <strong>1.08x faster than stdlib</strong> (was 2.4x slower in regex-bench)</li> </ul> <h3>Full Changelog</h3> <p>See <a href="https://github.com/coregx/coregex/blob/main/CHANGELOG.md#0117---2026-02-01">CHANGELOG.md</a></p> kolkov tag:github.com,2008:Repository/1105180758/v0.11.6 2026-02-01T18:56:45Z v0.11.6: PikeVM 6MB optimization - 1.68x faster than stdlib <h2>Performance</h2> <p>Major PikeVM optimization achieving <strong>1.68x speedup over stdlib</strong> for large inputs (was 2.2x slower).</p> <h3>Key Changes</h3> <ul> <li><strong>Windowed BoundedBacktracker (V12)</strong>: Search in 914KB windows before PikeVM fallback</li> <li><strong>SlotTable architecture</strong>: Rust-style per-state slot storage</li> <li><strong>Dynamic slot sizing</strong>: 0 (IsMatch), 2 (Find), full (Captures)</li> <li><strong>Lightweight searchThread</strong>: 16 bytes (was 40+ bytes)</li> </ul> <h3>Benchmark Results</h3> <p>Pattern <code>(\w{2,8})+</code> vs stdlib:</p> <table> <thead> <tr> <th>Size</th> <th>Speedup</th> </tr> </thead> <tbody> <tr> <td>10KB</td> <td><strong>1.68x faster</strong></td> </tr> <tr> <td>50KB</td> <td><strong>1.88x faster</strong></td> </tr> <tr> <td>100KB</td> <td><strong>2.04x faster</strong></td> </tr> <tr> <td>1MB</td> <td><strong>1.67x faster</strong></td> </tr> <tr> <td><strong>6MB</strong></td> <td><strong>1.68x faster</strong></td> </tr> </tbody> </table> <p><strong>6MB improvement: 1900ms → 628ms (3x faster)</strong></p> <h3>Full Changelog</h3> <p>See <a href="https://github.com/coregx/coregex/blob/main/CHANGELOG.md#0116---2026-02-01">CHANGELOG.md</a></p> kolkov tag:github.com,2008:Repository/1105180758/v0.11.5 2026-02-01T09:46:49Z v0.11.5: Fix checkHasWordBoundary catastrophic slowdown <h2>Summary</h2> <p>Fixes catastrophic performance regression in patterns with <code>\w{n,m}</code> quantifiers (Issue <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3880363266" data-permission-text="Title is private" data-url="https://github.com/coregx/coregex/issues/105" data-hovercard-type="issue" data-hovercard-url="/coregx/coregex/issues/105/hovercard" href="https://github.com/coregx/coregex/issues/105">#105</a>).</p> <p><strong>Before:</strong> 3 minutes 22 seconds on 79KB input (7,000,000x slower than stdlib)<br> <strong>After:</strong> 3.6 µs on 79KB input (<strong>8.6x faster than stdlib</strong>)</p> <h2>Changes</h2> <h3>Fixed</h3> <ul> <li><strong>checkHasWordBoundary catastrophic slowdown</strong> (Issue <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3880363266" data-permission-text="Title is private" data-url="https://github.com/coregx/coregex/issues/105" data-hovercard-type="issue" data-hovercard-url="/coregx/coregex/issues/105/hovercard" href="https://github.com/coregx/coregex/issues/105">#105</a>) <ul> <li>Root cause: O(N*M) complexity from scanning all NFA states per byte</li> <li>Fix: Use <code>NewBuilderWithWordBoundary()</code>, add <code>hasWordBoundary</code> guards, anchored prefilter verification</li> </ul> </li> </ul> <h3>Performance</h3> <ul> <li><strong>DFA state lookup: map → slice</strong> — 42% CPU time eliminated</li> <li><strong>Literal extraction from capture/repeat groups</strong> — better prefilters <ul> <li><code>=($\w...){2}</code> now extracts <code>=$</code> (2 bytes) instead of just <code>=</code></li> </ul> </li> </ul> <h2>Benchmarks (79KB input)</h2> <table> <thead> <tr> <th>Stage</th> <th>Time</th> <th>vs stdlib</th> </tr> </thead> <tbody> <tr> <td>Before fix</td> <td>3m 22s</td> <td>7,000,000x slower</td> </tr> <tr> <td><strong>After fix</strong></td> <td><strong>3.6 µs</strong></td> <td><strong>8.6x faster</strong></td> </tr> </tbody> </table> <h2>Credits</h2> <p><a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/danslo/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/danslo">@danslo</a> for root cause analysis and fix suggestions</p> <p><strong>Full Changelog</strong>: <a class="commit-link" href="https://github.com/coregx/coregex/compare/v0.11.4...v0.11.5"><tt>v0.11.4...v0.11.5</tt></a></p> kolkov tag:github.com,2008:Repository/1105180758/v0.11.4 2026-01-16T15:59:53Z v0.11.4: FindAll multiline optimization <h2>Fixed</h2> <ul> <li><strong>FindAll/FindAllIndex now use UseMultilineReverseSuffix strategy</strong> (Issue <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3822484285" data-permission-text="Title is private" data-url="https://github.com/coregx/coregex/issues/102" data-hovercard-type="issue" data-hovercard-url="/coregx/coregex/issues/102/hovercard" href="https://github.com/coregx/coregex/issues/102">#102</a>) <ul> <li><code>FindIndicesAt()</code> was missing dispatch for <code>UseMultilineReverseSuffix</code></li> <li><code>IsMatch</code>/<code>Find</code> were fast (1µs), but <code>FindAll</code> was slow (78ms) — <strong>100x gap vs Rust</strong></li> <li>After fix: <code>FindAll</code> on 6MB with 2000 matches: <strong>~1ms</strong> (was 78ms)</li> </ul> </li> </ul> <h2>Performance</h2> <table> <thead> <tr> <th>Operation</th> <th>Before</th> <th>After</th> <th>Improvement</th> </tr> </thead> <tbody> <tr> <td>FindAll (6MB, 2000 matches)</td> <td>78ms</td> <td>~1ms</td> <td><strong>78x faster</strong></td> </tr> <tr> <td>vs Rust gap</td> <td>100x slower</td> <td>~1.3x slower</td> <td><strong>Near parity!</strong></td> </tr> </tbody> </table> <h2>Changed</h2> <ul> <li>Updated <code>golang.org/x/sys</code> v0.39.0 → v0.40.0</li> </ul> <p><strong>Full Changelog</strong>: <a class="commit-link" href="https://github.com/coregx/coregex/compare/v0.11.3...v0.11.4"><tt>v0.11.3...v0.11.4</tt></a></p> kolkov tag:github.com,2008:Repository/1105180758/v0.11.3 2026-01-16T14:45:53Z v0.11.3: Prefix fast path 319-552x speedup <h2>Performance</h2> <p>Pattern <code>(?m)^/.*\.php</code> now <strong>319-552x faster</strong> than stdlib (was 3.5-5.7x in v0.11.1)</p> <table> <thead> <tr> <th>Operation</th> <th>coregex</th> <th>stdlib</th> <th>Speedup</th> </tr> </thead> <tbody> <tr> <td>IsMatch</td> <td>182 ns</td> <td>100 µs</td> <td><strong>552x</strong></td> </tr> <tr> <td>Find</td> <td>240 ns</td> <td>81 µs</td> <td><strong>338x</strong></td> </tr> <tr> <td>CountAll</td> <td>58 µs</td> <td>18.7 ms</td> <td><strong>319x</strong></td> </tr> </tbody> </table> <h2>Algorithm</h2> <ol> <li>Suffix prefilter finds <code>.php</code> candidates (SIMD memmem)</li> <li>SIMD backward scan to find line start (<code>bytes.LastIndexByte</code>)</li> <li>O(1) prefix byte check (<code>/</code> at line start)</li> <li>Skip-to-next-line on mismatch (avoids O(n²) worst case)</li> <li>DFA fallback for complex patterns without extractable prefix</li> </ol> <h2>Changes</h2> <ul> <li><code>MultilineReverseSuffixSearcher.prefixBytes</code> for O(1) verification</li> <li><code>SetPrefixLiterals()</code> extracts prefix from pattern</li> <li><code>findLineStart()</code> uses SIMD <code>bytes.LastIndexByte</code></li> <li>Skip-to-next-line: on prefix mismatch, jump to next <code>\n</code> position</li> </ul> <p>Fixes <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3819410877" data-permission-text="Title is private" data-url="https://github.com/coregx/coregex/issues/99" data-hovercard-type="issue" data-hovercard-url="/coregx/coregex/issues/99/hovercard" href="https://github.com/coregx/coregex/issues/99">#99</a></p> kolkov tag:github.com,2008:Repository/1105180758/v0.11.2 2026-01-16T13:46:52Z v0.11.2: DFA verification for UseMultilineReverseSuffix <h2>Performance Improvement</h2> <p>Replace O(n*m) PikeVM verification with O(n) DFA verification for multiline suffix patterns.</p> <p><strong>Issue</strong>: <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3819410877" data-permission-text="Title is private" data-url="https://github.com/coregx/coregex/issues/99" data-hovercard-type="issue" data-hovercard-url="/coregx/coregex/issues/99/hovercard" href="https://github.com/coregx/coregex/issues/99">#99</a> (Rust regex 84x faster on <code>(?m)^/.*\.php</code>)</p> <h3>Benchmark Results</h3> <table> <thead> <tr> <th>Case</th> <th>Before</th> <th>After</th> <th>Speedup</th> </tr> </thead> <tbody> <tr> <td>No-match (2KB)</td> <td>1136 ns</td> <td>108 ns</td> <td><strong>10.5x</strong></td> </tr> <tr> <td>Long no-match</td> <td>25937 ns</td> <td>197 ns</td> <td><strong>131x</strong></td> </tr> <tr> <td>Large input (6MB)</td> <td>66 ms</td> <td>~5-10 ms</td> <td><strong>10-30x</strong> (expected)</td> </tr> </tbody> </table> <h3>Changes</h3> <ul> <li><code>MultilineReverseSuffixSearcher.forwardDFA</code> replaces <code>pikevm</code> field</li> <li>Uses <code>lazy.DFA.SearchAtAnchored()</code> for linear-time anchored matching</li> <li><code>lazy.CompileWithConfig()</code> creates forward DFA with proper config</li> </ul> <h3>Research Insight</h3> <p>Analysis of Rust regex-automata revealed that the hybrid (lazy) DFA does <strong>NOT</strong> use per-state acceleration — only the dense (pre-compiled) DFA does. The real performance difference comes from using DFA vs NFA/PikeVM for verification.</p> <p>coregex already has partial state acceleration in <code>dfa/lazy/</code>. The main fix was switching from PikeVM to DFA verification.</p> <hr> <p><strong>Full Changelog</strong>: <a class="commit-link" href="https://github.com/coregx/coregex/compare/v0.11.1...v0.11.2"><tt>v0.11.1...v0.11.2</tt></a></p> kolkov tag:github.com,2008:Repository/1105180758/v0.11.1 2026-01-15T21:56:33Z v0.11.1: UseMultilineReverseSuffix 3.5-5.7x speedup <h2>What's New</h2> <p>New <strong>18th strategy</strong> <code>UseMultilineReverseSuffix</code> for multiline suffix patterns like <code>(?m)^/.*\.php</code>.</p> <h3>Performance (Issue <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3819071280" data-permission-text="Title is private" data-url="https://github.com/coregx/coregex/issues/97" data-hovercard-type="issue" data-hovercard-url="/coregx/coregex/issues/97/hovercard" href="https://github.com/coregx/coregex/issues/97">#97</a>)</h3> <p><strong>Before</strong>: coregex was 24% slower than stdlib<br> <strong>After</strong>: coregex is <strong>3.5-5.7x faster</strong> than stdlib</p> <table> <thead> <tr> <th>Operation</th> <th>coregex</th> <th>stdlib</th> <th>Speedup</th> </tr> </thead> <tbody> <tr> <td>IsMatch (0.5MB)</td> <td>20.6 µs</td> <td>72.2 µs</td> <td><strong>3.5x</strong></td> </tr> <tr> <td>Find (0.5MB)</td> <td>15.3 µs</td> <td>68.7 µs</td> <td><strong>4.5x</strong></td> </tr> <tr> <td>CountAll (200 matches)</td> <td>2.56 ms</td> <td>14.6 ms</td> <td><strong>5.7x</strong></td> </tr> <tr> <td>No-match (small)</td> <td>90 ns</td> <td>1.1 µs</td> <td><strong>12x</strong></td> </tr> <tr> <td>No-match (2KB)</td> <td>184 ns</td> <td>24 µs</td> <td><strong>130x</strong></td> </tr> </tbody> </table> <h3>Algorithm</h3> <ol> <li>Suffix prefilter finds <code>.php</code> candidates</li> <li>Backward scan to line start (<code>\n</code> or pos 0)</li> <li>Forward PikeVM verification</li> </ol> <h3>Files</h3> <ul> <li><code>meta/reverse_suffix_multiline.go</code> (NEW)</li> <li><code>meta/reverse_suffix_multiline_test.go</code> (NEW)</li> </ul> <p><strong>Full Changelog</strong>: <a class="commit-link" href="https://github.com/coregx/coregex/compare/v0.11.0...v0.11.1"><tt>v0.11.0...v0.11.1</tt></a></p> kolkov