diff options
Diffstat (limited to 'src/System.Memory/src/System/SpanHelpers.T.cs')
-rw-r--r-- | src/System.Memory/src/System/SpanHelpers.T.cs | 105 |
1 files changed, 104 insertions, 1 deletions
diff --git a/src/System.Memory/src/System/SpanHelpers.T.cs b/src/System.Memory/src/System/SpanHelpers.T.cs index 88bb4447f8..db119a8913 100644 --- a/src/System.Memory/src/System/SpanHelpers.T.cs +++ b/src/System.Memory/src/System/SpanHelpers.T.cs @@ -23,7 +23,7 @@ namespace System int valueTailLength = valueLength - 1; int index = 0; - for (;;) + for (; ; ) { Debug.Assert(0 <= index && index <= searchSpaceLength); // Ensures no deceptive underflows in the computation of "remainingSearchSpaceLength". int remainingSearchSpaceLength = searchSpaceLength - index - valueTailLength; @@ -119,6 +119,109 @@ namespace System return (int)(byte*)(index + 7); } + public static int LastIndexOf<T>(ref T searchSpace, int searchSpaceLength, ref T value, int valueLength) + where T : IEquatable<T> + { + Debug.Assert(searchSpaceLength >= 0); + Debug.Assert(valueLength >= 0); + + if (valueLength == 0) + return 0; // A zero-length sequence is always treated as "found" at the start of the search space. + + T valueHead = value; + ref T valueTail = ref Unsafe.Add(ref value, 1); + int valueTailLength = valueLength - 1; + + int index = 0; + for (; ; ) + { + Debug.Assert(0 <= index && index <= searchSpaceLength); // Ensures no deceptive underflows in the computation of "remainingSearchSpaceLength". + int remainingSearchSpaceLength = searchSpaceLength - index - valueTailLength; + if (remainingSearchSpaceLength <= 0) + break; // The unsearched portion is now shorter than the sequence we're looking for. So it can't be there. + + // Do a quick search for the first element of "value". + int relativeIndex = LastIndexOf(ref searchSpace, valueHead, remainingSearchSpaceLength); + if (relativeIndex == -1) + break; + + // Found the first element of "value". See if the tail matches. + if (SequenceEqual(ref Unsafe.Add(ref searchSpace, relativeIndex + 1), ref valueTail, valueTailLength)) + return relativeIndex; // The tail matched. Return a successful find. + + index += remainingSearchSpaceLength - relativeIndex; + } + return -1; + } + + public static unsafe int LastIndexOf<T>(ref T searchSpace, T value, int length) + where T : IEquatable<T> + { + Debug.Assert(length >= 0); + + while (length >= 8) + { + length -= 8; + + if (value.Equals(Unsafe.Add(ref searchSpace, length + 7))) + goto Found7; + if (value.Equals(Unsafe.Add(ref searchSpace, length + 6))) + goto Found6; + if (value.Equals(Unsafe.Add(ref searchSpace, length + 5))) + goto Found5; + if (value.Equals(Unsafe.Add(ref searchSpace, length + 4))) + goto Found4; + if (value.Equals(Unsafe.Add(ref searchSpace, length + 3))) + goto Found3; + if (value.Equals(Unsafe.Add(ref searchSpace, length + 2))) + goto Found2; + if (value.Equals(Unsafe.Add(ref searchSpace, length + 1))) + goto Found1; + if (value.Equals(Unsafe.Add(ref searchSpace, length))) + goto Found; + } + + if (length >= 4) + { + length -= 4; + + if (value.Equals(Unsafe.Add(ref searchSpace, length + 3))) + goto Found3; + if (value.Equals(Unsafe.Add(ref searchSpace, length + 2))) + goto Found2; + if (value.Equals(Unsafe.Add(ref searchSpace, length + 1))) + goto Found1; + if (value.Equals(Unsafe.Add(ref searchSpace, length))) + goto Found; + } + + while (length > 0) + { + length--; + + if (value.Equals(Unsafe.Add(ref searchSpace, length))) + goto Found; + } + return -1; + + Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549 + return length; + Found1: + return length + 1; + Found2: + return length + 2; + Found3: + return length + 3; + Found4: + return length + 4; + Found5: + return length + 5; + Found6: + return length + 6; + Found7: + return length + 7; + } + public static bool SequenceEqual<T>(ref T first, ref T second, int length) where T : IEquatable<T> { |