Replace easy Substrings with AsSpan/Slices (#17916)
authorStephen Toub <stoub@microsoft.com>
Thu, 10 May 2018 01:36:19 +0000 (21:36 -0400)
committerGitHub <noreply@github.com>
Thu, 10 May 2018 01:36:19 +0000 (21:36 -0400)
* Replace several Substrings with AsSpan/Slices

* Address PR feedback

src/System.Private.CoreLib/shared/System/Globalization/TextInfo.cs
src/System.Private.CoreLib/shared/System/Reflection/AssemblyNameFormatter.cs
src/System.Private.CoreLib/shared/System/Reflection/Module.cs
src/System.Private.CoreLib/shared/System/TimeZoneInfo.Unix.cs
src/System.Private.CoreLib/shared/System/Type.Helpers.cs
src/System.Private.CoreLib/shared/System/Type.cs
src/System.Private.CoreLib/src/System/AppContext/AppContextDefaultValues.cs

index 183f02c..4906bed 100644 (file)
@@ -809,11 +809,20 @@ namespace System.Globalization
         {
             Debug.Assert(charLen == 1 || charLen == 2, "[TextInfo.AddTitlecaseLetter] CharUnicodeInfo.InternalGetUnicodeCategory returned an unexpected charLen!");
 
-            // for surrogate pairs do a simple ToUpper operation on the substring
             if (charLen == 2)
             {
-                // Surrogate pair
-                result.Append(ToUpper(input.Substring(inputIndex, charLen)));
+                // for surrogate pairs do a ToUpper operation on the substring
+                ReadOnlySpan<char> src = input.AsSpan(inputIndex, 2);
+                if (_invariantMode)
+                {
+                    result.Append(src); // surrogate pair in invariant mode, so changing case is a nop
+                }
+                else
+                {
+                    Span<char> dst = stackalloc char[2];
+                    ChangeCase(src, dst, toUpper: true);
+                    result.Append(dst);
+                }
                 inputIndex++;
             }
             else
index 716afb0..90ccd1f 100644 (file)
@@ -111,8 +111,7 @@ namespace System.Reflection
                         continue;
                     if ((s.Length - i) < escapeReplacement.Length)
                         continue;
-                    string prefix = s.Substring(i, escapeReplacement.Length);
-                    if (prefix == escapeReplacement)
+                    if (s.AsSpan(i, escapeReplacement.Length).SequenceEqual(escapeReplacement))
                     {
                         sb.Append('\\');
                         sb.Append(kv.Key);
index 56f83c4..d290f78 100644 (file)
@@ -130,53 +130,29 @@ namespace System.Reflection
 
         public override string ToString() => ScopeName;
 
-        public static readonly TypeFilter FilterTypeName = FilterTypeNameImpl;
-        public static readonly TypeFilter FilterTypeNameIgnoreCase = FilterTypeNameIgnoreCaseImpl;
+        public static readonly TypeFilter FilterTypeName = (m, c) => FilterTypeNameImpl(m, c, StringComparison.Ordinal);
+        public static readonly TypeFilter FilterTypeNameIgnoreCase = (m, c) => FilterTypeNameImpl(m, c, StringComparison.OrdinalIgnoreCase);
 
         private const BindingFlags DefaultLookup = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
 
         // FilterTypeName 
         // This method will filter the class based upon the name.  It supports
         //    a trailing wild card.
-        private static bool FilterTypeNameImpl(Type cls, object filterCriteria)
+        private static bool FilterTypeNameImpl(Type cls, object filterCriteria, StringComparison comparison)
         {
             // Check that the criteria object is a String object
-            if (filterCriteria == null || !(filterCriteria is string))
-                throw new InvalidFilterCriteriaException(SR.InvalidFilterCriteriaException_CritString);
-
-            string str = (string)filterCriteria;
-
-            // Check to see if this is a prefix or exact match requirement
-            if (str.Length > 0 && str[str.Length - 1] == '*')
+            if (!(filterCriteria is string str))
             {
-                str = str.Substring(0, str.Length - 1);
-                return cls.Name.StartsWith(str, StringComparison.Ordinal);
-            }
-
-            return cls.Name.Equals(str);
-        }
-
-        // FilterFieldNameIgnoreCase
-        // This method filter the Type based upon name, it ignores case.
-        private static bool FilterTypeNameIgnoreCaseImpl(Type cls, object filterCriteria)
-        {
-            // Check that the criteria object is a String object
-            if (filterCriteria == null || !(filterCriteria is string))
                 throw new InvalidFilterCriteriaException(SR.InvalidFilterCriteriaException_CritString);
-
-            string str = (string)filterCriteria;
-
+            }
             // Check to see if this is a prefix or exact match requirement
             if (str.Length > 0 && str[str.Length - 1] == '*')
             {
-                str = str.Substring(0, str.Length - 1);
-                string name = cls.Name;
-                if (name.Length >= str.Length)
-                    return (string.Compare(name, 0, str, 0, str.Length, StringComparison.OrdinalIgnoreCase) == 0);
-                else
-                    return false;
+                ReadOnlySpan<char> slice = str.AsSpan(0, str.Length - 1);
+                return cls.Name.AsSpan().StartsWith(slice, comparison);
             }
-            return (string.Compare(str, cls.Name, StringComparison.OrdinalIgnoreCase) == 0);
+
+            return cls.Name.Equals(str, comparison);
         }
     }
 }
index 920131d..a91e602 100644 (file)
@@ -1079,16 +1079,16 @@ namespace System
             return null;
         }
 
-        private static TimeSpan? TZif_ParseOffsetString(string offset)
+        private static TimeSpan? TZif_ParseOffsetString(ReadOnlySpan<char> offset)
         {
             TimeSpan? result = null;
 
-            if (!string.IsNullOrEmpty(offset))
+            if (offset.Length > 0)
             {
                 bool negative = offset[0] == '-';
                 if (negative || offset[0] == '+')
                 {
-                    offset = offset.Substring(1);
+                    offset = offset.Slice(1);
                 }
 
                 // Try parsing just hours first.
index db8df23..3de7d82 100644 (file)
@@ -473,54 +473,31 @@ namespace System
         // This method will filter based upon the name.  A partial wildcard
         //  at the end of the string is supported.
         //  filterCriteria -- This is the string name
-        private static bool FilterNameImpl(MemberInfo m, object filterCriteria)
+        private static bool FilterNameImpl(MemberInfo m, object filterCriteria, StringComparison comparison)
         {
             // Check that the criteria object is a String object
-            if (filterCriteria == null || !(filterCriteria is string))
+            if (!(filterCriteria is string filterCriteriaString))
+            {
                 throw new InvalidFilterCriteriaException(SR.InvalidFilterCriteriaException_CritString);
+            }
 
-            // At the moment this fails if its done on a single line....
-            string str = ((string)filterCriteria);
-            str = str.Trim();
+            ReadOnlySpan<char> str = filterCriteriaString.AsSpan().Trim();
+            ReadOnlySpan<char> name = m.Name;
 
-            string name = m.Name;
             // Get the nested class name only, as opposed to the mangled one
             if (m.MemberType == MemberTypes.NestedType)
-                name = name.Substring(name.LastIndexOf('+') + 1);
-            // Check to see if this is a prefix or exact match requirement
-            if (str.Length > 0 && str[str.Length - 1] == '*')
             {
-                str = str.Substring(0, str.Length - 1);
-                return (name.StartsWith(str, StringComparison.Ordinal));
+                name = name.Slice(name.LastIndexOf('+') + 1);
             }
 
-            return (name.Equals(str));
-        }
-
-        // FilterIgnoreCase
-        // This delegate will do a name search but does it with the
-        //  ignore case specified.
-        private static bool FilterNameIgnoreCaseImpl(MemberInfo m, object filterCriteria)
-        {
-            // Check that the criteria object is a String object
-            if (filterCriteria == null || !(filterCriteria is string))
-                throw new InvalidFilterCriteriaException(SR.InvalidFilterCriteriaException_CritString);
-
-            string str = (string)filterCriteria;
-            str = str.Trim();
-
-            string name = m.Name;
-            // Get the nested class name only, as opposed to the mangled one
-            if (m.MemberType == MemberTypes.NestedType)
-                name = name.Substring(name.LastIndexOf('+') + 1);
             // Check to see if this is a prefix or exact match requirement
             if (str.Length > 0 && str[str.Length - 1] == '*')
             {
-                str = str.Substring(0, str.Length - 1);
-                return (string.Compare(name, 0, str, 0, str.Length, StringComparison.OrdinalIgnoreCase) == 0);
+                str = str.Slice(0, str.Length - 1);
+                return name.StartsWith(str, comparison);
             }
 
-            return (string.Compare(str, name, StringComparison.OrdinalIgnoreCase) == 0);
+            return name.Equals(str, comparison);
         }
     }
 }
index b57baa8..79f6b6f 100644 (file)
@@ -387,8 +387,8 @@ namespace System
         public static readonly object Missing = System.Reflection.Missing.Value;
 
         public static readonly MemberFilter FilterAttribute = FilterAttributeImpl;
-        public static readonly MemberFilter FilterName = FilterNameImpl;
-        public static readonly MemberFilter FilterNameIgnoreCase = FilterNameIgnoreCaseImpl;
+        public static readonly MemberFilter FilterName = (m, c) => FilterNameImpl(m, c, StringComparison.Ordinal);
+        public static readonly MemberFilter FilterNameIgnoreCase = (m, c) => FilterNameImpl(m, c, StringComparison.OrdinalIgnoreCase);
 
         private const BindingFlags DefaultLookup = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
     }
index 320a141..2388784 100644 (file)
@@ -110,11 +110,9 @@ namespace System
                     versionFound = true;
 
                     // Allow the version to include a 'v' or 'V' prefix...
-                    if (value.Length > 0 && (value[0] == c_versionValuePrefix || value[0] == 'V'))
-                    {
-                        value = value.Substring(1);
-                    }
-                    Version realVersion = Version.Parse(value);
+                    Version realVersion = value.Length > 0 && (value[0] == c_versionValuePrefix || value[0] == 'V') ?
+                        Version.Parse(value.AsSpan(1)) :
+                        Version.Parse(value);
                     // The version class will represent some unset values as -1 internally (instead of 0).
                     version = realVersion.Major * 10000;
                     if (realVersion.Minor > 0)