diff options
Diffstat (limited to 'src/System.Private.CoreLib/shared/System/SpanHelpers.Byte.cs')
-rw-r--r-- | src/System.Private.CoreLib/shared/System/SpanHelpers.Byte.cs | 94 |
1 files changed, 93 insertions, 1 deletions
diff --git a/src/System.Private.CoreLib/shared/System/SpanHelpers.Byte.cs b/src/System.Private.CoreLib/shared/System/SpanHelpers.Byte.cs index 2890adb56..373065363 100644 --- a/src/System.Private.CoreLib/shared/System/SpanHelpers.Byte.cs +++ b/src/System.Private.CoreLib/shared/System/SpanHelpers.Byte.cs @@ -16,7 +16,7 @@ using nuint = System.UInt32; namespace System { - internal static partial class SpanHelpers + internal static partial class SpanHelpers // .Byte { public static int IndexOf(ref byte searchSpace, int searchSpaceLength, ref byte value, int valueLength) { @@ -96,6 +96,98 @@ namespace System return index; } + // Adapted from IndexOf(...) + public static unsafe bool Contains(ref byte searchSpace, byte value, int length) + { + Debug.Assert(length >= 0); + + uint uValue = value; // Use uint for comparisons to avoid unnecessary 8->32 extensions + IntPtr index = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations + IntPtr nLength = (IntPtr)length; + + if (Vector.IsHardwareAccelerated && length >= Vector<byte>.Count * 2) + { + int unaligned = (int)Unsafe.AsPointer(ref searchSpace) & (Vector<byte>.Count - 1); + nLength = (IntPtr)((Vector<byte>.Count - unaligned) & (Vector<byte>.Count - 1)); + } + + SequentialScan: + while ((byte*)nLength >= (byte*)8) + { + nLength -= 8; + + if (uValue == Unsafe.AddByteOffset(ref searchSpace, index + 0) || + uValue == Unsafe.AddByteOffset(ref searchSpace, index + 1) || + uValue == Unsafe.AddByteOffset(ref searchSpace, index + 2) || + uValue == Unsafe.AddByteOffset(ref searchSpace, index + 3) || + uValue == Unsafe.AddByteOffset(ref searchSpace, index + 4) || + uValue == Unsafe.AddByteOffset(ref searchSpace, index + 5) || + uValue == Unsafe.AddByteOffset(ref searchSpace, index + 6) || + uValue == Unsafe.AddByteOffset(ref searchSpace, index + 7)) + { + goto Found; + } + + index += 8; + } + + if ((byte*)nLength >= (byte*)4) + { + nLength -= 4; + + if (uValue == Unsafe.AddByteOffset(ref searchSpace, index + 0) || + uValue == Unsafe.AddByteOffset(ref searchSpace, index + 1) || + uValue == Unsafe.AddByteOffset(ref searchSpace, index + 2) || + uValue == Unsafe.AddByteOffset(ref searchSpace, index + 3)) + { + goto Found; + } + + index += 4; + } + + while ((byte*)nLength > (byte*)0) + { + nLength -= 1; + + if (uValue == Unsafe.AddByteOffset(ref searchSpace, index)) + goto Found; + + index += 1; + } + + if (Vector.IsHardwareAccelerated && ((int)(byte*)index < length)) + { + nLength = (IntPtr)((length - (int)(byte*)index) & ~(Vector<byte>.Count - 1)); + + // Get comparison Vector + Vector<byte> vComparison = new Vector<byte>(value); + + while ((byte*)nLength > (byte*)index) + { + var vMatches = Vector.Equals(vComparison, Unsafe.ReadUnaligned<Vector<byte>>(ref Unsafe.AddByteOffset(ref searchSpace, index))); + if (Vector<byte>.Zero.Equals(vMatches)) + { + index += Vector<byte>.Count; + continue; + } + + goto Found; + } + + if ((int)(byte*)index < length) + { + nLength = (IntPtr)(length - (int)(byte*)index); + goto SequentialScan; + } + } + + return false; + + Found: + return true; + } + public static unsafe int IndexOf(ref byte searchSpace, byte value, int length) { Debug.Assert(length >= 0); |