Use string.Create in ConvertFromUtf32 (dotnet/coreclr#21409)
authorStephen Toub <stoub@microsoft.com>
Sat, 8 Dec 2018 04:49:29 +0000 (23:49 -0500)
committerJan Kotas <jkotas@microsoft.com>
Sat, 8 Dec 2018 04:49:29 +0000 (20:49 -0800)
* Use string.Create in ConvertFromUtf32

Removes the unsafe code from the method.  Also happens to make it a bit faster.

* Improve Rune.ToString performance

Commit migrated from https://github.com/dotnet/coreclr/commit/ca60cf7c507e73f3bb28de0f7781b201a66cf8d2

src/libraries/System.Private.CoreLib/src/System/Char.cs
src/libraries/System.Private.CoreLib/src/System/String.cs
src/libraries/System.Private.CoreLib/src/System/Text/Rune.cs

index e6ce2fd..1312380 100644 (file)
@@ -15,6 +15,7 @@
 using System.Diagnostics;
 using System.Globalization;
 using System.Runtime.InteropServices;
+using System.Text;
 
 namespace System
 {
@@ -921,29 +922,12 @@ namespace System
 
         public static string ConvertFromUtf32(int utf32)
         {
-            // For UTF32 values from U+00D800 ~ U+00DFFF, we should throw.  They
-            // are considered as irregular code unit sequence, but they are not illegal.
-            if (((uint)utf32 > UNICODE_PLANE16_END) || (utf32 >= CharUnicodeInfo.HIGH_SURROGATE_START && utf32 <= CharUnicodeInfo.LOW_SURROGATE_END))
+            if (!UnicodeUtility.IsValidUnicodeScalar((uint)utf32))
             {
                 throw new ArgumentOutOfRangeException(nameof(utf32), SR.ArgumentOutOfRange_InvalidUTF32);
             }
 
-            if (utf32 < UNICODE_PLANE01_START)
-            {
-                // This is a BMP character.
-                return (char.ToString((char)utf32));
-            }
-
-            unsafe
-            {
-                // This is a supplementary character.  Convert it to a surrogate pair in UTF-16.
-                utf32 -= UNICODE_PLANE01_START;
-                uint surrogate = 0; // allocate 2 chars worth of stack space
-                char* address = (char*)&surrogate;
-                address[0] = (char)((utf32 / 0x400) + (int)CharUnicodeInfo.HIGH_SURROGATE_START);
-                address[1] = (char)((utf32 % 0x400) + (int)CharUnicodeInfo.LOW_SURROGATE_START);
-                return new string(address, 0, 2);
-            }
+            return Rune.UnsafeCreate((uint)utf32).ToString();
         }
 
 
index 366b678..ea8b5e3 100644 (file)
@@ -11,6 +11,7 @@ using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using System.Runtime.Versioning;
 using System.Text;
+using Internal.Runtime.CompilerServices;
 
 namespace System
 {
@@ -499,6 +500,14 @@ namespace System
             return result;
         }
 
+        internal static string CreateFromChar(char c1, char c2)
+        {
+            string result = FastAllocateString(2);
+            result._firstChar = c1;
+            Unsafe.Add(ref result._firstChar, 1) = c2;
+            return result;
+        }
+
         internal static unsafe void wstrcpy(char* dmem, char* smem, int charCount)
         {
             Buffer.Memmove((byte*)dmem, (byte*)smem, ((uint)charCount) * 2);
index 7de9c2d..74aecbe 100644 (file)
@@ -335,8 +335,15 @@ namespace System.Text
         /// </summary>
         public override string ToString()
         {
-            Span<char> chars = stackalloc char[2]; // worst case
-            return new string(chars.Slice(0, EncodeToUtf16(chars)));
+            if (IsBmp)
+            {
+                return string.CreateFromChar((char)_value);
+            }
+            else
+            {
+                UnicodeUtility.GetUtf16SurrogatesFromSupplementaryPlaneScalar(_value, out char high, out char low);
+                return string.CreateFromChar(high, low);
+            }
         }
 
         /// <summary>