| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902 |
- // Licensed to the .NET Foundation under one or more agreements.
- // The .NET Foundation licenses this file to you under the MIT license.
- // See the LICENSE file in the project root for more information.
- using System.Diagnostics;
- using System.Runtime.CompilerServices; // Do not remove. This is necessary for netstandard, since this file is mirrored into corefx
- #if !netstandard
- using Internal.Runtime.CompilerServices;
- #endif
- namespace System
- {
- internal static partial class SpanHelpers // .T
- {
- public static int IndexOf<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 = IndexOf(ref Unsafe.Add(ref searchSpace, index), valueHead, remainingSearchSpaceLength);
- if (relativeIndex == -1)
- break;
- index += relativeIndex;
- // Found the first element of "value". See if the tail matches.
- if (SequenceEqual(ref Unsafe.Add(ref searchSpace, index + 1), ref valueTail, valueTailLength))
- return index; // The tail matched. Return a successful find.
- index++;
- }
- return -1;
- }
- // Adapted from IndexOf(...)
- public unsafe static bool Contains<T>(ref T searchSpace, T value, int length)
- where T : IEquatable<T>
- {
- Debug.Assert(length >= 0);
- IntPtr index = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
- if (default(T) != null || (object)value != null)
- {
- while (length >= 8)
- {
- length -= 8;
- if (value.Equals(Unsafe.Add(ref searchSpace, index + 0)) ||
- value.Equals(Unsafe.Add(ref searchSpace, index + 1)) ||
- value.Equals(Unsafe.Add(ref searchSpace, index + 2)) ||
- value.Equals(Unsafe.Add(ref searchSpace, index + 3)) ||
- value.Equals(Unsafe.Add(ref searchSpace, index + 4)) ||
- value.Equals(Unsafe.Add(ref searchSpace, index + 5)) ||
- value.Equals(Unsafe.Add(ref searchSpace, index + 6)) ||
- value.Equals(Unsafe.Add(ref searchSpace, index + 7)))
- {
- goto Found;
- }
- index += 8;
- }
- if (length >= 4)
- {
- length -= 4;
- if (value.Equals(Unsafe.Add(ref searchSpace, index + 0)) ||
- value.Equals(Unsafe.Add(ref searchSpace, index + 1)) ||
- value.Equals(Unsafe.Add(ref searchSpace, index + 2)) ||
- value.Equals(Unsafe.Add(ref searchSpace, index + 3)))
- {
- goto Found;
- }
- index += 4;
- }
- while (length > 0)
- {
- length -= 1;
- if (value.Equals(Unsafe.Add(ref searchSpace, index)))
- goto Found;
- index += 1;
- }
- }
- else
- {
- byte* len = (byte*)length;
- for (index = (IntPtr)0; index.ToPointer() < len; index += 1)
- {
- if ((object)Unsafe.Add(ref searchSpace, index) is null)
- {
- goto Found;
- }
- }
- }
- return false;
- Found:
- return true;
- }
- public static unsafe int IndexOf<T>(ref T searchSpace, T value, int length)
- where T : IEquatable<T>
- {
- Debug.Assert(length >= 0);
- IntPtr index = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
- if (default(T) != null || (object)value != null)
- {
- while (length >= 8)
- {
- length -= 8;
- if (value.Equals(Unsafe.Add(ref searchSpace, index)))
- goto Found;
- if (value.Equals(Unsafe.Add(ref searchSpace, index + 1)))
- goto Found1;
- if (value.Equals(Unsafe.Add(ref searchSpace, index + 2)))
- goto Found2;
- if (value.Equals(Unsafe.Add(ref searchSpace, index + 3)))
- goto Found3;
- if (value.Equals(Unsafe.Add(ref searchSpace, index + 4)))
- goto Found4;
- if (value.Equals(Unsafe.Add(ref searchSpace, index + 5)))
- goto Found5;
- if (value.Equals(Unsafe.Add(ref searchSpace, index + 6)))
- goto Found6;
- if (value.Equals(Unsafe.Add(ref searchSpace, index + 7)))
- goto Found7;
- index += 8;
- }
- if (length >= 4)
- {
- length -= 4;
- if (value.Equals(Unsafe.Add(ref searchSpace, index)))
- goto Found;
- if (value.Equals(Unsafe.Add(ref searchSpace, index + 1)))
- goto Found1;
- if (value.Equals(Unsafe.Add(ref searchSpace, index + 2)))
- goto Found2;
- if (value.Equals(Unsafe.Add(ref searchSpace, index + 3)))
- goto Found3;
- index += 4;
- }
- while (length > 0)
- {
- if (value.Equals(Unsafe.Add(ref searchSpace, index)))
- goto Found;
- index += 1;
- length--;
- }
- }
- else
- {
- byte* len = (byte*)length;
- for (index = (IntPtr)0; index.ToPointer() < len; index += 1)
- {
- if ((object)Unsafe.Add(ref searchSpace, index) is null)
- {
- goto Found;
- }
- }
- }
- return -1;
- Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549
- return (int)(byte*)index;
- Found1:
- return (int)(byte*)(index + 1);
- Found2:
- return (int)(byte*)(index + 2);
- Found3:
- return (int)(byte*)(index + 3);
- Found4:
- return (int)(byte*)(index + 4);
- Found5:
- return (int)(byte*)(index + 5);
- Found6:
- return (int)(byte*)(index + 6);
- Found7:
- return (int)(byte*)(index + 7);
- }
- public static int IndexOfAny<T>(ref T searchSpace, T value0, T value1, int length)
- where T : IEquatable<T>
- {
- Debug.Assert(length >= 0);
- T lookUp;
- int index = 0;
- if (default(T) != null || ((object)value0 != null && (object)value1 != null))
- {
- while ((length - index) >= 8)
- {
- lookUp = Unsafe.Add(ref searchSpace, index);
- if (value0.Equals(lookUp) || value1.Equals(lookUp))
- goto Found;
- lookUp = Unsafe.Add(ref searchSpace, index + 1);
- if (value0.Equals(lookUp) || value1.Equals(lookUp))
- goto Found1;
- lookUp = Unsafe.Add(ref searchSpace, index + 2);
- if (value0.Equals(lookUp) || value1.Equals(lookUp))
- goto Found2;
- lookUp = Unsafe.Add(ref searchSpace, index + 3);
- if (value0.Equals(lookUp) || value1.Equals(lookUp))
- goto Found3;
- lookUp = Unsafe.Add(ref searchSpace, index + 4);
- if (value0.Equals(lookUp) || value1.Equals(lookUp))
- goto Found4;
- lookUp = Unsafe.Add(ref searchSpace, index + 5);
- if (value0.Equals(lookUp) || value1.Equals(lookUp))
- goto Found5;
- lookUp = Unsafe.Add(ref searchSpace, index + 6);
- if (value0.Equals(lookUp) || value1.Equals(lookUp))
- goto Found6;
- lookUp = Unsafe.Add(ref searchSpace, index + 7);
- if (value0.Equals(lookUp) || value1.Equals(lookUp))
- goto Found7;
- index += 8;
- }
- if ((length - index) >= 4)
- {
- lookUp = Unsafe.Add(ref searchSpace, index);
- if (value0.Equals(lookUp) || value1.Equals(lookUp))
- goto Found;
- lookUp = Unsafe.Add(ref searchSpace, index + 1);
- if (value0.Equals(lookUp) || value1.Equals(lookUp))
- goto Found1;
- lookUp = Unsafe.Add(ref searchSpace, index + 2);
- if (value0.Equals(lookUp) || value1.Equals(lookUp))
- goto Found2;
- lookUp = Unsafe.Add(ref searchSpace, index + 3);
- if (value0.Equals(lookUp) || value1.Equals(lookUp))
- goto Found3;
- index += 4;
- }
- while (index < length)
- {
- lookUp = Unsafe.Add(ref searchSpace, index);
- if (value0.Equals(lookUp) || value1.Equals(lookUp))
- goto Found;
- index++;
- }
- }
- else
- {
- for (index = 0; index < length; index++)
- {
- lookUp = Unsafe.Add(ref searchSpace, index);
- if ((object)lookUp is null)
- {
- if ((object)value0 is null || (object)value1 is null)
- {
- goto Found;
- }
- }
- else if (lookUp.Equals(value0) || lookUp.Equals(value1))
- {
- goto Found;
- }
- }
- }
- return -1;
- Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549
- return index;
- Found1:
- return index + 1;
- Found2:
- return index + 2;
- Found3:
- return index + 3;
- Found4:
- return index + 4;
- Found5:
- return index + 5;
- Found6:
- return index + 6;
- Found7:
- return index + 7;
- }
- public static int IndexOfAny<T>(ref T searchSpace, T value0, T value1, T value2, int length)
- where T : IEquatable<T>
- {
- Debug.Assert(length >= 0);
- T lookUp;
- int index = 0;
- if (default(T) != null || ((object)value0 != null && (object)value1 != null && (object)value2 != null))
- {
- while ((length - index) >= 8)
- {
- lookUp = Unsafe.Add(ref searchSpace, index);
- if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp))
- goto Found;
- lookUp = Unsafe.Add(ref searchSpace, index + 1);
- if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp))
- goto Found1;
- lookUp = Unsafe.Add(ref searchSpace, index + 2);
- if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp))
- goto Found2;
- lookUp = Unsafe.Add(ref searchSpace, index + 3);
- if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp))
- goto Found3;
- lookUp = Unsafe.Add(ref searchSpace, index + 4);
- if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp))
- goto Found4;
- lookUp = Unsafe.Add(ref searchSpace, index + 5);
- if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp))
- goto Found5;
- lookUp = Unsafe.Add(ref searchSpace, index + 6);
- if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp))
- goto Found6;
- lookUp = Unsafe.Add(ref searchSpace, index + 7);
- if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp))
- goto Found7;
- index += 8;
- }
- if ((length - index) >= 4)
- {
- lookUp = Unsafe.Add(ref searchSpace, index);
- if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp))
- goto Found;
- lookUp = Unsafe.Add(ref searchSpace, index + 1);
- if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp))
- goto Found1;
- lookUp = Unsafe.Add(ref searchSpace, index + 2);
- if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp))
- goto Found2;
- lookUp = Unsafe.Add(ref searchSpace, index + 3);
- if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp))
- goto Found3;
- index += 4;
- }
- while (index < length)
- {
- lookUp = Unsafe.Add(ref searchSpace, index);
- if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp))
- goto Found;
- index++;
- }
- }
- else
- {
- for (index = 0; index < length; index++)
- {
- lookUp = Unsafe.Add(ref searchSpace, index);
- if ((object)lookUp is null)
- {
- if ((object)value0 is null || (object)value1 is null || (object)value2 is null)
- {
- goto Found;
- }
- }
- else if (lookUp.Equals(value0) || lookUp.Equals(value1) || lookUp.Equals(value2))
- {
- goto Found;
- }
- }
- }
- return -1;
- Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549
- return index;
- Found1:
- return index + 1;
- Found2:
- return index + 2;
- Found3:
- return index + 3;
- Found4:
- return index + 4;
- Found5:
- return index + 5;
- Found6:
- return index + 6;
- Found7:
- return index + 7;
- }
- public static int IndexOfAny<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.
- int index = -1;
- for (int i = 0; i < valueLength; i++)
- {
- var tempIndex = IndexOf(ref searchSpace, Unsafe.Add(ref value, i), searchSpaceLength);
- if ((uint)tempIndex < (uint)index)
- {
- index = tempIndex;
- // Reduce space for search, cause we don't care if we find the search value after the index of a previously found value
- searchSpaceLength = tempIndex;
- if (index == 0)
- break;
- }
- }
- return index;
- }
- 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 int LastIndexOf<T>(ref T searchSpace, T value, int length)
- where T : IEquatable<T>
- {
- Debug.Assert(length >= 0);
- if (default(T) != null || (object)value != null)
- {
- 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;
- }
- }
- else
- {
- for (length--; length >= 0; length--)
- {
- if ((object)Unsafe.Add(ref searchSpace, length) is null)
- {
- 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 int LastIndexOfAny<T>(ref T searchSpace, T value0, T value1, int length)
- where T : IEquatable<T>
- {
- Debug.Assert(length >= 0);
- T lookUp;
- if (default(T) != null || ((object)value0 != null && (object)value1 != null))
- {
- while (length >= 8)
- {
- length -= 8;
- lookUp = Unsafe.Add(ref searchSpace, length + 7);
- if (value0.Equals(lookUp) || value1.Equals(lookUp))
- goto Found7;
- lookUp = Unsafe.Add(ref searchSpace, length + 6);
- if (value0.Equals(lookUp) || value1.Equals(lookUp))
- goto Found6;
- lookUp = Unsafe.Add(ref searchSpace, length + 5);
- if (value0.Equals(lookUp) || value1.Equals(lookUp))
- goto Found5;
- lookUp = Unsafe.Add(ref searchSpace, length + 4);
- if (value0.Equals(lookUp) || value1.Equals(lookUp))
- goto Found4;
- lookUp = Unsafe.Add(ref searchSpace, length + 3);
- if (value0.Equals(lookUp) || value1.Equals(lookUp))
- goto Found3;
- lookUp = Unsafe.Add(ref searchSpace, length + 2);
- if (value0.Equals(lookUp) || value1.Equals(lookUp))
- goto Found2;
- lookUp = Unsafe.Add(ref searchSpace, length + 1);
- if (value0.Equals(lookUp) || value1.Equals(lookUp))
- goto Found1;
- lookUp = Unsafe.Add(ref searchSpace, length);
- if (value0.Equals(lookUp) || value1.Equals(lookUp))
- goto Found;
- }
- if (length >= 4)
- {
- length -= 4;
- lookUp = Unsafe.Add(ref searchSpace, length + 3);
- if (value0.Equals(lookUp) || value1.Equals(lookUp))
- goto Found3;
- lookUp = Unsafe.Add(ref searchSpace, length + 2);
- if (value0.Equals(lookUp) || value1.Equals(lookUp))
- goto Found2;
- lookUp = Unsafe.Add(ref searchSpace, length + 1);
- if (value0.Equals(lookUp) || value1.Equals(lookUp))
- goto Found1;
- lookUp = Unsafe.Add(ref searchSpace, length);
- if (value0.Equals(lookUp) || value1.Equals(lookUp))
- goto Found;
- }
- while (length > 0)
- {
- length--;
- lookUp = Unsafe.Add(ref searchSpace, length);
- if (value0.Equals(lookUp) || value1.Equals(lookUp))
- goto Found;
- }
- }
- else
- {
- for (length--; length >= 0; length--)
- {
- lookUp = Unsafe.Add(ref searchSpace, length);
- if ((object)lookUp is null)
- {
- if ((object)value0 is null || (object)value1 is null)
- {
- goto Found;
- }
- }
- else if (lookUp.Equals(value0) || lookUp.Equals(value1))
- {
- 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 int LastIndexOfAny<T>(ref T searchSpace, T value0, T value1, T value2, int length)
- where T : IEquatable<T>
- {
- Debug.Assert(length >= 0);
- T lookUp;
- if (default(T) != null || ((object)value0 != null && (object)value1 != null))
- {
- while (length >= 8)
- {
- length -= 8;
- lookUp = Unsafe.Add(ref searchSpace, length + 7);
- if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp))
- goto Found7;
- lookUp = Unsafe.Add(ref searchSpace, length + 6);
- if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp))
- goto Found6;
- lookUp = Unsafe.Add(ref searchSpace, length + 5);
- if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp))
- goto Found5;
- lookUp = Unsafe.Add(ref searchSpace, length + 4);
- if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp))
- goto Found4;
- lookUp = Unsafe.Add(ref searchSpace, length + 3);
- if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp))
- goto Found3;
- lookUp = Unsafe.Add(ref searchSpace, length + 2);
- if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp))
- goto Found2;
- lookUp = Unsafe.Add(ref searchSpace, length + 1);
- if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp))
- goto Found1;
- lookUp = Unsafe.Add(ref searchSpace, length);
- if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp))
- goto Found;
- }
- if (length >= 4)
- {
- length -= 4;
- lookUp = Unsafe.Add(ref searchSpace, length + 3);
- if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp))
- goto Found3;
- lookUp = Unsafe.Add(ref searchSpace, length + 2);
- if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp))
- goto Found2;
- lookUp = Unsafe.Add(ref searchSpace, length + 1);
- if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp))
- goto Found1;
- lookUp = Unsafe.Add(ref searchSpace, length);
- if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp))
- goto Found;
- }
- while (length > 0)
- {
- length--;
- lookUp = Unsafe.Add(ref searchSpace, length);
- if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp))
- goto Found;
- }
- }
- else
- {
- for (length--; length >= 0; length--)
- {
- lookUp = Unsafe.Add(ref searchSpace, length);
- if ((object)lookUp is null)
- {
- if ((object)value0 is null || (object)value1 is null || (object)value2 is null)
- {
- goto Found;
- }
- }
- else if (lookUp.Equals(value0) || lookUp.Equals(value1) || lookUp.Equals(value2))
- {
- 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 int LastIndexOfAny<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.
- int index = -1;
- for (int i = 0; i < valueLength; i++)
- {
- var tempIndex = LastIndexOf(ref searchSpace, Unsafe.Add(ref value, i), searchSpaceLength);
- if (tempIndex > index)
- index = tempIndex;
- }
- return index;
- }
- public static bool SequenceEqual<T>(ref T first, ref T second, int length)
- where T : IEquatable<T>
- {
- Debug.Assert(length >= 0);
- if (Unsafe.AreSame(ref first, ref second))
- goto Equal;
- IntPtr index = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
- T lookUp0;
- T lookUp1;
- while (length >= 8)
- {
- length -= 8;
- lookUp0 = Unsafe.Add(ref first, index);
- lookUp1 = Unsafe.Add(ref second, index);
- if (!(lookUp0?.Equals(lookUp1) ?? (object)lookUp1 is null))
- goto NotEqual;
- lookUp0 = Unsafe.Add(ref first, index + 1);
- lookUp1 = Unsafe.Add(ref second, index + 1);
- if (!(lookUp0?.Equals(lookUp1) ?? (object)lookUp1 is null))
- goto NotEqual;
- lookUp0 = Unsafe.Add(ref first, index + 2);
- lookUp1 = Unsafe.Add(ref second, index + 2);
- if (!(lookUp0?.Equals(lookUp1) ?? (object)lookUp1 is null))
- goto NotEqual;
- lookUp0 = Unsafe.Add(ref first, index + 3);
- lookUp1 = Unsafe.Add(ref second, index + 3);
- if (!(lookUp0?.Equals(lookUp1) ?? (object)lookUp1 is null))
- goto NotEqual;
- lookUp0 = Unsafe.Add(ref first, index + 4);
- lookUp1 = Unsafe.Add(ref second, index + 4);
- if (!(lookUp0?.Equals(lookUp1) ?? (object)lookUp1 is null))
- goto NotEqual;
- lookUp0 = Unsafe.Add(ref first, index + 5);
- lookUp1 = Unsafe.Add(ref second, index + 5);
- if (!(lookUp0?.Equals(lookUp1) ?? (object)lookUp1 is null))
- goto NotEqual;
- lookUp0 = Unsafe.Add(ref first, index + 6);
- lookUp1 = Unsafe.Add(ref second, index + 6);
- if (!(lookUp0?.Equals(lookUp1) ?? (object)lookUp1 is null))
- goto NotEqual;
- lookUp0 = Unsafe.Add(ref first, index + 7);
- lookUp1 = Unsafe.Add(ref second, index + 7);
- if (!(lookUp0?.Equals(lookUp1) ?? (object)lookUp1 is null))
- goto NotEqual;
- index += 8;
- }
- if (length >= 4)
- {
- length -= 4;
- lookUp0 = Unsafe.Add(ref first, index);
- lookUp1 = Unsafe.Add(ref second, index);
- if (!(lookUp0?.Equals(lookUp1) ?? (object)lookUp1 is null))
- goto NotEqual;
- lookUp0 = Unsafe.Add(ref first, index + 1);
- lookUp1 = Unsafe.Add(ref second, index + 1);
- if (!(lookUp0?.Equals(lookUp1) ?? (object)lookUp1 is null))
- goto NotEqual;
- lookUp0 = Unsafe.Add(ref first, index + 2);
- lookUp1 = Unsafe.Add(ref second, index + 2);
- if (!(lookUp0?.Equals(lookUp1) ?? (object)lookUp1 is null))
- goto NotEqual;
- lookUp0 = Unsafe.Add(ref first, index + 3);
- lookUp1 = Unsafe.Add(ref second, index + 3);
- if (!(lookUp0?.Equals(lookUp1) ?? (object)lookUp1 is null))
- goto NotEqual;
- index += 4;
- }
- while (length > 0)
- {
- lookUp0 = Unsafe.Add(ref first, index);
- lookUp1 = Unsafe.Add(ref second, index);
- if (!(lookUp0?.Equals(lookUp1) ?? (object)lookUp1 is null))
- goto NotEqual;
- index += 1;
- length--;
- }
- Equal:
- return true;
- NotEqual: // Workaround for https://github.com/dotnet/coreclr/issues/13549
- return false;
- }
- public static int SequenceCompareTo<T>(ref T first, int firstLength, ref T second, int secondLength)
- where T : IComparable<T>
- {
- Debug.Assert(firstLength >= 0);
- Debug.Assert(secondLength >= 0);
- var minLength = firstLength;
- if (minLength > secondLength)
- minLength = secondLength;
- for (int i = 0; i < minLength; i++)
- {
- T lookUp = Unsafe.Add(ref second, i);
- int result = (Unsafe.Add(ref first, i)?.CompareTo(lookUp) ?? (((object)lookUp is null) ? 0 : -1));
- if (result != 0)
- return result;
- }
- return firstLength.CompareTo(secondLength);
- }
- }
- }
|