⚡️ Faster fc.stringMatching for \W \D \S .#7050
Merged
Merged
Conversation
The negated meta-character filters (`\W`, `\D`, `\S` and `.`) used `defaultChar().filter((c) => safeIndexOf(arr, c) === -1)`, an O(n) linear scan run per generated character on the rejection-sampling path. `\W`'s forbidden array has 63 entries and accepts only ~34% of candidates, so the scan cost is paid repeatedly. Precompute the membership sets once at module scope and test with the poisoning-safe `safeHas` (O(1)). Accept/reject decisions are identical, so the RNG sequence and generated values are byte-for-byte unchanged. https://claude.ai/code/session_01SRx4yxfDXbBWd5JDy7nrtz
🦋 Changeset detectedLatest commit: 59dd849 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
@fast-check/ava
fast-check
@fast-check/jest
@fast-check/packaged
@fast-check/poisoning
@fast-check/vitest
@fast-check/worker
commit: |
Contributor
⏱️ Benchmark ResultsClick to expand |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7050 +/- ##
==========================================
+ Coverage 94.86% 94.88% +0.01%
==========================================
Files 212 212
Lines 5884 5899 +15
Branches 1543 1548 +5
==========================================
+ Hits 5582 5597 +15
Misses 294 294
Partials 8 8
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:
|
dubzzz
commented
Jun 5, 2026
Applied by GitHub Action workflow: PR Format Run ID: 26993052809 Target PR: 7050
dubzzz
enabled auto-merge (squash)
June 5, 2026 03:16
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.
Description
This is a performance-only change to
fc.stringMatching. Generated values are byte-for-byte unchanged — only the speed ofgenerateimproves for regexes using the negated meta-character classes\W,\D,\Sand.. No public API change, no behavior change for end users.Measured improvement (interleaved separate-process A/B, median of medians):
stringMatching(/\W{8}/)and similar\W-heavy patterns: ~−5–8% ns/op (measured −5.5% in a clean run, ~−8% in the discovering agent's runs; always beats the matched noise floor)./^[a-zA-Z0-9]+$/) are unaffected — the control sample moved −1.1%, inside the noise band.\D/\S/.benefit too in principle, but their forbidden-character arrays are tiny (10/6/2–4 entries) so the gain there stays within measurement noise.Why
The negated meta-character filters were implemented as a linear scan over a forbidden-character array, run per generated character on the rejection-sampling path:
\W'swordCharsarray has 63 entries and\Waccepts only ~34% ofgrapheme-asciicandidates, so each accepted character costs several full-lengthO(n)scans. This precomputes the membership sets once at module scope and tests with the poisoning-safesafeHas(O(1)):Because the accept/reject decision for every candidate is identical, the RNG draw sequence — and therefore the generated (and shrunk) values — are exactly preserved.
Scope, correctness and impact
stringMatching.ts) plus the changeset. Uses the existing poisoning-safeSet/safeHasglobals, consistent with the rest of the codebase.stringMatching,SanitizeRegexAst,TokenizeRegex,ClampRegexAstall pass (229 tests). Output was verified byte-identical tomainacross many regexes × seeds × bias settings, so the distribution is provably unchanged and no new test is needed.fc.stringMatchingongenerate#7044 (which touches theAlternativebranch); the only textual overlap is theglobals.jsimport line, a trivial rebase for whichever merges second.Checklist
— Don't delete this checklist and make sure you do the following before opening the PR
pnpm run bumpor by following the instructions from the changeset bot🐛(vitest) Something...) when the change targets a package other thanfast-checkGenerated by Claude Code