Use IndexOfAnyValues in CoreLib (#78678)
authorMiha Zupan <mihazupan.zupan1@gmail.com>
Tue, 22 Nov 2022 19:33:50 +0000 (19:33 +0000)
committerGitHub <noreply@github.com>
Tue, 22 Nov 2022 19:33:50 +0000 (11:33 -0800)
* Use IndexOfAnyValues in CoreLib

* Avoid the init overhead of IndexOfAnyValues in string

src/coreclr/System.Private.CoreLib/src/System/TypeNameParser.cs
src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs

index 851f1d5..2df15e8 100644 (file)
@@ -1,6 +1,7 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
+using System.Buffers;
 using System.Diagnostics;
 using System.Diagnostics.CodeAnalysis;
 using System.IO;
@@ -88,7 +89,8 @@ namespace System
 
         #region Private Data Members
         private readonly SafeTypeNameParserHandle m_NativeParser;
-        private static readonly char[] SPECIAL_CHARS = { ',', '[', ']', '&', '*', '+', '\\' }; /* see typeparse.h */
+        private const string SpecialChars = ",[]&*+\\"; // see typeparse.h
+        private static readonly IndexOfAnyValues<char> s_specialChars = IndexOfAnyValues.Create(SpecialChars);
         #endregion
 
         #region Constructor and Disposer
@@ -276,13 +278,18 @@ namespace System
 
         private static string EscapeTypeName(string name)
         {
-            if (name.IndexOfAny(SPECIAL_CHARS) < 0)
+            int specialCharIndex = name.AsSpan().IndexOfAny(s_specialChars);
+            if (specialCharIndex < 0)
+            {
                 return name;
+            }
 
             var sb = new ValueStringBuilder(stackalloc char[64]);
-            foreach (char c in name)
+            sb.Append(name.AsSpan(0, specialCharIndex));
+
+            foreach (char c in name.AsSpan(specialCharIndex))
             {
-                if (Array.IndexOf<char>(SPECIAL_CHARS, c) >= 0)
+                if (SpecialChars.Contains(c))
                     sb.Append('\\');
 
                 sb.Append(c);
index 58a2a92..264acfb 100644 (file)
@@ -17,6 +17,17 @@ namespace System
 {
     public partial class String
     {
+        // Avoid paying the init cost of all the IndexOfAnyValues unless they are actually used.
+        private static class IndexOfAnyValuesStorage
+        {
+            // The Unicode Standard, Sec. 5.8, Recommendation R4 and Table 5-2 state that the CR, LF,
+            // CRLF, NEL, LS, FF, and PS sequences are considered newline functions. That section
+            // also specifically excludes VT from the list of newline functions, so we do not include
+            // it in the needle list.
+            public static readonly IndexOfAnyValues<char> NewLineChars =
+                IndexOfAnyValues.Create("\r\n\f\u0085\u2028\u2029");
+        }
+
         private const int StackallocIntBufferSizeLimit = 128;
 
         private static void FillStringChecked(string dest, int destPos, string src)
@@ -1233,16 +1244,9 @@ namespace System
             // the haystack; or O(n) if no needle is found. This ensures that in the common case
             // of this method being called within a loop, the worst-case runtime is O(n) rather than
             // O(n^2), where n is the length of the input text.
-            //
-            // The Unicode Standard, Sec. 5.8, Recommendation R4 and Table 5-2 state that the CR, LF,
-            // CRLF, NEL, LS, FF, and PS sequences are considered newline functions. That section
-            // also specifically excludes VT from the list of newline functions, so we do not include
-            // it in the needle list.
-
-            const string needles = "\r\n\f\u0085\u2028\u2029";
 
             stride = default;
-            int idx = text.IndexOfAny(needles);
+            int idx = text.IndexOfAny(IndexOfAnyValuesStorage.NewLineChars);
             if ((uint)idx < (uint)text.Length)
             {
                 stride = 1; // needle found