Clean up Uri.UnescapeDataString (dotnet/corefx#42225)
authorStephen Toub <stoub@microsoft.com>
Thu, 31 Oct 2019 00:00:25 +0000 (20:00 -0400)
committerGitHub <noreply@github.com>
Thu, 31 Oct 2019 00:00:25 +0000 (20:00 -0400)
- Use string.IndexOf rather than an open-coded, unsafe loop.
- Avoid an unnecessary SequenceEquals at the end: we're only at this point if a `%` was found highlighting that something escaped was found.
- Use stack memory for smaller inputs if possible, to avoid unnecessary ArrayPool interaction
- Remove an unnecessary argument to a helper function.
- Fix ValueStringBuilder.Grow to only copy the contained data.

Commit migrated from https://github.com/dotnet/corefx/commit/04f79d96e8ce89e738e7f8f595f43a52e9cdd4a4

src/libraries/System.Private.Uri/src/System/UriExt.cs
src/libraries/System.Private.Uri/src/System/UriHelper.cs

index 9fc6bd5..321b008 100644 (file)
@@ -546,30 +546,21 @@ namespace System
             if (stringToUnescape.Length == 0)
                 return string.Empty;
 
-            unsafe
-            {
-                fixed (char* pStr = stringToUnescape)
-                {
-                    int position;
-                    for (position = 0; position < stringToUnescape.Length; ++position)
-                        if (pStr[position] == '%')
-                            break;
-
-                    if (position == stringToUnescape.Length)
-                        return stringToUnescape;
-
-                    UnescapeMode unescapeMode = UnescapeMode.Unescape | UnescapeMode.UnescapeAll;
-                    position = 0;
-                    ValueStringBuilder vsb = new ValueStringBuilder(stringToUnescape.Length);
-                    UriHelper.UnescapeString(stringToUnescape, 0, stringToUnescape.Length, ref vsb, ref position,
-                        c_DummyChar, c_DummyChar, c_DummyChar, unescapeMode, null, false);
-
-                    ReadOnlySpan<char> resultSpan = vsb.AsSpan(0, position);
-                    string result = resultSpan.SequenceEqual(stringToUnescape) ? stringToUnescape : resultSpan.ToString();
-                    vsb.Dispose();
-                    return result;
-                }
-            }
+            int position = stringToUnescape.IndexOf('%');
+            if (position == -1)
+                return stringToUnescape;
+
+            var vsb = new ValueStringBuilder(stackalloc char[256]);
+            vsb.EnsureCapacity(stringToUnescape.Length);
+
+            vsb.Append(stringToUnescape.AsSpan(0, position));
+            UriHelper.UnescapeString(
+                stringToUnescape, position, stringToUnescape.Length, ref vsb,
+                c_DummyChar, c_DummyChar, c_DummyChar,
+                UnescapeMode.Unescape | UnescapeMode.UnescapeAll,
+                syntax: null, isQuery: false);
+
+            return vsb.ToString();
         }
 
         // Where stringToEscape is intended to be a completely unescaped URI string.
index 3bfb7b9..c903f47 100644 (file)
@@ -342,14 +342,11 @@ namespace System
         //   For this reason it returns a char[] that is usually the same ref as the input "dest" value.
         //
         internal static unsafe void UnescapeString(string input, int start, int end, ref ValueStringBuilder dest,
-            ref int destPosition, char rsvd1, char rsvd2, char rsvd3, UnescapeMode unescapeMode, UriParser? syntax,
-            bool isQuery)
+            char rsvd1, char rsvd2, char rsvd3, UnescapeMode unescapeMode, UriParser? syntax, bool isQuery)
         {
             fixed (char* pStr = input)
             {
-                UnescapeString(pStr, start, end, ref dest, rsvd1, rsvd2, rsvd3, unescapeMode,
-                    syntax, isQuery);
-                destPosition = dest.Length;
+                UnescapeString(pStr, start, end, ref dest, rsvd1, rsvd2, rsvd3, unescapeMode, syntax, isQuery);
             }
         }
         internal static unsafe void UnescapeString(char* pStr, int start, int end, ref ValueStringBuilder dest,