Use IndexOfAny/SearchValues in more places around Uri#124433
Use IndexOfAny/SearchValues in more places around Uri#124433MihaZupan merged 4 commits intodotnet:mainfrom
Conversation
|
Tagging subscribers to this area: @karelz, @dotnet/ncl |
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
BenchmarkSwitcher.FromAssembly(typeof(Bench).Assembly).Run(args);
public class Bench
{
private string _noUserInfoShortHost = default!;
private string _noUserInfoLongHost = default!;
private string _withUserInfoShortHost = default!;
private string _withUserInfoLongHost = default!;
private string _basicHostShortPath = default!;
private string _basicHostLongPath = default!;
private Uri _baseUri = default!;
private string _relativeWithScheme = default!;
private string _relativeNoScheme = default!;
[GlobalSetup]
public void Setup()
{
_noUserInfoShortHost = "http://host/path";
_noUserInfoLongHost = "http://" + new string('a', 64) + ".example.com/path";
_withUserInfoShortHost = "http://user:pass@host/path";
_withUserInfoLongHost = "http://user:pass@" + new string('a', 64) + ".example.com/path";
_basicHostShortPath = "myscheme://host/path";
_basicHostLongPath = "myscheme://" + new string('a', 64) + ".example.com/path?query#fragment";
_baseUri = new Uri("http://base.example.com/basepath/");
_relativeWithScheme = "http://other.example.com/otherpath";
_relativeNoScheme = "relative/path?query#fragment";
UriParser.Register(new GenericUriParser(GenericUriParserOptions.Default), "myscheme", -1);
}
[Benchmark]
public Uri NoUserInfo_ShortHost() => new Uri(_noUserInfoShortHost);
[Benchmark]
public Uri NoUserInfo_LongHost() => new Uri(_noUserInfoLongHost);
[Benchmark]
public Uri WithUserInfo_ShortHost() => new Uri(_withUserInfoShortHost);
[Benchmark]
public Uri WithUserInfo_LongHost() => new Uri(_withUserInfoLongHost);
[Benchmark]
public Uri BasicHost_ShortPath() => new Uri(_basicHostShortPath);
[Benchmark]
public Uri BasicHost_LongPath() => new Uri(_basicHostLongPath);
[Benchmark]
public Uri CombinedString_WithScheme() => new Uri(_baseUri, _relativeWithScheme);
[Benchmark]
public Uri CombinedString_NoScheme() => new Uri(_baseUri, _relativeNoScheme);
} |
There was a problem hiding this comment.
Pull request overview
This pull request optimizes URI parsing by replacing character-by-character loops with SearchValues.IndexOfAny for improved performance when searching for delimiters. The changes focus on three key areas of URI parsing: scheme detection in relative URIs, user info parsing in authority components, and basic hostname end detection.
Changes:
- Replaces manual loop with
IndexOfAnyfor finding scheme delimiters in relative URI resolution - Introduces
SearchValuesfor user info end characters and refactors user info parsing logic - Simplifies basic hostname end detection using
IndexOfAnyinstead of manual iteration
| break; | ||
| var vsb = new ValueStringBuilder(stackalloc char[StackallocThreshold]); | ||
| IriHelper.EscapeUnescapeIri(ref vsb, slice.Slice(0, userInfoLength), isQuery: false); | ||
| newHost = string.Concat(newHost, vsb.AsSpan()); |
There was a problem hiding this comment.
We could put newHost in vsb first.
There was a problem hiding this comment.
Yes, we'd just be copying the original newHost around an extra time in that case. We do this sort of thing in more places to avoid copying the prefix again.
In the long term my hope is that this substring allocation will get removed anyway and we'd only allocate the new _string once.
EgorBot/runtime-utils#618 (comment)
https://github.com/dotnet/runtime/pull/124433/changes?w=1