Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
address code review and API review feedback
  • Loading branch information
adamsitnik committed Apr 21, 2023
commit d72e89b3c510bac6b6d553bfe2b7565b8d9713d0
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,15 @@ public static bool Equals(ReadOnlySpan<byte> left, ReadOnlySpan<char> right)
{
for (int i = 0; i < right.Length; i++)
{
char c = right[i];
byte b = left[i];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we care about the bound check here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we've already confirmed left.Length == right.Length above, I think we're OK without another bounds check here.

char c = right[i];

if (c != b)
if (b != c)
{
return false;
}

if (!UnicodeUtility.IsAsciiCodePoint(c) || !UnicodeUtility.IsAsciiCodePoint(b))
if (!UnicodeUtility.IsAsciiCodePoint((uint)(b | c)))
{
return false;
}
Expand All @@ -58,16 +58,16 @@ public static bool Equals(ReadOnlySpan<byte> left, ReadOnlySpan<char> right)
// Loop until either we've finished all elements or there's less than a vector's-worth remaining.
do
{
charValues = Vector256.LoadUnsafe(ref currentCharsSearchSpace);
byteValues = Vector128.LoadUnsafe(ref currentBytesSearchSpace);
charValues = Vector256.LoadUnsafe(ref currentCharsSearchSpace);

// it's OK to widen the bytes, it's NOT OK to narrow the chars (we could loose some information)
if (Vector256.Equals(Widen(byteValues), charValues) != Vector256<ushort>.AllBitsSet)
{
return false;
}

if ((charValues.AsByte() | byteValues).ExtractMostSignificantBits() != 0)
if (byteValues.ExtractMostSignificantBits() != 0 || charValues.AsByte().ExtractMostSignificantBits() != 0)
{
return false;
}
Expand All @@ -80,16 +80,16 @@ public static bool Equals(ReadOnlySpan<byte> left, ReadOnlySpan<char> right)
// If any elements remain, process the last vector in the search space.
if ((uint)right.Length % Vector256<ushort>.Count != 0)
{
charValues = Vector256.LoadUnsafe(ref oneVectorAwayFromCharsEnd);
byteValues = Vector128.LoadUnsafe(ref oneVectorAwayFromBytesEnd);
charValues = Vector256.LoadUnsafe(ref oneVectorAwayFromCharsEnd);

// it's OK to widen the bytes, it's NOT OK to narrow the chars (we could loose some information)
if (Vector256.Equals(Widen(byteValues), charValues) != Vector256<ushort>.AllBitsSet)
{
return false;
}

if (charValues.AsByte().ExtractMostSignificantBits() != 0 || byteValues.ExtractMostSignificantBits() != 0)
if (byteValues.ExtractMostSignificantBits() != 0 || charValues.AsByte().ExtractMostSignificantBits() != 0)
{
return false;
}
Expand All @@ -108,22 +108,22 @@ public static bool Equals(ReadOnlySpan<byte> left, ReadOnlySpan<char> right)
// Loop until either we've finished all elements or there's less than a vector's-worth remaining.
do
{
charValues = Vector128.LoadUnsafe(ref currentCharsSearchSpace);
byteValues = Vector64.LoadUnsafe(ref currentBytesSearchSpace);
charValues = Vector128.LoadUnsafe(ref currentCharsSearchSpace);

// it's OK to widen the bytes, it's NOT OK to narrow the chars (we could loose some information)
if (Vector128.Equals(Widen(byteValues), charValues) != Vector128<ushort>.AllBitsSet)
{
return false;
}

if (VectorContainsNonAsciiChar(charValues) || VectorContainsNonAsciiChar(byteValues))
if (VectorContainsNonAsciiChar(byteValues) | VectorContainsNonAsciiChar(charValues))
{
return false;
}

currentCharsSearchSpace = ref Unsafe.Add(ref currentCharsSearchSpace, Vector128<ushort>.Count);
currentBytesSearchSpace = ref Unsafe.Add(ref currentBytesSearchSpace, Vector64<byte>.Count);
currentCharsSearchSpace = ref Unsafe.Add(ref currentCharsSearchSpace, Vector128<ushort>.Count);
}
while (!Unsafe.IsAddressGreaterThan(ref currentCharsSearchSpace, ref oneVectorAwayFromCharsEnd));

Expand All @@ -139,7 +139,7 @@ public static bool Equals(ReadOnlySpan<byte> left, ReadOnlySpan<char> right)
return false;
}

if (VectorContainsNonAsciiChar(charValues) || VectorContainsNonAsciiChar(byteValues))
if (VectorContainsNonAsciiChar(byteValues) || VectorContainsNonAsciiChar(charValues))
{
return false;
}
Expand All @@ -153,6 +153,10 @@ public static bool Equals(ReadOnlySpan<byte> left, ReadOnlySpan<char> right)
public static bool Equals(ReadOnlySpan<byte> left, ReadOnlySpan<byte> right)
=> left.Length == right.Length && Equals<byte>(left, right);

/// <inheritdoc cref="Equals(ReadOnlySpan{byte}, ReadOnlySpan{char})"/>
public static bool Equals(ReadOnlySpan<char> left, ReadOnlySpan<byte> right)
=> Equals(right, left);

/// <inheritdoc cref="Equals(ReadOnlySpan{byte}, ReadOnlySpan{char})"/>
public static bool Equals(ReadOnlySpan<char> left, ReadOnlySpan<char> right)
=> left.Length == right.Length && Equals<ushort>(MemoryMarshal.Cast<char, ushort>(left), MemoryMarshal.Cast<char, ushort>(right));
Expand All @@ -171,7 +175,7 @@ private static bool Equals<T>(ReadOnlySpan<T> left, ReadOnlySpan<T> right) where
return false;
}

if (!UnicodeUtility.IsAsciiCodePoint(valueA) || !UnicodeUtility.IsAsciiCodePoint(valueB))
if (!UnicodeUtility.IsAsciiCodePoint(valueA | valueB))
{
return false;
}
Expand All @@ -198,7 +202,7 @@ private static bool Equals<T>(ReadOnlySpan<T> left, ReadOnlySpan<T> right) where
return false;
}

if (rightValues.AsByte().ExtractMostSignificantBits() != 0 || leftValues.ExtractMostSignificantBits() != 0)
if ((leftValues.AsByte() | rightValues.AsByte()).ExtractMostSignificantBits() != 0)
{
return false;
}
Expand All @@ -219,7 +223,7 @@ private static bool Equals<T>(ReadOnlySpan<T> left, ReadOnlySpan<T> right) where
return false;
}

if (rightValues.AsByte().ExtractMostSignificantBits() != 0 || leftValues.ExtractMostSignificantBits() != 0)
if ((leftValues.AsByte() | rightValues.AsByte()).ExtractMostSignificantBits() != 0)
{
return false;
}
Expand All @@ -246,7 +250,7 @@ private static bool Equals<T>(ReadOnlySpan<T> left, ReadOnlySpan<T> right) where
return false;
}

if (VectorContainsAnyNonAsciiData(leftValues) || VectorContainsAnyNonAsciiData(rightValues))
if (VectorContainsAnyNonAsciiData(leftValues | rightValues))
{
return false;
}
Expand All @@ -259,15 +263,15 @@ private static bool Equals<T>(ReadOnlySpan<T> left, ReadOnlySpan<T> right) where
// If any elements remain, process the last vector in the search space.
if ((uint)right.Length % Vector128<T>.Count != 0)
{
rightValues = Vector128.LoadUnsafe(ref oneVectorAwayFromRightEnd);
leftValues = Vector128.LoadUnsafe(ref oneVectorAwayFromLeftEnd);
rightValues = Vector128.LoadUnsafe(ref oneVectorAwayFromRightEnd);

if (Vector128.Equals(leftValues, rightValues) != Vector128<T>.AllBitsSet)
{
return false;
}

if (VectorContainsAnyNonAsciiData(leftValues) || VectorContainsAnyNonAsciiData(rightValues))
if (VectorContainsAnyNonAsciiData(leftValues | rightValues))
{
return false;
}
Expand All @@ -291,6 +295,10 @@ public static bool EqualsIgnoreCase(ReadOnlySpan<byte> left, ReadOnlySpan<byte>
public static bool EqualsIgnoreCase(ReadOnlySpan<byte> left, ReadOnlySpan<char> right)
=> left.Length == right.Length && SequenceEqualIgnoreCase(right, left);

/// <inheritdoc cref="EqualsIgnoreCase(ReadOnlySpan{byte}, ReadOnlySpan{byte})"/>
public static bool EqualsIgnoreCase(ReadOnlySpan<char> left, ReadOnlySpan<byte> right)
=> EqualsIgnoreCase(right, left);

/// <inheritdoc cref="EqualsIgnoreCase(ReadOnlySpan{byte}, ReadOnlySpan{byte})"/>
public static bool EqualsIgnoreCase(ReadOnlySpan<char> left, ReadOnlySpan<char> right)
=> left.Length == right.Length && SequenceEqualIgnoreCase(right, left);
Expand Down
2 changes: 2 additions & 0 deletions src/libraries/System.Runtime/ref/System.Runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13906,9 +13906,11 @@ public static class Ascii
{
public static bool Equals(System.ReadOnlySpan<byte> left, System.ReadOnlySpan<byte> right) { throw null; }
public static bool Equals(System.ReadOnlySpan<byte> left, System.ReadOnlySpan<char> right) { throw null; }
public static bool Equals(System.ReadOnlySpan<char> left, System.ReadOnlySpan<byte> right) { throw null; }
public static bool Equals(System.ReadOnlySpan<char> left, System.ReadOnlySpan<char> right) { throw null; }
public static bool EqualsIgnoreCase(System.ReadOnlySpan<byte> left, System.ReadOnlySpan<byte> right) { throw null; }
public static bool EqualsIgnoreCase(System.ReadOnlySpan<byte> left, System.ReadOnlySpan<char> right) { throw null; }
public static bool EqualsIgnoreCase(System.ReadOnlySpan<char> left, System.ReadOnlySpan<byte> right) { throw null; }
public static bool EqualsIgnoreCase(System.ReadOnlySpan<char> left, System.ReadOnlySpan<char> right) { throw null; }
public static bool IsValid(System.ReadOnlySpan<byte> value) { throw null; }
public static bool IsValid(System.ReadOnlySpan<char> value) { throw null; }
Expand Down
Loading