{"action":"created","comment":{"url":"https://api.github.com/repos/dotnet/corefx/pulls/comments/152032364","pull_request_review_id":77826492,"id":152032364,"diff_hunk":"@@ -0,0 +1,184 @@\n+// Licensed to the .NET Foundation under one or more agreements.\n+// The .NET Foundation licenses this file to you under the MIT license.\n+// See the LICENSE file in the project root for more information.\n+\n+using System.Buffers;\n+using System.Diagnostics;\n+using System.Runtime.CompilerServices;\n+\n+namespace System.Text\n+{\n+    internal ref struct ValueStringBuilder\n+    {\n+        private char[] _arrayToReturnToPool;\n+        private Span<char> _chars;\n+        private int _pos;\n+\n+        public ValueStringBuilder(Span<char> initialBuffer)\n+        {\n+            _arrayToReturnToPool = null;\n+            _chars = initialBuffer;\n+            _pos = 0;\n+        }\n+\n+        public int Length => _pos;\n+\n+        public override string ToString()\n+        {\n+            var s = new string(_chars.Slice(0, _pos));\n+            Clear();\n+            return s;\n+        }\n+\n+        public bool TryCopyTo(Span<char> destination, out int charsWritten)\n+        {\n+            if (_chars.Slice(0, _pos).TryCopyTo(destination))\n+            {\n+                charsWritten = _pos;\n+                Clear();\n+                return true;\n+            }\n+            else\n+            {\n+                charsWritten = 0;\n+                return false;\n+            }\n+        }\n+\n+        public void Insert(int index, char value, int count)\n+        {\n+            if (_pos > _chars.Length - count)\n+            {\n+                Grow(count);\n+            }\n+\n+            int remaining = _pos - index;\n+            _chars.Slice(index, remaining).CopyTo(_chars.Slice(index + count));\n+            _chars.Slice(index, count).Fill(value);\n+            _pos += count;\n+        }\n+\n+        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n+        public void Append(char c)\n+        {\n+            int pos = _pos;\n+            if (pos < _chars.Length)\n+            {\n+                _chars[pos] = c;\n+                _pos = pos + 1;\n+            }\n+            else\n+            {\n+                GrowAndAppend(c);\n+            }\n+        }\n+\n+        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n+        public void Append(string s)\n+        {\n+            int pos = _pos;\n+            if (s.Length == 1 && pos < _chars.Length) // very common case, e.g. appending strings from NumberFormatInfo like separators, percent symbols, etc.\n+            {\n+                _chars[pos] = s[0];\n+                _pos = pos + 1;\n+            }\n+            else\n+            {\n+                AppendSlow(s);\n+            }\n+        }\n+\n+        private void AppendSlow(string s)\n+        {\n+            int pos = _pos;\n+            if (pos > _chars.Length - s.Length)\n+            {\n+                Grow(s.Length);\n+            }\n+\n+            bool copied = s.AsReadOnlySpan().TryCopyTo(_chars.Slice(pos));\n+            Debug.Assert(copied, \"Grow should have made enough room to successfully copy\");\n+            _pos += s.Length;\n+        }\n+\n+        public void Append(char c, int count)\n+        {\n+            if (_pos > _chars.Length - count)\n+            {\n+                Grow(count);\n+            }\n+\n+            Span<char> dst = _chars.Slice(_pos, count);\n+            for (int i = 0; i < dst.Length; i++)\n+            {\n+                dst[i] = c;\n+            }\n+            _pos += count;\n+        }\n+\n+        public unsafe void Append(char* value, int length)\n+        {\n+            int pos = _pos;\n+            if (pos > _chars.Length - length)\n+            {\n+                Grow(length);\n+            }\n+\n+            Span<char> dst = _chars.Slice(_pos, length);\n+            for (int i = 0; i < dst.Length; i++)\n+            {\n+                dst[i] = *value++;\n+            }\n+            _pos += length;\n+        }\n+\n+        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n+        public Span<char> AppendSpan(int length)\n+        {\n+            int origPos = _pos;\n+            if (origPos > _chars.Length - length)\n+            {\n+                Grow(length);\n+            }\n+\n+            _pos = origPos + length;\n+            return _chars.Slice(origPos, length);\n+        }\n+\n+        [MethodImpl(MethodImplOptions.NoInlining)]\n+        private void GrowAndAppend(char c)\n+        {\n+            Grow(1);\n+            Append(c);\n+        }\n+\n+        [MethodImpl(MethodImplOptions.NoInlining)]\n+        private void Grow(int requiredAdditionalCapacity)\n+        {\n+            Debug.Assert(requiredAdditionalCapacity > _chars.Length - _pos);\n+\n+            char[] poolArray = ArrayPool<char>.Shared.Rent(Math.Max(_pos + requiredAdditionalCapacity, _chars.Length * 2));\n+\n+            bool success = _chars.TryCopyTo(poolArray);\n+            Debug.Assert(success);\n+\n+            char[] toReturn = _arrayToReturnToPool;\n+            _chars = _arrayToReturnToPool = poolArray;\n+            if (toReturn != null)\n+            {\n+                ArrayPool<char>.Shared.Return(toReturn);","path":"src/Common/src/System/Text/ValueStringBuilder.cs","position":169,"original_position":169,"commit_id":"27a1327499f826d8ad63e8fba23f86fd811e697d","original_commit_id":"27a1327499f826d8ad63e8fba23f86fd811e697d","user":{"login":"bartonjs","id":10642668,"avatar_url":"https://avatars3.githubusercontent.com/u/10642668?v=4","gravatar_id":"","url":"https://api.github.com/users/bartonjs","html_url":"https://github.com/bartonjs","followers_url":"https://api.github.com/users/bartonjs/followers","following_url":"https://api.github.com/users/bartonjs/following{/other_user}","gists_url":"https://api.github.com/users/bartonjs/gists{/gist_id}","starred_url":"https://api.github.com/users/bartonjs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bartonjs/subscriptions","organizations_url":"https://api.github.com/users/bartonjs/orgs","repos_url":"https://api.github.com/users/bartonjs/repos","events_url":"https://api.github.com/users/bartonjs/events{/privacy}","received_events_url":"https://api.github.com/users/bartonjs/received_events","type":"User","site_admin":false},"body":"Do we have guidelines on clearing things before returning?  In System.Security.Cryptography the answer is \"always clear\"; but I can appreciate that I have to be more defensive than the general case.","created_at":"2017-11-20T16:00:44Z","updated_at":"2017-11-20T16:05:25Z","html_url":"https://github.com/dotnet/corefx/pull/25353#discussion_r152032364","pull_request_url":"https://api.github.com/repos/dotnet/corefx/pulls/25353","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/dotnet/corefx/pulls/comments/152032364"},"html":{"href":"https://github.com/dotnet/corefx/pull/25353#discussion_r152032364"},"pull_request":{"href":"https://api.github.com/repos/dotnet/corefx/pulls/25353"}}},"pull_request":{"url":"https://api.github.com/repos/dotnet/corefx/pulls/25353","id":153514079,"html_url":"https://github.com/dotnet/corefx/pull/25353","diff_url":"https://github.com/dotnet/corefx/pull/25353.diff","patch_url":"https://github.com/dotnet/corefx/pull/25353.patch","issue_url":"https://api.github.com/repos/dotnet/corefx/issues/25353","number":25353,"state":"open","locked":false,"title":"Improve performance of BigInteger.ToString(\"x\")","user":{"login":"stephentoub","id":2642209,"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},"body":"Benchmark:\r\n```C#\r\nusing System;\r\nusing System.Numerics;\r\nusing BenchmarkDotNet.Attributes.Jobs;\r\nusing BenchmarkDotNet.Attributes;\r\nusing BenchmarkDotNet.Running;\r\n\r\n[MemoryDiagnoser]\r\n[InProcess]\r\npublic class Program\r\n{\r\n    public static void Main() => BenchmarkRunner.Run<Program>();\r\n\r\n    private static BigInteger s_smallBigInt = new BigInteger(100);\r\n    private static BigInteger s_largeBigInt = BigInteger.Parse(new string('9', 2000));\r\n\r\n    [Benchmark]\r\n    public void BigIntegerToString_Small()\r\n    {\r\n        BigInteger small = s_smallBigInt;\r\n        for (int i = 0; i < 100_000; i++) small.ToString(\"x\");\r\n    }\r\n\r\n    [Benchmark]\r\n    public void BigIntegerToString_Large()\r\n    {\r\n        BigInteger large = s_largeBigInt;\r\n        for (int i = 0; i < 1_000; i++) large.ToString(\"x\");\r\n    }\r\n}\r\n```\r\n\r\nBefore:\r\n```\r\n |                   Method |     Mean |     Error |    StdDev |     Gen 0 | Allocated |\r\n |------------------------- |---------:|----------:|----------:|----------:|----------:|\r\n | BigIntegerToString_Small | 20.01 ms | 0.4187 ms | 0.6519 ms | 6843.7500 |  27.47 MB |\r\n | BigIntegerToString_Large | 29.62 ms | 0.3435 ms | 0.3045 ms | 8468.7500 |  33.91 MB |\r\n```\r\n\r\nAfter:\r\n```\r\n |                   Method |     Mean |     Error |    StdDev |     Gen 0 | Allocated |\r\n |------------------------- |---------:|----------:|----------:|----------:|----------:|\r\n | BigIntegerToString_Small | 9.445 ms | 0.1153 ms | 0.0834 ms |  750.0000 |   3.05 MB |\r\n | BigIntegerToString_Large | 3.946 ms | 0.0603 ms | 0.0534 ms | 1000.0000 |   4.01 MB |\r\n```\r\n\r\nSo for this small value, an ~2x throughput improvement, and for this large value, an ~8x throughput improvement, and for both, an ~9x reduction in allocation.\r\n\r\ncc: @bartonjs ","created_at":"2017-11-19T20:32:44Z","updated_at":"2017-11-20T16:05:25Z","closed_at":null,"merged_at":null,"merge_commit_sha":"216919fab193987e912acd597241b1be339e990b","assignee":null,"assignees":[],"requested_reviewers":[],"milestone":null,"commits_url":"https://api.github.com/repos/dotnet/corefx/pulls/25353/commits","review_comments_url":"https://api.github.com/repos/dotnet/corefx/pulls/25353/comments","review_comment_url":"https://api.github.com/repos/dotnet/corefx/pulls/comments{/number}","comments_url":"https://api.github.com/repos/dotnet/corefx/issues/25353/comments","statuses_url":"https://api.github.com/repos/dotnet/corefx/statuses/27a1327499f826d8ad63e8fba23f86fd811e697d","head":{"label":"stephentoub:biginteger_tryformat","ref":"biginteger_tryformat","sha":"27a1327499f826d8ad63e8fba23f86fd811e697d","user":{"login":"stephentoub","id":2642209,"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},"repo":{"id":26551529,"name":"corefx","full_name":"stephentoub/corefx","owner":{"login":"stephentoub","id":2642209,"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},"private":false,"html_url":"https://github.com/stephentoub/corefx","description":"This repository contains the foundational libraries that make up the .NET Core development stack.","fork":true,"url":"https://api.github.com/repos/stephentoub/corefx","forks_url":"https://api.github.com/repos/stephentoub/corefx/forks","keys_url":"https://api.github.com/repos/stephentoub/corefx/keys{/key_id}","collaborators_url":"https://api.github.com/repos/stephentoub/corefx/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/stephentoub/corefx/teams","hooks_url":"https://api.github.com/repos/stephentoub/corefx/hooks","issue_events_url":"https://api.github.com/repos/stephentoub/corefx/issues/events{/number}","events_url":"https://api.github.com/repos/stephentoub/corefx/events","assignees_url":"https://api.github.com/repos/stephentoub/corefx/assignees{/user}","branches_url":"https://api.github.com/repos/stephentoub/corefx/branches{/branch}","tags_url":"https://api.github.com/repos/stephentoub/corefx/tags","blobs_url":"https://api.github.com/repos/stephentoub/corefx/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/stephentoub/corefx/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/stephentoub/corefx/git/refs{/sha}","trees_url":"https://api.github.com/repos/stephentoub/corefx/git/trees{/sha}","statuses_url":"https://api.github.com/repos/stephentoub/corefx/statuses/{sha}","languages_url":"https://api.github.com/repos/stephentoub/corefx/languages","stargazers_url":"https://api.github.com/repos/stephentoub/corefx/stargazers","contributors_url":"https://api.github.com/repos/stephentoub/corefx/contributors","subscribers_url":"https://api.github.com/repos/stephentoub/corefx/subscribers","subscription_url":"https://api.github.com/repos/stephentoub/corefx/subscription","commits_url":"https://api.github.com/repos/stephentoub/corefx/commits{/sha}","git_commits_url":"https://api.github.com/repos/stephentoub/corefx/git/commits{/sha}","comments_url":"https://api.github.com/repos/stephentoub/corefx/comments{/number}","issue_comment_url":"https://api.github.com/repos/stephentoub/corefx/issues/comments{/number}","contents_url":"https://api.github.com/repos/stephentoub/corefx/contents/{+path}","compare_url":"https://api.github.com/repos/stephentoub/corefx/compare/{base}...{head}","merges_url":"https://api.github.com/repos/stephentoub/corefx/merges","archive_url":"https://api.github.com/repos/stephentoub/corefx/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/stephentoub/corefx/downloads","issues_url":"https://api.github.com/repos/stephentoub/corefx/issues{/number}","pulls_url":"https://api.github.com/repos/stephentoub/corefx/pulls{/number}","milestones_url":"https://api.github.com/repos/stephentoub/corefx/milestones{/number}","notifications_url":"https://api.github.com/repos/stephentoub/corefx/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/stephentoub/corefx/labels{/name}","releases_url":"https://api.github.com/repos/stephentoub/corefx/releases{/id}","deployments_url":"https://api.github.com/repos/stephentoub/corefx/deployments","created_at":"2014-11-12T19:06:24Z","updated_at":"2016-10-22T10:27:30Z","pushed_at":"2017-11-20T15:21:21Z","git_url":"git://github.com/stephentoub/corefx.git","ssh_url":"git@github.com:stephentoub/corefx.git","clone_url":"https://github.com/stephentoub/corefx.git","svn_url":"https://github.com/stephentoub/corefx","homepage":"","size":155236,"stargazers_count":2,"watchers_count":2,"language":"C#","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":2,"default_branch":"master"}},"base":{"label":"dotnet:master","ref":"master","sha":"0eb5e7451028e9374b8bb03972aa945c128193e1","user":{"login":"dotnet","id":9141961,"avatar_url":"https://avatars0.githubusercontent.com/u/9141961?v=4","gravatar_id":"","url":"https://api.github.com/users/dotnet","html_url":"https://github.com/dotnet","followers_url":"https://api.github.com/users/dotnet/followers","following_url":"https://api.github.com/users/dotnet/following{/other_user}","gists_url":"https://api.github.com/users/dotnet/gists{/gist_id}","starred_url":"https://api.github.com/users/dotnet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dotnet/subscriptions","organizations_url":"https://api.github.com/users/dotnet/orgs","repos_url":"https://api.github.com/users/dotnet/repos","events_url":"https://api.github.com/users/dotnet/events{/privacy}","received_events_url":"https://api.github.com/users/dotnet/received_events","type":"Organization","site_admin":false},"repo":{"id":26295345,"name":"corefx","full_name":"dotnet/corefx","owner":{"login":"dotnet","id":9141961,"avatar_url":"https://avatars0.githubusercontent.com/u/9141961?v=4","gravatar_id":"","url":"https://api.github.com/users/dotnet","html_url":"https://github.com/dotnet","followers_url":"https://api.github.com/users/dotnet/followers","following_url":"https://api.github.com/users/dotnet/following{/other_user}","gists_url":"https://api.github.com/users/dotnet/gists{/gist_id}","starred_url":"https://api.github.com/users/dotnet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dotnet/subscriptions","organizations_url":"https://api.github.com/users/dotnet/orgs","repos_url":"https://api.github.com/users/dotnet/repos","events_url":"https://api.github.com/users/dotnet/events{/privacy}","received_events_url":"https://api.github.com/users/dotnet/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/dotnet/corefx","description":"This repo contains the .NET Core foundational libraries, called CoreFX. It includes classes for collections, file systems, console, XML, async and many others. We welcome contributions.","fork":false,"url":"https://api.github.com/repos/dotnet/corefx","forks_url":"https://api.github.com/repos/dotnet/corefx/forks","keys_url":"https://api.github.com/repos/dotnet/corefx/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dotnet/corefx/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dotnet/corefx/teams","hooks_url":"https://api.github.com/repos/dotnet/corefx/hooks","issue_events_url":"https://api.github.com/repos/dotnet/corefx/issues/events{/number}","events_url":"https://api.github.com/repos/dotnet/corefx/events","assignees_url":"https://api.github.com/repos/dotnet/corefx/assignees{/user}","branches_url":"https://api.github.com/repos/dotnet/corefx/branches{/branch}","tags_url":"https://api.github.com/repos/dotnet/corefx/tags","blobs_url":"https://api.github.com/repos/dotnet/corefx/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dotnet/corefx/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dotnet/corefx/git/refs{/sha}","trees_url":"https://api.github.com/repos/dotnet/corefx/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dotnet/corefx/statuses/{sha}","languages_url":"https://api.github.com/repos/dotnet/corefx/languages","stargazers_url":"https://api.github.com/repos/dotnet/corefx/stargazers","contributors_url":"https://api.github.com/repos/dotnet/corefx/contributors","subscribers_url":"https://api.github.com/repos/dotnet/corefx/subscribers","subscription_url":"https://api.github.com/repos/dotnet/corefx/subscription","commits_url":"https://api.github.com/repos/dotnet/corefx/commits{/sha}","git_commits_url":"https://api.github.com/repos/dotnet/corefx/git/commits{/sha}","comments_url":"https://api.github.com/repos/dotnet/corefx/comments{/number}","issue_comment_url":"https://api.github.com/repos/dotnet/corefx/issues/comments{/number}","contents_url":"https://api.github.com/repos/dotnet/corefx/contents/{+path}","compare_url":"https://api.github.com/repos/dotnet/corefx/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dotnet/corefx/merges","archive_url":"https://api.github.com/repos/dotnet/corefx/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dotnet/corefx/downloads","issues_url":"https://api.github.com/repos/dotnet/corefx/issues{/number}","pulls_url":"https://api.github.com/repos/dotnet/corefx/pulls{/number}","milestones_url":"https://api.github.com/repos/dotnet/corefx/milestones{/number}","notifications_url":"https://api.github.com/repos/dotnet/corefx/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dotnet/corefx/labels{/name}","releases_url":"https://api.github.com/repos/dotnet/corefx/releases{/id}","deployments_url":"https://api.github.com/repos/dotnet/corefx/deployments","created_at":"2014-11-06T23:42:48Z","updated_at":"2017-11-20T14:37:20Z","pushed_at":"2017-11-20T16:00:26Z","git_url":"git://github.com/dotnet/corefx.git","ssh_url":"git@github.com:dotnet/corefx.git","clone_url":"https://github.com/dotnet/corefx.git","svn_url":"https://github.com/dotnet/corefx","homepage":"https://github.com/dotnet/core","size":161767,"stargazers_count":12883,"watchers_count":12883,"language":"C#","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":3606,"mirror_url":null,"archived":false,"open_issues_count":2189,"forks":3606,"open_issues":2189,"watchers":12883,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/dotnet/corefx/pulls/25353"},"html":{"href":"https://github.com/dotnet/corefx/pull/25353"},"issue":{"href":"https://api.github.com/repos/dotnet/corefx/issues/25353"},"comments":{"href":"https://api.github.com/repos/dotnet/corefx/issues/25353/comments"},"review_comments":{"href":"https://api.github.com/repos/dotnet/corefx/pulls/25353/comments"},"review_comment":{"href":"https://api.github.com/repos/dotnet/corefx/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/dotnet/corefx/pulls/25353/commits"},"statuses":{"href":"https://api.github.com/repos/dotnet/corefx/statuses/27a1327499f826d8ad63e8fba23f86fd811e697d"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"bartonjs"}}