Commit 73a3d79
authored
fix: optimize Range parsing and formatting (#726)
<!-- What / Why -->
<!-- Describe the request in detail. What it does and why it's being
changed. -->
This pull request optimizes the Range class in the following ways:
1. Produce fewer intermediate objects when reducing a range's space
characters to single spaces. This seems to improve bench-subset scores
by up to 5%, and bench-satisfies scores to a lesser degree.
2. Optimize Range formatting with explicit for loops instead, avoiding
an intermediate array creation. This seems to improve bench-satisfies
and bench-subset scores by up to 20%.
3. Calculate Range's `.range` string (used by `.format()` and
`.toString()`) lazily. This seems to improve bench-satisfies and
bench-subset scores by up to 9%.
The external interface for the class stays the same, except for the new
internal `.formatted` property used to cache its lazily calculated
string. `Range#range` property is now also read-only.
There is a new test lazy formatting to ensure full test coverage.
The benchmarks bench-satisfies and bench-subset benefit from these
changes, sometimes by up to 40%. Other benchmark results seem to stay
the same. Here are the affected benchmarks before:
```
$ node benchmarks/bench-satisfies.js
satisfies(1.0.6, 1.0.3||^2.0.0) x 695,094 ops/sec ±0.68% (97 runs sampled)
satisfies(1.0.6, 2.2.2||~3.0.0) x 764,115 ops/sec ±0.40% (99 runs sampled)
satisfies(1.0.6, 2.3.0||<4.0.0) x 805,593 ops/sec ±0.62% (97 runs sampled)
satisfies(1.0.6, 1.0.3||^2.0.0, {"includePrelease":true}) x 695,045 ops/sec ±0.73% (95 runs sampled)
satisfies(1.0.6, 2.2.2||~3.0.0, {"includePrelease":true}) x 750,433 ops/sec ±0.66% (99 runs sampled)
satisfies(1.0.6, 2.3.0||<4.0.0, {"includePrelease":true}) x 787,903 ops/sec ±0.39% (99 runs sampled)
satisfies(1.0.6, 1.0.3||^2.0.0, {"includePrelease":true,"loose":true}) x 652,166 ops/sec ±0.34% (99 runs sampled)
satisfies(1.0.6, 2.2.2||~3.0.0, {"includePrelease":true,"loose":true}) x 696,377 ops/sec ±0.36% (96 runs sampled)
satisfies(1.0.6, 2.3.0||<4.0.0, {"includePrelease":true,"loose":true}) x 721,729 ops/sec ±0.35% (98 runs sampled)
satisfies(1.0.6, 1.0.3||^2.0.0, {"includePrelease":true,"loose":true,"rtl":true}) x 585,692 ops/sec ±0.75% (95 runs sampled)
satisfies(1.0.6, 2.2.2||~3.0.0, {"includePrelease":true,"loose":true,"rtl":true}) x 631,653 ops/sec ±0.33% (96 runs sampled)
satisfies(1.0.6, 2.3.0||<4.0.0, {"includePrelease":true,"loose":true,"rtl":true}) x 650,110 ops/sec ±0.64% (95 runs sampled)
$ node benchmarks/bench-subset.js
subset(1.2.3, *) x 633,342 ops/sec ±0.61% (95 runs sampled)
subset(^1.2.3, *) x 743,036 ops/sec ±0.47% (97 runs sampled)
subset(^1.2.3-pre.0, *) x 680,087 ops/sec ±0.76% (98 runs sampled)
subset(^1.2.3-pre.0, *) x 680,948 ops/sec ±0.46% (96 runs sampled)
subset(1 || 2 || 3, *) x 330,669 ops/sec ±0.53% (98 runs sampled)
```
And after:
```
$ node benchmarks/bench-satisfies.js
satisfies(1.0.6, 1.0.3||^2.0.0) x 896,936 ops/sec ±0.53% (94 runs sampled)
satisfies(1.0.6, 2.2.2||~3.0.0) x 998,214 ops/sec ±0.40% (95 runs sampled)
satisfies(1.0.6, 2.3.0||<4.0.0) x 1,000,593 ops/sec ±0.43% (97 runs sampled)
satisfies(1.0.6, 1.0.3||^2.0.0, {"includePrelease":true}) x 890,369 ops/sec ±0.41% (100 runs sampled)
satisfies(1.0.6, 2.2.2||~3.0.0, {"includePrelease":true}) x 977,239 ops/sec ±0.48% (97 runs sampled)
satisfies(1.0.6, 2.3.0||<4.0.0, {"includePrelease":true}) x 983,682 ops/sec ±0.95% (96 runs sampled)
satisfies(1.0.6, 1.0.3||^2.0.0, {"includePrelease":true,"loose":true}) x 805,330 ops/sec ±0.84% (98 runs sampled)
satisfies(1.0.6, 2.2.2||~3.0.0, {"includePrelease":true,"loose":true}) x 894,117 ops/sec ±0.43% (99 runs sampled)
satisfies(1.0.6, 2.3.0||<4.0.0, {"includePrelease":true,"loose":true}) x 911,742 ops/sec ±0.42% (96 runs sampled)
satisfies(1.0.6, 1.0.3||^2.0.0, {"includePrelease":true,"loose":true,"rtl":true}) x 741,254 ops/sec ±0.35% (97 runs sampled)
satisfies(1.0.6, 2.2.2||~3.0.0, {"includePrelease":true,"loose":true,"rtl":true}) x 807,380 ops/sec ±0.42% (99 runs sampled)
satisfies(1.0.6, 2.3.0||<4.0.0, {"includePrelease":true,"loose":true,"rtl":true}) x 820,390 ops/sec ±0.37% (99 runs sampled)
$ node benchmarks/bench-subset.js
subset(1.2.3, *) x 905,030 ops/sec ±0.63% (96 runs sampled)
subset(^1.2.3, *) x 1,026,457 ops/sec ±0.63% (95 runs sampled)
subset(^1.2.3-pre.0, *) x 923,789 ops/sec ±0.41% (97 runs sampled)
subset(^1.2.3-pre.0, *) x 923,136 ops/sec ±0.44% (96 runs sampled)
subset(1 || 2 || 3, *) x 432,037 ops/sec ±0.67% (96 runs sampled)
```1 parent 2975ece commit 73a3d79
2 files changed
+33
-10
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
1 | 3 | | |
2 | 4 | | |
3 | 5 | | |
| |||
18 | 20 | | |
19 | 21 | | |
20 | 22 | | |
21 | | - | |
| 23 | + | |
22 | 24 | | |
23 | 25 | | |
24 | 26 | | |
| |||
29 | 31 | | |
30 | 32 | | |
31 | 33 | | |
32 | | - | |
33 | | - | |
34 | | - | |
35 | | - | |
| 34 | + | |
36 | 35 | | |
37 | 36 | | |
38 | 37 | | |
| |||
66 | 65 | | |
67 | 66 | | |
68 | 67 | | |
69 | | - | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
70 | 88 | | |
71 | 89 | | |
72 | 90 | | |
73 | | - | |
74 | | - | |
75 | | - | |
76 | | - | |
77 | 91 | | |
78 | 92 | | |
79 | 93 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
82 | 82 | | |
83 | 83 | | |
84 | 84 | | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
85 | 94 | | |
86 | 95 | | |
87 | 96 | | |
| |||
0 commit comments