{"action":"created","issue":{"url":"https://api.github.com/repos/dotnet/coreclr/issues/21766","repository_url":"https://api.github.com/repos/dotnet/coreclr","labels_url":"https://api.github.com/repos/dotnet/coreclr/issues/21766/labels{/name}","comments_url":"https://api.github.com/repos/dotnet/coreclr/issues/21766/comments","events_url":"https://api.github.com/repos/dotnet/coreclr/issues/21766/events","html_url":"https://github.com/dotnet/coreclr/pull/21766","id":395385277,"node_id":"MDExOlB1bGxSZXF1ZXN0MjQxODUxNDkx","number":21766,"title":"Improve performance of Path.ChangeExtension","user":{"login":"stephentoub","id":2642209,"node_id":"MDQ6VXNlcjI2NDIyMDk=","avatar_url":"https://avatars0.githubusercontent.com/u/2642209?v=4","gravatar_id":"","url":"https://api.github.com/users/stephentoub","html_url":"https://github.com/stephentoub","followers_url":"https://api.github.com/users/stephentoub/followers","following_url":"https://api.github.com/users/stephentoub/following{/other_user}","gists_url":"https://api.github.com/users/stephentoub/gists{/gist_id}","starred_url":"https://api.github.com/users/stephentoub/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stephentoub/subscriptions","organizations_url":"https://api.github.com/users/stephentoub/orgs","repos_url":"https://api.github.com/users/stephentoub/repos","events_url":"https://api.github.com/users/stephentoub/events{/privacy}","received_events_url":"https://api.github.com/users/stephentoub/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":5,"created_at":"2019-01-02T21:24:33Z","updated_at":"2019-01-03T16:11:35Z","closed_at":null,"author_association":"MEMBER","pull_request":{"url":"https://api.github.com/repos/dotnet/coreclr/pulls/21766","html_url":"https://github.com/dotnet/coreclr/pull/21766","diff_url":"https://github.com/dotnet/coreclr/pull/21766.diff","patch_url":"https://github.com/dotnet/coreclr/pull/21766.patch"},"body":"In the common case where it need to replace a non-empty extension with a non-empty extension, it currently incurs a substring without the original extension prior to then concatenating with the new extension.  This PR avoids that.\r\n\r\n(As the `Path` implementation is in corelib, this uses `string.FastAllocateString` and then formats into it with a span; if we wanted to avoid that, `string.Create` could also be used.  That could also be addressed with new `String.Concat` overloads that accept `ReadOnlySpan<char>`s.)\r\n\r\nBenchmark:\r\n```C#\r\n[Benchmark] public string ChangeExtensionReplace() => Path.ChangeExtension(@\"c:\\this\\is\\a\\path\\hello.txt\", \".dat\");\r\n[Benchmark] public string ChangeExtensionRemove() => Path.ChangeExtension(@\"c:\\this\\is\\a\\path\\hello.txt\", null);\r\n```\r\n\r\nBefore:\r\n```\r\n                 Method |     Mean |     Error |    StdDev |  Gen 0 | Allocated |\r\n----------------------- |---------:|----------:|----------:|-------:|----------:|\r\n ChangeExtensionReplace | 41.39 ns | 1.4013 ns | 2.7985 ns | 0.0363 |     152 B |\r\n  ChangeExtensionRemove | 18.57 ns | 0.2763 ns | 0.2449 ns | 0.0172 |      72 B |\r\n```\r\n\r\nAfter:\r\n```\r\n                 Method |     Mean |     Error |    StdDev |  Gen 0 | Allocated |\r\n----------------------- |---------:|----------:|----------:|-------:|----------:|\r\n ChangeExtensionReplace | 18.66 ns | 0.1989 ns | 0.1764 ns | 0.0191 |      80 B |\r\n  ChangeExtensionRemove | 18.81 ns | 0.2678 ns | 0.2505 ns | 0.0172 |      72 B |\r\n```\r\n\r\ncc: @JeremyKuhne, @jkotas"},"comment":{"url":"https://api.github.com/repos/dotnet/coreclr/issues/comments/451191431","html_url":"https://github.com/dotnet/coreclr/pull/21766#issuecomment-451191431","issue_url":"https://api.github.com/repos/dotnet/coreclr/issues/21766","id":451191431,"node_id":"MDEyOklzc3VlQ29tbWVudDQ1MTE5MTQzMQ==","user":{"login":"stephentoub","id":2642209,"node_id":"MDQ6VXNlcjI2NDIyMDk=","avatar_url":"https://avatars0.githubusercontent.com/u/2642209?v=4","gravatar_id":"","url":"https://api.github.com/users/stephentoub","html_url":"https://github.com/stephentoub","followers_url":"https://api.github.com/users/stephentoub/followers","following_url":"https://api.github.com/users/stephentoub/following{/other_user}","gists_url":"https://api.github.com/users/stephentoub/gists{/gist_id}","starred_url":"https://api.github.com/users/stephentoub/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stephentoub/subscriptions","organizations_url":"https://api.github.com/users/stephentoub/orgs","repos_url":"https://api.github.com/users/stephentoub/repos","events_url":"https://api.github.com/users/stephentoub/events{/privacy}","received_events_url":"https://api.github.com/users/stephentoub/received_events","type":"User","site_admin":false},"created_at":"2019-01-03T16:11:35Z","updated_at":"2019-01-03T16:11:35Z","author_association":"MEMBER","body":"I added String.Concat overloads for spans, utilized them in a few places in corelib (including in Path.ChangeExtension), and opened https://github.com/dotnet/corefx/issues/34330 to make the methods public."}}
{"actor":{"display_login":"stephentoub"}}