Reduce allocation in Index/Range.ToString (#21755)
authorStephen Toub <stoub@microsoft.com>
Thu, 3 Jan 2019 20:07:57 +0000 (15:07 -0500)
committerGitHub <noreply@github.com>
Thu, 3 Jan 2019 20:07:57 +0000 (15:07 -0500)
* Reduce allocation in Index/Range.ToString

* Address PR feedback

src/System.Private.CoreLib/shared/System/Index.cs
src/System.Private.CoreLib/shared/System/Range.cs

index 29be7e4..887506e 100644 (file)
@@ -2,6 +2,8 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+using System.Diagnostics;
+
 namespace System
 {
     public readonly struct Index : IEquatable<Index>
@@ -28,10 +30,15 @@ namespace System
             return _value;
         }
 
-        public override string ToString()
+        public override string ToString() => FromEnd ? ToStringFromEnd() : ((uint)Value).ToString();
+
+        private string ToStringFromEnd()
         {
-            string str = Value.ToString();
-            return FromEnd ? "^" + str : str;
+            Span<char> span = stackalloc char[11]; // 1 for ^ and 10 for longest possible uint value
+            bool formatted = ((uint)Value).TryFormat(span.Slice(1), out int charsWritten);
+            Debug.Assert(formatted);
+            span[0] = '^';
+            return new string(span.Slice(0, charsWritten + 1));
         }
 
         public static implicit operator Index(int value)
index c03cf34..b858da2 100644 (file)
@@ -2,6 +2,8 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+using System.Diagnostics;
+
 namespace System
 {
     public readonly struct Range : IEquatable<Range>
@@ -35,7 +37,31 @@ namespace System
 
         public override string ToString()
         {
-            return Start + ".." + End;
+            Span<char> span = stackalloc char[2 + (2 * 11)]; // 2 for "..", then for each index 1 for '^' and 10 for longest possible uint
+            int charsWritten;
+            int pos = 0;
+
+            if (Start.FromEnd)
+            {
+                span[0] = '^';
+                pos = 1;
+            }
+            bool formatted = ((uint)Start.Value).TryFormat(span.Slice(pos), out charsWritten);
+            Debug.Assert(formatted);
+            pos += charsWritten;
+
+            span[pos++] = '.';
+            span[pos++] = '.';
+
+            if (End.FromEnd)
+            {
+                span[pos++] = '^';
+            }
+            formatted = ((uint)End.Value).TryFormat(span.Slice(pos), out charsWritten);
+            Debug.Assert(formatted);
+            pos += charsWritten;
+
+            return new string(span.Slice(0, pos));
         }
 
         public static Range Create(Index start, Index end) => new Range(start, end);