Skip to content

perf(isFloat): cache the compiled regex instead of rebuilding it per call - #2847

Open
cesco69 wants to merge 1 commit into
validatorjs:masterfrom
cesco69:perf/cache-isfloat-regex
Open

perf(isFloat): cache the compiled regex instead of rebuilding it per call#2847
cesco69 wants to merge 1 commit into
validatorjs:masterfrom
cesco69:perf/cache-isfloat-regex

Conversation

@cesco69

@cesco69 cesco69 commented Aug 11, 2026

Copy link
Copy Markdown

perf(isFloat): cache the compiled regex instead of rebuilding it per call

What

isFloat builds a RegExp on every invocation:

const float = new RegExp(`^(?:[-+])?(?:[0-9]+)?(?:\\${options.locale ? decimal[options.locale] : '.'}[0-9]*)?(?:[eE][\\+\\-]?(?:[0-9]+))?$`);

The pattern only varies with the decimal separator, which comes from the fixed decimal
locale table. This PR caches the compiled regexes by separator.

isInt.js, right next to it, already hoists its two regexes to module scope. This brings
isFloat in line with that.

Why it matters

isFloat is not only called directly: toFloat calls it internally too.

// toFloat.js
export default function toFloat(str) {
  if (!isFloat(str)) return NaN;
  return parseFloat(str);
}

So a caller that validates and then converts — a very common pairing — compiles the same
pattern twice per value.

Measurements

Node 26, best of 5 rounds, 500k calls per measurement, inputs ['42','3.14','-17','1e10','0','999999','-0.5','12345']:

ns/call ops/s
current (new RegExp per call) 271 3,685,288
this PR (cached) 136 7,362,859

2.0x faster.

Downstream effect, measured on tsoa, which calls both
isFloat and toFloat for every numeric request parameter — one route with two numeric
parameters, per request:

ns/request
current 2253
with this PR 343

That is 85% of the cost of tsoa's argument validation, removed by this one change.

Correctness

  • The pattern is built from the same template literal, so the compiled regex is identical.
  • The regex has no g flag, so there is no lastIndex state to share between calls.
  • Equivalence checked on: 42 -42 +42 0 3.14 -3.14 .5 5. 1e10 1E-10 '' . , - + abc 1,5 0x10 Infinity NaN '1 ' ' 1' 1.2.3 --1 1e ++ 1e+ 12345678901234567890 -0 1.0e5 .e5 +.5 -.5 e5 — no divergence.
  • npm test: 323 passing.
  • npx eslint src/lib/isFloat.js: clean.

Reproducing

bench/isfloat.mjs in this PR description's companion file, run with node --expose-gc.

…call

isFloat built a new RegExp on every invocation. The pattern only varies with the
decimal separator, which comes from the fixed set of locales, so the compiled
regexes are now cached by separator.

isInt already hoists its regexes to module scope; this brings isFloat in line.

Behaviour is unchanged: the pattern is built from the same template literal, and
the existing test suite passes.
@codecov

codecov Bot commented Aug 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (cdb7daf) to head (010387c).

Additional details and impacted files
@@            Coverage Diff            @@
##            master     #2847   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files          114       114           
  Lines         2599      2606    +7     
  Branches       658       659    +1     
=========================================
+ Hits          2599      2606    +7     

☔ 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.

@rubiin
rubiin requested review from WikiRik, pano9000 and tux-tn August 15, 2026 19:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants