Skip to content

⚡️ Faster fc.stringMatching for \W \D \S .#7050

Merged
dubzzz merged 3 commits into
mainfrom
claude/perf-stringMatching-set-membership
Jun 5, 2026
Merged

⚡️ Faster fc.stringMatching for \W \D \S .#7050
dubzzz merged 3 commits into
mainfrom
claude/perf-stringMatching-set-membership

Conversation

@dubzzz

@dubzzz dubzzz commented Jun 4, 2026

Copy link
Copy Markdown
Owner

Description

AI-agent disclosure: this PR was authored by an automated agent (Claude Code) and has not been line-by-line reviewed by a human before submission.

This is a performance-only change to fc.stringMatching. Generated values are byte-for-byte unchanged — only the speed of generate improves for regexes using the negated meta-character classes \W, \D, \S and .. 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).
  • Regexes that don't use these negated classes (e.g. the common /^[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:

case '\\W': return defaultChar().filter((c) => safeIndexOf(wordChars, c) === -1);

\W's wordChars array has 63 entries and \W accepts only ~34% of grapheme-ascii candidates, so each accepted character costs several full-length O(n) scans. This precomputes the membership sets once at module scope and tests with the poisoning-safe safeHas (O(1)):

const wordCharsSet = new Set(wordChars); // + digit/space/terminator/newLineAndTerminator sets
case '\\W': return defaultChar().filter((c) => !safeHas(wordCharsSet, c));

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

  • Impact: patch. A changeset is included.
  • Single concern: one file (stringMatching.ts) plus the changeset. Uses the existing poisoning-safe Set/safeHas globals, consistent with the rest of the codebase.
  • Tests: stringMatching, SanitizeRegexAst, TokenizeRegex, ClampRegexAst all pass (229 tests). Output was verified byte-identical to main across many regexes × seeds × bias settings, so the distribution is provably unchanged and no new test is needed.
  • Note for reviewers: this is independent of ⚡️ Faster fc.stringMatching on generate #7044 (which touches the Alternative branch); the only textual overlap is the globals.js import 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

  • I have a full understanding of every line in this PR — whether the code was hand-written, AI-generated, copied from external sources or produced by any other tool
  • I flagged the impact of my change (minor / patch / major) either by running pnpm run bump or by following the instructions from the changeset bot
  • I kept this PR focused on a single concern and did not bundle unrelated changes
  • I followed the gitmoji specification for the name of the PR, including the package scope (e.g. 🐛(vitest) Something...) when the change targets a package other than fast-check
  • I added relevant tests and they would have failed without my PR (when applicable)

Generated by Claude Code

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-bot

changeset-bot Bot commented Jun 4, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 59dd849

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
fast-check Patch

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

@pkg-pr-new

pkg-pr-new Bot commented Jun 4, 2026

Copy link
Copy Markdown
@fast-check/ava

npm i https://pkg.pr.new/@fast-check/ava@7050

fast-check

npm i https://pkg.pr.new/fast-check@7050

@fast-check/jest

npm i https://pkg.pr.new/@fast-check/jest@7050

@fast-check/packaged

npm i https://pkg.pr.new/@fast-check/packaged@7050

@fast-check/poisoning

npm i https://pkg.pr.new/@fast-check/poisoning@7050

@fast-check/vitest

npm i https://pkg.pr.new/@fast-check/vitest@7050

@fast-check/worker

npm i https://pkg.pr.new/@fast-check/worker@7050

commit: 59dd849

@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

⏱️ Benchmark Results

Click to expand

 RUN  v4.1.5 /home/runner/work/fast-check/fast-check


 ✓  fast-check  test/bench/arbitraries.bench.ts > generate 43468ms
     name                                                         hz     min      max    mean     p75     p99    p995     p999      rme  samples
   · boolean()                                          5,840,494.84  0.0001   0.5012  0.0002  0.0002  0.0010  0.0022   0.0025   ±0.38%  2920260  [0.63x] ⇓
     boolean()                                          9,237,910.12  0.0001   0.3650  0.0001  0.0001  0.0001  0.0002   0.0004   ±0.39%  4618956  (baseline)
   · integer()                                          7,230,940.05  0.0001   0.3302  0.0001  0.0002  0.0002  0.0003   0.0003   ±0.18%  3615471  [0.77x] ⇓
     integer()                                          9,414,483.12  0.0001   0.1674  0.0001  0.0001  0.0002  0.0002   0.0002   ±0.14%  4707242  (baseline)
   · maxSafeInteger()                                   5,094,234.57  0.0001   0.6370  0.0002  0.0002  0.0003  0.0003   0.0004   ±0.33%  2547118  [0.77x] ⇓
     maxSafeInteger()                                   6,591,260.18  0.0001   0.2590  0.0002  0.0002  0.0002  0.0003   0.0004   ±0.20%  3295631  (baseline)
   · bigInt()                                           1,165,483.59  0.0006   0.3095  0.0009  0.0012  0.0014  0.0017   0.0040   ±0.33%   582742  [0.78x] ⇓
     bigInt()                                           1,492,725.56  0.0005   0.3452  0.0007  0.0009  0.0010  0.0013   0.0019   ±0.32%   746363  (baseline)
   · float()                                            4,219,016.97  0.0002   0.4448  0.0002  0.0002  0.0003  0.0004   0.0025   ±0.33%  2109509  [0.75x] ⇓
     float()                                            5,603,710.99  0.0001   0.2136  0.0002  0.0002  0.0002  0.0003   0.0006   ±0.19%  2801856  (baseline)
   · double()                                           1,545,916.56  0.0004   3.6985  0.0006  0.0007  0.0010  0.0013   0.0031   ±4.28%   772959  [0.73x] ⇓
     double()                                           2,112,153.06  0.0003   0.3724  0.0005  0.0006  0.0009  0.0011   0.0016   ±0.31%  1056077  (baseline)
   · date()                                             2,774,680.30  0.0003   3.0461  0.0004  0.0003  0.0005  0.0006   0.0014   ±3.17%  1389885  [0.69x] ⇓
     date()                                             4,021,749.86  0.0002   0.2145  0.0002  0.0003  0.0003  0.0004   0.0009   ±0.19%  2010875  (baseline)
   · string()                                             686,446.72  0.0003   8.2491  0.0015  0.0014  0.0042  0.0064   0.0221   ±8.95%   343224  [0.53x] ⇓
     string()                                           1,301,159.32  0.0002   0.3495  0.0008  0.0010  0.0016  0.0017   0.0029   ±0.36%   650580  (baseline)
   · string({ maxLength: 100, size: 'max' })              146,292.64  0.0003  13.6725  0.0068  0.0088  0.0211  0.0264   0.0354   ±7.01%    73147  [0.65x] ⇓
     string({ maxLength: 100, size: 'max' })              224,217.25  0.0002   0.3106  0.0045  0.0065  0.0125  0.0132   0.0196   ±0.52%   112110  (baseline)
   · string({ unit: 'grapheme' })                         532,164.10  0.0003  10.8121  0.0019  0.0021  0.0047  0.0059   0.0135  ±10.59%   268224  [0.62x] ⇓
     string({ unit: 'grapheme' })                         852,087.41  0.0002   0.3546  0.0012  0.0016  0.0026  0.0028   0.0098   ±0.36%   426044  (baseline)
   · base64String()                                       755,369.98  0.0003   8.5652  0.0013  0.0013  0.0027  0.0044   0.0134   ±9.35%   377685  [0.60x] ⇓
     base64String()                                     1,259,338.58  0.0002   0.3380  0.0008  0.0010  0.0016  0.0017   0.0039   ±0.40%   629670  (baseline)
   · array(integer())                                   1,314,933.84  0.0002   8.3914  0.0008  0.0007  0.0018  0.0022   0.0057   ±7.89%   657467  [0.62x] ⇓
     array(integer())                                   2,131,831.98  0.0002   0.8271  0.0005  0.0005  0.0011  0.0012   0.0016   ±0.47%  1065916  (baseline)
   · array(integer(), { maxLength: 100, size: 'max' })    256,448.84  0.0003   8.3771  0.0039  0.0045  0.0119  0.0153   0.0219   ±7.55%   128225  [0.63x] ⇓
     array(integer(), { maxLength: 100, size: 'max' })    407,212.39  0.0002   0.3100  0.0025  0.0034  0.0081  0.0087   0.0148   ±0.49%   203607  (baseline)
   · uniqueArray(integer())                             1,014,016.31  0.0003   6.1748  0.0010  0.0011  0.0021  0.0023   0.0089   ±6.94%   507027  [0.64x] ⇓
     uniqueArray(integer())                             1,587,879.34  0.0002   0.3798  0.0006  0.0008  0.0015  0.0016   0.0027   ±0.36%   793940  (baseline)
   · set(integer())                                       822,523.70  0.0003   9.0611  0.0012  0.0014  0.0029  0.0037   0.0121   ±6.52%   411262  [0.66x] ⇓
     set(integer())                                     1,255,229.08  0.0003   0.2321  0.0008  0.0010  0.0019  0.0025   0.0054   ±0.36%   627615  (baseline)
   · tuple(integer())                                   3,646,685.53  0.0002   0.4968  0.0003  0.0003  0.0004  0.0005   0.0013   ±0.63%  1823343  [0.78x] ⇓
     tuple(integer())                                   4,666,657.59  0.0002   0.3399  0.0002  0.0002  0.0003  0.0004   0.0009   ±0.50%  2333329  (baseline)
   · record({ a: integer() })                           1,010,585.73  0.0005  13.3113  0.0010  0.0006  0.0018  0.0020   0.0057  ±17.39%   505293  [0.46x] ⇓
     record({ a: integer() })                           2,217,923.81  0.0003   0.3772  0.0005  0.0005  0.0008  0.0010   0.0014   ±0.45%  1108962  (baseline)
   · dictionary(string(), integer())                       79,618.07  0.0005  13.1828  0.0126  0.0142  0.0337  0.0415   0.0589  ±13.08%    39810  [0.64x] ⇓
     dictionary(string(), integer())                      124,703.94  0.0004  19.7837  0.0080  0.0106  0.0263  0.0307   0.0420   ±8.08%    62352  (baseline)
   · map(string(), integer())                             113,490.32  0.0003  10.6474  0.0088  0.0096  0.0249  0.0307   0.0438  ±14.02%    57184  [0.54x] ⇓
     map(string(), integer())                             208,501.73  0.0002   0.3379  0.0048  0.0071  0.0149  0.0172   0.0253   ±0.59%   104252  (baseline)
   · constantFrom(...)                                  7,239,808.83  0.0001   0.6395  0.0001  0.0001  0.0002  0.0002   0.0003   ±0.28%  3619905  [0.74x] ⇓
     constantFrom(...)                                  9,799,033.31  0.0001   0.3876  0.0001  0.0001  0.0001  0.0001   0.0002   ±0.17%  4899517  (baseline)
   · oneof(integer(), integer())                        3,962,558.79  0.0002   0.5502  0.0003  0.0003  0.0003  0.0004   0.0009   ±0.24%  1981280  [0.78x] ⇓
     oneof(integer(), integer())                        5,076,050.39  0.0001   0.4850  0.0002  0.0002  0.0003  0.0003   0.0007   ±0.22%  2538026  (baseline)
   · oneof({ weight, arbitrary }, ...)                  3,888,643.39  0.0002  11.3791  0.0003  0.0003  0.0004  0.0005   0.0010   ±4.47%  1944322  [0.75x] ⇓
     oneof({ weight, arbitrary }, ...)                  5,209,841.17  0.0001   0.0376  0.0002  0.0002  0.0003  0.0003   0.0006   ±0.09%  2604921  (baseline)
   · option(integer())                                  4,019,699.02  0.0002   0.5626  0.0002  0.0003  0.0003  0.0004   0.0010   ±0.35%  2009850  [0.76x] ⇓
     option(integer())                                  5,282,137.38  0.0001   0.3746  0.0002  0.0002  0.0003  0.0003   0.0007   ±0.33%  2641069  (baseline)
   · subarray([1, 2, 3, 4, 5])                          1,733,818.44  0.0003   0.4339  0.0006  0.0007  0.0011  0.0014   0.0021   ±0.53%   866910  [0.68x] ⇓
     subarray([1, 2, 3, 4, 5])                          2,544,851.34  0.0002   0.3507  0.0004  0.0005  0.0007  0.0009   0.0014   ±0.37%  1272426  (baseline)
   · letrec(tree)                                         478,158.89  0.0002  13.5184  0.0021  0.0021  0.0068  0.0089   0.0159  ±17.73%   239080  [0.48x] ⇓
     letrec(tree)                                         999,553.56  0.0001   0.3415  0.0010  0.0015  0.0042  0.0048   0.0096   ±0.47%   499779  (baseline)
   · memo(tree)                                           460,397.73  0.0002  13.3020  0.0022  0.0022  0.0063  0.0088   0.0145  ±18.35%   230199  [0.45x] ⇓
     memo(tree)                                         1,029,136.86  0.0001   0.3450  0.0010  0.0017  0.0033  0.0034   0.0087   ±0.47%   514569  (baseline)
   · anything()                                            58,290.27  0.0003  13.0272  0.0172  0.0223  0.0763  0.0909   0.1434  ±13.87%    29146  [0.57x] ⇓
     anything()                                           102,065.99  0.0002   4.0333  0.0098  0.0163  0.0508  0.0578   0.0781   ±2.38%    51035  (baseline)
   · json()                                                58,033.73  0.0003  12.3500  0.0172  0.0230  0.0724  0.0803   0.1044  ±14.11%    29018  [0.61x] ⇓
     json()                                                94,859.62  0.0002   1.0154  0.0105  0.0178  0.0540  0.0610   0.0784   ±1.72%    47431  (baseline)
   · entityGraph(node -> node)                              6,925.24  0.0082  16.5333  0.1444  0.1044  0.3692  0.4864  14.9951  ±19.99%     3529  [0.74x] ⇓
     entityGraph(node -> node)                              9,320.55  0.0062   8.7051  0.1073  0.0982  0.1726  0.2077   8.2832  ±12.15%     4661  (baseline)
   · emailAddress()                                        62,670.30  0.0025  11.8525  0.0160  0.0154  0.0374  0.0437   0.0691  ±13.72%    31336  [0.54x] ⇓
     emailAddress()                                       116,543.95  0.0019   0.5560  0.0086  0.0109  0.0169  0.0202   0.0281   ±0.76%    58272  (baseline)
   · webUrl()                                             104,919.70  0.0024  12.2128  0.0095  0.0077  0.0204  0.0237   0.0394  ±15.85%    53071  [0.49x] ⇓
     webUrl()                                             216,091.74  0.0018   0.4520  0.0046  0.0054  0.0086  0.0120   0.0181   ±0.73%   108046  (baseline)
   · ipV4()                                             1,048,363.97  0.0006   8.1637  0.0010  0.0009  0.0012  0.0017   0.0071   ±9.44%   524182  [0.65x] ⇓
     ipV4()                                             1,618,471.83  0.0005   0.5645  0.0006  0.0006  0.0008  0.0011   0.0016   ±0.63%   809236  (baseline)
   · ipV6()                                               165,760.53  0.0005  10.3780  0.0060  0.0054  0.0149  0.0169   0.0270  ±12.83%    83327  [0.57x] ⇓
     ipV6()                                               289,615.99  0.0004  18.2143  0.0035  0.0039  0.0098  0.0120   0.0159   ±7.16%   144808  (baseline)
   · uuid()                                               501,822.34  0.0011  13.0257  0.0020  0.0015  0.0033  0.0037   0.0131  ±14.86%   252195  [0.55x] ⇓
     uuid()                                               915,498.10  0.0008   0.3776  0.0011  0.0011  0.0016  0.0018   0.0096   ±0.40%   457750  (baseline)
   · stringMatching(/^[a-zA-Z0-9]+$/)                     358,703.78  0.0008  11.3033  0.0028  0.0026  0.0039  0.0048   0.0147  ±14.78%   180062  [0.56x] ⇓
     stringMatching(/^[a-zA-Z0-9]+$/)                     640,823.71  0.0006   8.2633  0.0016  0.0019  0.0029  0.0030   0.0110   ±3.27%   320413  (baseline)
   · mixedCase(string())                                  471,181.29  0.0005   4.5638  0.0021  0.0024  0.0038  0.0045   0.0138   ±5.37%   235591  [0.68x] ⇓
     mixedCase(string())                                  692,609.26  0.0004   0.3828  0.0014  0.0018  0.0027  0.0028   0.0105   ±0.46%   346306  (baseline)
   · integer().map(.)                                   5,114,854.26  0.0001   0.7202  0.0002  0.0002  0.0003  0.0003   0.0005   ±0.40%  2557428  [0.77x] ⇓
     integer().map(.)                                   6,646,346.52  0.0001   0.2883  0.0002  0.0002  0.0002  0.0002   0.0005   ±0.47%  3323174  (baseline)
   · integer().chain(.)                                 2,892,905.76  0.0003   0.6163  0.0003  0.0004  0.0005  0.0006   0.0014   ±0.68%  1446453  [0.76x] ⇓
     integer().chain(.)                                 3,783,300.93  0.0002   0.4241  0.0003  0.0003  0.0004  0.0004   0.0010   ±0.53%  1891651  (baseline)
   · integer().filter(.)                                3,077,690.44  0.0001   0.6897  0.0003  0.0004  0.0010  0.0011   0.0015   ±0.43%  1538846  [0.81x] ⇓
     integer().filter(.)                                3,822,610.63  0.0001  10.9131  0.0003  0.0003  0.0008  0.0009   0.0012   ±4.28%  1911306  (baseline)

 ✓  fast-check  test/bench/runners.bench.ts > runner 2429ms
     name                                                     hz     min     max    mean     p75     p99    p995    p999     rme  samples
   · assert on sync predicate not returning anything   12,451.76  0.0773  0.3444  0.0803  0.0784  0.1546  0.1657  0.1940  ±0.36%     6226  [0.77x] ⇓
     assert on sync predicate not returning anything   16,067.29  0.0600  0.2371  0.0622  0.0607  0.1192  0.1269  0.1487  ±0.31%     8034  (baseline)
   · assert on sync predicate returning true           12,403.80  0.0770  0.3708  0.0806  0.0782  0.1558  0.1645  0.2433  ±0.41%     6202  [0.77x] ⇓
     assert on sync predicate returning true           16,154.28  0.0599  0.2651  0.0619  0.0605  0.1184  0.1254  0.1770  ±0.32%     8078  (baseline)
   · assert on async predicate not returning anything   8,414.31  0.1128  0.3811  0.1188  0.1157  0.1937  0.1991  0.2307  ±0.40%     4208  [0.77x] ⇓
     assert on async predicate not returning anything  10,898.55  0.0874  0.2729  0.0918  0.0892  0.1501  0.1543  0.1737  ±0.34%     5450  (baseline)
   · check on sync predicate not returning anything    12,440.88  0.0772  0.4890  0.0804  0.0784  0.1534  0.1667  0.2359  ±0.41%     6221  [0.80x] ⇓
     check on sync predicate not returning anything    15,632.62  0.0601  0.9559  0.0640  0.0620  0.1143  0.1353  0.2222  ±0.53%     7817  (baseline)

 BENCH  Summary

   fast-check  constantFrom(...) - test/bench/arbitraries.bench.ts > generate
    1.00x faster than integer()
    1.24x faster than boolean()
    1.42x faster than integer().map(.)
    1.42x faster than maxSafeInteger()
    1.72x faster than float()
    1.80x faster than option(integer())
    1.83x faster than oneof(integer(), integer())
    1.86x faster than oneof({ weight, arbitrary }, ...)
    1.99x faster than tuple(integer())
    2.35x faster than integer().filter(.)
    2.50x faster than integer().chain(.)
    2.61x faster than date()
    4.18x faster than subarray([1, 2, 3, 4, 5])
    4.68x faster than double()
    5.51x faster than array(integer())
    6.21x faster than bigInt()
    6.91x faster than ipV4()
    7.14x faster than uniqueArray(integer())
    7.16x faster than record({ a: integer() })
    8.80x faster than set(integer())
    9.58x faster than base64String()
    10.55x faster than string()
    13.60x faster than string({ unit: 'grapheme' })
    14.43x faster than uuid()
    15.14x faster than letrec(tree)
    15.37x faster than mixedCase(string())
    15.73x faster than memo(tree)
    20.18x faster than stringMatching(/^[a-zA-Z0-9]+$/)
    28.23x faster than array(integer(), { maxLength: 100, size: 'max' })
    43.68x faster than ipV6()
    49.49x faster than string({ maxLength: 100, size: 'max' })
    63.79x faster than map(string(), integer())
    69.00x faster than webUrl()
    90.93x faster than dictionary(string(), integer())
    115.52x faster than emailAddress()
    124.20x faster than anything()
    124.75x faster than json()
    1045.42x faster than entityGraph(node -> node)

   fast-check  assert on sync predicate not returning anything - test/bench/runners.bench.ts > runner
    1.00x faster than check on sync predicate not returning anything
    1.00x faster than assert on sync predicate returning true
    1.48x faster than assert on async predicate not returning anything

Benchmark report written to /home/runner/work/fast-check/fast-check/benchmark.json

Commit: 59dd849 (merge: a441d72)

@codecov

codecov Bot commented Jun 4, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.88%. Comparing base (dc9f32a) to head (59dd849).
⚠️ Report is 4 commits behind head on main.

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              
Flag Coverage Δ
tests 94.88% <100.00%> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread packages/fast-check/src/arbitrary/stringMatching.ts Outdated
dubzzz and others added 2 commits June 5, 2026 05:10
  Applied by GitHub Action workflow: PR Format
  Run ID: 26993052809
  Target PR: 7050
@dubzzz
dubzzz enabled auto-merge (squash) June 5, 2026 03:16
@dubzzz
dubzzz merged commit f3f1746 into main Jun 5, 2026
50 checks passed
@dubzzz
dubzzz deleted the claude/perf-stringMatching-set-membership branch June 5, 2026 03:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants