-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Fix CompareTo/Equals when dealing with Empty Span or Span wrapping a null string #17115
Conversation
@@ -181,6 +181,8 @@ internal static unsafe int LastIndexOfOrdinalCore(string source, string value, i | |||
private static unsafe int CompareStringOrdinalIgnoreCase(char* string1, int count1, char* string2, int count2) | |||
{ | |||
Debug.Assert(!GlobalizationMode.Invariant); | |||
Debug.Assert(string1 != null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The asserts in this file are unnecessary. The Unix globalizations API handle NULL with zero-sized buffer just fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(You can keep them if you would like though.)
@@ -393,13 +393,33 @@ internal int Compare(ReadOnlySpan<char> string1, string string2, CompareOptions | |||
|
|||
internal virtual int CompareOptionNone(ReadOnlySpan<char> string1, ReadOnlySpan<char> string2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
virtual
is not necessary here. You can remove it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(It will be more efficient without it.)
} | ||
if (string2.IsEmpty) | ||
return 1; | ||
|
||
return _invariantMode ? | ||
string.CompareOrdinal(string1, string2) : | ||
CompareString(string1, string2, CompareOptions.None); | ||
} | ||
|
||
internal virtual int CompareOptionIgnoreCase(ReadOnlySpan<char> string1, ReadOnlySpan<char> string2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here. Virtual is unnecessary.
@@ -895,12 +917,16 @@ public unsafe virtual int IndexOf(string source, string value, int startIndex, i | |||
internal virtual int IndexOfOrdinal(ReadOnlySpan<char> source, ReadOnlySpan<char> value, bool ignoreCase) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Virtual is unnecessary.
I think it is pretty questionable behavior. I would consider it a design bug. I am not sure whether we want to be replicating it... |
@@ -393,13 +393,33 @@ internal int Compare(ReadOnlySpan<char> string1, string string2, CompareOptions | |||
|
|||
internal virtual int CompareOptionNone(ReadOnlySpan<char> string1, ReadOnlySpan<char> string2) | |||
{ | |||
// Check for empty span or span from a null string | |||
if (string1.IsEmpty) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can just do this as:
if (span.Length == 0 || string2.Length == 0)
return string1.Length - string2.Length;
It is how the same check is done in MemoryExtensions.Fast.cs.
@@ -895,12 +917,16 @@ public unsafe virtual int IndexOf(string source, string value, int startIndex, i | |||
internal virtual int IndexOfOrdinal(ReadOnlySpan<char> source, ReadOnlySpan<char> value, bool ignoreCase) | |||
{ | |||
Debug.Assert(!_invariantMode); | |||
Debug.Assert(!source.IsEmpty); | |||
Debug.Assert(!value.IsEmpty); | |||
return IndexOfOrdinalCore(source, value, ignoreCase); | |||
} | |||
|
|||
internal unsafe virtual int IndexOf(ReadOnlySpan<char> source, ReadOnlySpan<char> value, CompareOptions options) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
virtual is unnecessary.
@dotnet-bot test Windows_NT arm Cross Checked corefx_baseline Build and Test |
@dotnet-bot test Tizen armel Cross Checked Innerloop Build and Test |
length == 0
and addressing them ahead of time. Resolved based on the discussion in https://github.com/dotnet/corefx/issues/27350.From https://msdn.microsoft.com/en-us/library/d4tt83f9(v=vs.110).aspx
Added tests in corefx: dotnet/corefx#28347
cc @KrzysztofCwalina, @jkotas, @tarekgh, @stephentoub, @joshfree, @VSadov