// Search/Query methods
//
- private static unsafe bool EqualsHelper(String strA, String strB)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static bool EqualsHelper(String strA, String strB)
{
Debug.Assert(strA != null);
Debug.Assert(strB != null);
Debug.Assert(strA.Length == strB.Length);
- int length = strA.Length;
-
- fixed (char* ap = &strA._firstChar) fixed (char* bp = &strB._firstChar)
- {
- char* a = ap;
- char* b = bp;
-
-#if BIT64
- // Single int read aligns pointers for the following long reads
- // PERF: No length check needed as there is always an int32 worth of string allocated
- // This read can also include the null terminator which both strings will have
- if (*(int*)a != *(int*)b) return false;
- length -= 2; a += 2; b += 2;
-
- // for AMD64 bit platform we unroll by 12 and
- // check 3 qword at a time. This is less code
- // than the 32 bit case and is a shorter path length.
-
- while (length >= 12)
- {
- if (*(long*)a != *(long*)b) return false;
- if (*(long*)(a + 4) != *(long*)(b + 4)) return false;
- if (*(long*)(a + 8) != *(long*)(b + 8)) return false;
- length -= 12; a += 12; b += 12;
- }
-#else
- while (length >= 10)
- {
- if (*(int*)a != *(int*)b) return false;
- if (*(int*)(a + 2) != *(int*)(b + 2)) return false;
- if (*(int*)(a + 4) != *(int*)(b + 4)) return false;
- if (*(int*)(a + 6) != *(int*)(b + 6)) return false;
- if (*(int*)(a + 8) != *(int*)(b + 8)) return false;
- length -= 10; a += 10; b += 10;
- }
-#endif
-
- // This depends on the fact that the String objects are
- // always zero terminated and that the terminating zero is not included
- // in the length. For odd string sizes, the last compare will include
- // the zero terminator.
- while (length > 0)
- {
- if (*(int*)a != *(int*)b) return false;
- length -= 2; a += 2; b += 2;
- }
-
- return true;
- }
+ return SpanHelpers.SequenceEqual(
+ ref Unsafe.As<char, byte>(ref strA.GetRawStringData()),
+ ref Unsafe.As<char, byte>(ref strB.GetRawStringData()),
+ ((nuint)strA.Length) * 2);
}
private static unsafe bool EqualsIgnoreCaseAsciiHelper(String strA, String strB)
}
}
- private static unsafe bool StartsWithOrdinalHelper(String str, String startsWith)
- {
- Debug.Assert(str != null);
- Debug.Assert(startsWith != null);
- Debug.Assert(str.Length >= startsWith.Length);
-
- int length = startsWith.Length;
-
- fixed (char* ap = &str._firstChar)
- fixed (char* bp = &startsWith._firstChar)
- {
- char* a = ap;
- char* b = bp;
-
-#if BIT64
- // Single int read aligns pointers for the following long reads
- // No length check needed as this method is called when length >= 2
- Debug.Assert(length >= 2);
- if (*(int*)a != *(int*)b)
- return false;
- length -= 2;
- a += 2;
- b += 2;
-
- while (length >= 12)
- {
- if (*(long*)a != *(long*)b)
- return false;
- if (*(long*)(a + 4) != *(long*)(b + 4))
- return false;
- if (*(long*)(a + 8) != *(long*)(b + 8))
- return false;
- length -= 12;
- a += 12;
- b += 12;
- }
-#else
- while (length >= 10)
- {
- if (*(int*)a != *(int*)b) return false;
- if (*(int*)(a+2) != *(int*)(b+2)) return false;
- if (*(int*)(a+4) != *(int*)(b+4)) return false;
- if (*(int*)(a+6) != *(int*)(b+6)) return false;
- if (*(int*)(a+8) != *(int*)(b+8)) return false;
- length -= 10; a += 10; b += 10;
- }
-#endif
-
- while (length >= 2)
- {
- if (*(int*)a != *(int*)b)
- return false;
- length -= 2;
- a += 2;
- b += 2;
- }
-
- // PERF: This depends on the fact that the String objects are always zero terminated
- // and that the terminating zero is not included in the length. For even string sizes
- // this compare can include the zero terminator. Bitwise OR avoids a branch.
- return length == 0 | *a == *b;
- }
- }
-
private static unsafe int CompareOrdinalHelper(String strA, String strB)
{
Debug.Assert(strA != null);
}
return (value.Length == 1) ?
true : // First char is the same and thats all there is to compare
- StartsWithOrdinalHelper(this, value);
+ SpanHelpers.SequenceEqual(
+ ref Unsafe.As<char, byte>(ref this.GetRawStringData()),
+ ref Unsafe.As<char, byte>(ref value.GetRawStringData()),
+ ((nuint)value.Length) * 2);
case StringComparison.OrdinalIgnoreCase:
if (this.Length < value.Length)