fix(lib/utils): simpler algorithm for removeDotSegments#140
fix(lib/utils): simpler algorithm for removeDotSegments#140Uzlopak merged 11 commits intofastify:mainfrom
Conversation
|
Nice! Can we run benchmarks on this branch vs main? |
Co-authored-by: Aras Abbasi <aras.abbasi@googlemail.com> Signed-off-by: Burkov Egor <xwooffie@gmail.com>
Co-authored-by: Aras Abbasi <aras.abbasi@googlemail.com> Signed-off-by: Burkov Egor <xwooffie@gmail.com>
Actually no changes across this branch/main cause benchmark don't use enought long url to see it, and function not used across all library calls. You can add benchmark suite: suite.add('fast-uri: serialize uri', function () {
fasturi.serialize({
scheme: 'uri',
userinfo: 'foo:bar',
host: 'example.com',
port: 1,
path: './a/./b/c/../.././d/../e/f/.././/',
query: 'query',
fragment: 'fragment'
})
})Results: |
Co-authored-by: Aras Abbasi <aras.abbasi@googlemail.com> Signed-off-by: Burkov Egor <xwooffie@gmail.com>
Detailsfunction removeDotSegments (path) {
let input = path
const output = []
let nextSlash = -1
let len = 0
while (len = input.length) {
if (len === 1) {
if (input === '.') {
break
} else if (input === '/') {
output.push('/')
break
} else {
output.push(input)
break
}
} else if (len === 2) {
if (input[0] === '.') {
if (input[1] === '.') {
break
} else if (input[1] === '/') {
input = input.slice(2)
continue
}
} else if (input[0] === '/') {
if (input[1] === '.' || input[1] === '/') {
output.push('/')
break
}
}
} else if (len === 3) {
if (input === '/..') {
if (output.length !== 0) {
output.pop()
}
output.push('/')
break
}
}
if (input[0] === '.') {
if (input[1] === '.') {
if (input[2] === '/') {
input = input.slice(3)
}
} else if (input[1] === '/') {
input = input.slice(2)
}
} else if (input[0] === '/') {
if (input[1] === '.') {
if (input[2] === '/') {
input = input.slice(2)
continue
} else if (input[2] === '.') {
if (input[3] === '/') {
input = input.slice(3)
if (output.length !== 0) {
output.pop()
}
continue
}
}
}
}
// Rule 2E: Move normal path segment to output
if ((nextSlash = input.indexOf('/', 1)) === -1) {
output.push(input)
break
} else {
output.push(input.slice(0, nextSlash))
input = input.slice(nextSlash)
}
}
return output.join('')
}this pr: aras@aras-HP-ZBook-15-G3:~/workspace/fast-uri$ node benchmark.js
fast-uri: serialize uri x 559,853 ops/sec ±1.13% (91 runs sampled)mine: aras@aras-HP-ZBook-15-G3:~/workspace/fast-uri$ node benchmark.js
fast-uri: serialize uri x 653,915 ops/sec ±1.55% (93 runs sampled) |
@wooffie if you can confirm these results, I'd suggest applying @Uzlopak's suggestion. I understand it might look a little worse but performance is a key part of the Fastify ecosystem, and besides I'm used to seeing code like this in URI specs Thanks again! |
|
Can you please add your benchmark to the suite? Then we can make a final comparison between main and pr ;) |
|
My results: fast-uri: serialize uri x 1,349,182 ops/sec ±6.04% (78 runs sampled)
urijs: serialize uri x 385,399 ops/sec ±2.95% (81 runs sampled)
fast-uri: serialize long uri with dots x 921,619 ops/sec ±3.07% (92 runs sampled)
urijs: serialize long uri with dots x 215,996 ops/sec ±0.49% (96 runs sampledurijs has more complexity to work with dots. |
|
Well, it is more like, not that the changes resulted in a regression in other cases. |
|
I dont see any regression. main: fast-uri: parse domain x 1,118,155 ops/sec ±2.26% (90 runs sampled)
urijs: parse domain x 332,608 ops/sec ±0.70% (90 runs sampled)
WHATWG URL: parse domain x 2,862,487 ops/sec ±0.61% (94 runs sampled)
fast-uri: parse IPv4 x 1,602,475 ops/sec ±0.94% (92 runs sampled)
urijs: parse IPv4 x 287,487 ops/sec ±0.79% (94 runs sampled)
fast-uri: parse IPv6 x 860,477 ops/sec ±0.51% (94 runs sampled)
urijs: parse IPv6 x 222,171 ops/sec ±1.23% (94 runs sampled)
fast-uri: parse URN x 1,737,473 ops/sec ±0.51% (95 runs sampled)
urijs: parse URN x 859,554 ops/sec ±0.49% (93 runs sampled)
WHATWG URL: parse URN x 3,475,550 ops/sec ±0.60% (91 runs sampled)
fast-uri: parse URN uuid x 1,074,608 ops/sec ±0.99% (95 runs sampled)
urijs: parse URN uuid x 616,849 ops/sec ±0.59% (94 runs sampled)
fast-uri: serialize uri x 949,836 ops/sec ±1.49% (94 runs sampled)
urijs: serialize uri x 264,787 ops/sec ±0.47% (95 runs sampled)
fast-uri: serialize long uri with dots x 218,870 ops/sec ±0.66% (95 runs sampled)
urijs: serialize long uri with dots x 132,720 ops/sec ±0.72% (94 runs sampled)
fast-uri: serialize IPv6 x 409,919 ops/sec ±2.59% (91 runs sampled)
urijs: serialize IPv6 x 193,344 ops/sec ±0.47% (96 runs sampled)
fast-uri: serialize ws x 1,002,939 ops/sec ±0.65% (95 runs sampled)
urijs: serialize ws x 263,285 ops/sec ±0.56% (95 runs sampled)
fast-uri: resolve x 303,951 ops/sec ±0.75% (91 runs sampled)
urijs: resolve x 159,221 ops/sec ±2.24% (92 runs sampled)PR: fast-uri: parse domain x 1,120,644 ops/sec ±1.12% (90 runs sampled)
urijs: parse domain x 324,418 ops/sec ±1.68% (94 runs sampled)
WHATWG URL: parse domain x 2,781,028 ops/sec ±1.01% (93 runs sampled)
fast-uri: parse IPv4 x 1,574,421 ops/sec ±0.92% (95 runs sampled)
urijs: parse IPv4 x 270,356 ops/sec ±1.00% (93 runs sampled)
fast-uri: parse IPv6 x 829,637 ops/sec ±0.78% (93 runs sampled)
urijs: parse IPv6 x 214,412 ops/sec ±0.77% (95 runs sampled)
fast-uri: parse URN x 1,694,760 ops/sec ±0.90% (92 runs sampled)
urijs: parse URN x 844,838 ops/sec ±0.72% (97 runs sampled)
WHATWG URL: parse URN x 3,428,778 ops/sec ±0.59% (93 runs sampled)
fast-uri: parse URN uuid x 1,080,123 ops/sec ±0.62% (95 runs sampled)
urijs: parse URN uuid x 614,282 ops/sec ±0.63% (94 runs sampled)
fast-uri: serialize uri x 1,137,299 ops/sec ±0.78% (95 runs sampled)
urijs: serialize uri x 260,947 ops/sec ±0.55% (95 runs sampled)
fast-uri: serialize long uri with dots x 634,818 ops/sec ±0.69% (95 runs sampled)
urijs: serialize long uri with dots x 126,910 ops/sec ±0.63% (95 runs sampled)
fast-uri: serialize IPv6 x 427,203 ops/sec ±0.75% (96 runs sampled)
urijs: serialize IPv6 x 192,218 ops/sec ±1.24% (94 runs sampled)
fast-uri: serialize ws x 1,218,515 ops/sec ±1.29% (95 runs sampled)
urijs: serialize ws x 246,424 ops/sec ±1.12% (95 runs sampled)
fast-uri: resolve x 473,679 ops/sec ±0.92% (94 runs sampled)
urijs: resolve x 161,916 ops/sec ±0.58% (94 runs sampled) |
|
But there is one question left: Is it still everything according to the RFC? :D. |
|
I wrote some more unit tests to ensure that the rfc is met...well it wasnt. I missed two I pushed into this PR. |
…n /studio [skip ci] Bumps [fast-uri](https://github.com/fastify/fast-uri) from 3.0.6 to 3.1.0. Release notes *Sourced from [fast-uri's releases](https://github.com/fastify/fast-uri/releases).* > v3.1.0 > ------ > > What's Changed > -------------- > > * ci: remove master branch support by [`@Fdawgs`](https://github.com/Fdawgs) in [fastify/fast-uri#126](https://redirect.github.com/fastify/fast-uri/pull/126) > * chore(test) remove .gitkeep by [`@Fdawgs`](https://github.com/Fdawgs) in [fastify/fast-uri#128](https://redirect.github.com/fastify/fast-uri/pull/128) > * ci(ci): set job permissions by [`@Fdawgs`](https://github.com/Fdawgs) in [fastify/fast-uri#129](https://redirect.github.com/fastify/fast-uri/pull/129) > * ci: set permissions at workflow level by [`@Fdawgs`](https://github.com/Fdawgs) in [fastify/fast-uri#131](https://redirect.github.com/fastify/fast-uri/pull/131) > * ci: set workflow permissions to read-only by default by [`@Fdawgs`](https://github.com/Fdawgs) in [fastify/fast-uri#132](https://redirect.github.com/fastify/fast-uri/pull/132) > * ci(ci): restore job level permissions by [`@Fdawgs`](https://github.com/Fdawgs) in [fastify/fast-uri#133](https://redirect.github.com/fastify/fast-uri/pull/133) > * build(deps-dev): bump tsd from 0.31.2 to 0.32.0 by [`@dependabot`](https://github.com/dependabot)[bot] in [fastify/fast-uri#134](https://redirect.github.com/fastify/fast-uri/pull/134) > * ci(ci): pin actions to commit-hash by [`@Fdawgs`](https://github.com/Fdawgs) in [fastify/fast-uri#135](https://redirect.github.com/fastify/fast-uri/pull/135) > * ci: add node 24 to test matrix by [`@Fdawgs`](https://github.com/Fdawgs) in [fastify/fast-uri#136](https://redirect.github.com/fastify/fast-uri/pull/136) > * ci: use tags for immutable github actions by [`@Fdawgs`](https://github.com/Fdawgs) in [fastify/fast-uri#137](https://redirect.github.com/fastify/fast-uri/pull/137) > * chore(license): update date ranges; standardise style by [`@Fdawgs`](https://github.com/Fdawgs) in [fastify/fast-uri#138](https://redirect.github.com/fastify/fast-uri/pull/138) > * fix(lib/utils): simpler algorithm for removeDotSegments by [`@wooffie`](https://github.com/wooffie) in [fastify/fast-uri#140](https://redirect.github.com/fastify/fast-uri/pull/140) > * chore: remove uri-js by [`@Uzlopak`](https://github.com/Uzlopak) in [fastify/fast-uri#142](https://redirect.github.com/fastify/fast-uri/pull/142) > * chore: replace benchmark with tinybench by [`@Uzlopak`](https://github.com/Uzlopak) in [fastify/fast-uri#143](https://redirect.github.com/fastify/fast-uri/pull/143) > * fix: ipv4 is never normalized by [`@Uzlopak`](https://github.com/Uzlopak) in [fastify/fast-uri#144](https://redirect.github.com/fastify/fast-uri/pull/144) > * feat: add browser testing by [`@Uzlopak`](https://github.com/Uzlopak) in [fastify/fast-uri#146](https://redirect.github.com/fastify/fast-uri/pull/146) > * Update README.md by [`@zekth`](https://github.com/zekth) in [fastify/fast-uri#145](https://redirect.github.com/fastify/fast-uri/pull/145) > * chore: use jsdoc for static code analysis by [`@Uzlopak`](https://github.com/Uzlopak) in [fastify/fast-uri#147](https://redirect.github.com/fastify/fast-uri/pull/147) > * fix(lib/schemes/urn): check nid for undefined by [`@wooffie`](https://github.com/wooffie) in [fastify/fast-uri#141](https://redirect.github.com/fastify/fast-uri/pull/141) > > New Contributors > ---------------- > > * [`@wooffie`](https://github.com/wooffie) made their first contribution in [fastify/fast-uri#140](https://redirect.github.com/fastify/fast-uri/pull/140) > > **Full Changelog**: <fastify/fast-uri@v3.0.6...v3.1.0> Commits * [`2d08e68`](fastify/fast-uri@2d08e68) v3.1.0 * [`4f8cdd1`](fastify/fast-uri@4f8cdd1) fix(lib/schemes/urn): check nid for undefined ([#141](https://redirect.github.com/fastify/fast-uri/issues/141)) * [`eedf840`](fastify/fast-uri@eedf840) chore: use jsdoc for static code analysis ([#147](https://redirect.github.com/fastify/fast-uri/issues/147)) * [`fbf4545`](fastify/fast-uri@fbf4545) Update README.md ([#145](https://redirect.github.com/fastify/fast-uri/issues/145)) * [`56b0c74`](fastify/fast-uri@56b0c74) feat: add browser testing ([#146](https://redirect.github.com/fastify/fast-uri/issues/146)) * [`ee22a06`](fastify/fast-uri@ee22a06) fix: ipv4 is never normalized ([#144](https://redirect.github.com/fastify/fast-uri/issues/144)) * [`509dd94`](fastify/fast-uri@509dd94) chore: replace benchmark with tinybench ([#143](https://redirect.github.com/fastify/fast-uri/issues/143)) * [`7a16582`](fastify/fast-uri@7a16582) chore: remove uri-js ([#142](https://redirect.github.com/fastify/fast-uri/issues/142)) * [`f0160b0`](fastify/fast-uri@f0160b0) fix(lib/utils): simpler algorithm for removeDotSegments ([#140](https://redirect.github.com/fastify/fast-uri/issues/140)) * [`14d12da`](fastify/fast-uri@14d12da) chore(license): update date ranges; standardise style ([#138](https://redirect.github.com/fastify/fast-uri/issues/138)) * Additional commits viewable in [compare view](fastify/fast-uri@v3.0.6...v3.1.0) [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) You can trigger a rebase of this PR by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- Dependabot commands and options You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) > \*\*Note\*\* > Automatic rebases have been disabled on this pull request as it has been open for over 30 days.
Replace regex to linear algorithm. This fixes issue with fatal error/out of range.
Closes #139
Checklist
npm run test && npm run benchmark --if-presentand the Code of conduct