Improve string.Equals OrdinalIgnoreCase performance for matching chars (dotnet/corecl...
authorBruce Bowyer-Smyth <bbowyersmyth@live.com.au>
Tue, 21 Feb 2017 17:25:18 +0000 (03:25 +1000)
committerDan Moseley <danmose@microsoft.com>
Tue, 21 Feb 2017 17:25:18 +0000 (09:25 -0800)
* Improve string.Equals OrdinalIgnoreCase performance for matching chars

* Added code comment

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

src/coreclr/src/mscorlib/src/System/String.Comparison.cs

index dda0bd6..970d107 100644 (file)
@@ -133,6 +133,48 @@ namespace System
             }
         }
 
+        private unsafe static bool EqualsIgnoreCaseAsciiHelper(String strA, String strB)
+        {
+            Contract.Requires(strA != null);
+            Contract.Requires(strB != null);
+            Contract.Requires(strA.Length == strB.Length);
+            Contract.EndContractBlock();
+            int length = strA.Length;
+
+            fixed (char* ap = &strA.m_firstChar) fixed (char* bp = &strB.m_firstChar)
+            {
+                char* a = ap;
+                char* b = bp;
+
+                while (length != 0)
+                {
+                    int charA = *a;
+                    int charB = *b;
+
+                    Debug.Assert((charA | charB) <= 0x7F, "strings have to be ASCII");
+
+                    // Ordinal equals or lowercase equals if the result ends up in the a-z range 
+                    if (charA == charB ||
+                       ((charA | 0x20) == (charB | 0x20) &&
+                          (uint)((charA | 0x20) - 'a') <= (uint)('z' - 'a')))
+                    {
+                        a++;
+                        b++;
+                        length--;
+                    }
+                    else
+                    {
+                        goto ReturnFalse;
+                    }
+                }
+
+                return true;
+
+                ReturnFalse:
+                return false;
+            }
+        }
+
         private unsafe static bool StartsWithOrdinalHelper(String str, String startsWith)
         {
             Contract.Requires(str != null);
@@ -865,7 +907,7 @@ namespace System
 
                     // If both strings are ASCII strings, we can take the fast path.
                     if (this.IsAscii() && value.IsAscii()) {
-                        return (CompareOrdinalIgnoreCaseHelper(this, value) == 0);
+                        return EqualsIgnoreCaseAsciiHelper(this, value);
                     }
 
 #if FEATURE_COREFX_GLOBALIZATION
@@ -934,7 +976,7 @@ namespace System
                     else {
                         // If both strings are ASCII strings, we can take the fast path.
                         if (a.IsAscii() && b.IsAscii()) {
-                            return (CompareOrdinalIgnoreCaseHelper(a, b) == 0);
+                            return EqualsIgnoreCaseAsciiHelper(a, b);
                         }
                         // Take the slow path.