Use vectorized T=byte implementations to optimize all MemoryExtensions APIs for T...
authorAhson Khan <ahkha@microsoft.com>
Fri, 16 Mar 2018 18:05:14 +0000 (11:05 -0700)
committerJan Kotas <jkotas@microsoft.com>
Sat, 17 Mar 2018 01:51:16 +0000 (18:51 -0700)
* Adding IsTypeNumeric helper

* Add more NUint operations and use IsTypeNumeric everywhere.

* Revert addition of LangVersion 7.2

* Fix formatting

* Revert use of nuint and IsNumericType for *IndexOf* APIs

* Fix comment, undo leftover changes, and fix indentation.

* Address PR feedback - use nuint where possible.

* PR feedback - Cleanup SequenceEqual just like SequenceCompareTo

* Add new NUInt operations for netcoreapp/coreclr mirror.

* Address PR feedback

* Add T = char and T = long tests for StartsWith and EndsWith

Signed-off-by: dotnet-bot-corefx-mirror <dotnet-bot@microsoft.com>
src/mscorlib/shared/System/MemoryExtensions.cs
src/mscorlib/shared/System/SpanHelpers.Byte.cs
src/mscorlib/shared/System/SpanHelpers.T.cs

index e4bc825..be6d22e 100644 (file)
@@ -11,12 +11,12 @@ using Internal.Runtime.CompilerServices;
 #endif
 
 #if netstandard
-using nuint=System.NUInt;
+using nuint = System.NUInt;
 #else
 #if BIT64
-using nuint=System.UInt64;
+using nuint = System.UInt64;
 #else
-using nuint=System.UInt32;
+using nuint = System.UInt32;
 #endif // BIT64
 #endif // netstandard
 
@@ -191,6 +191,7 @@ namespace System
                     ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
                     Unsafe.As<T, byte>(ref value),
                     span.Length);
+
             return SpanHelpers.IndexOf(ref MemoryMarshal.GetReference(span), value, span.Length);
         }
 
@@ -209,6 +210,7 @@ namespace System
                     span.Length,
                     ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(value)),
                     value.Length);
+
             return SpanHelpers.IndexOf(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(value), value.Length);
         }
 
@@ -226,6 +228,7 @@ namespace System
                     ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
                     Unsafe.As<T, byte>(ref value),
                     span.Length);
+
             return SpanHelpers.LastIndexOf<T>(ref MemoryMarshal.GetReference(span), value, span.Length);
         }
 
@@ -244,6 +247,7 @@ namespace System
                     span.Length,
                     ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(value)),
                     value.Length);
+
             return SpanHelpers.LastIndexOf<T>(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(value), value.Length);
         }
 
@@ -255,33 +259,13 @@ namespace System
             where T : IEquatable<T>
         {
             int length = first.Length;
-            if (typeof(T) == typeof(byte) || typeof(T) == typeof(sbyte))
-                return length == second.Length &&
-                SpanHelpers.SequenceEqual(
-                    ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(first)),
-                    ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(second)),
-                    length);
-
-            if (typeof(T) == typeof(char) || typeof(T) == typeof(short) || typeof(T) == typeof(ushort))
-                return length == second.Length &&
-                SpanHelpers.SequenceEqualBytes(
-                    ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(first)),
-                    ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(second)),
-                    ((nuint)length) * 2); // If this multiplication overflows, the Span we got overflows the entire address range. There's no happy outcome for this api in such a case so we choose not to take the overhead of checking. 
-
-            if (typeof(T) == typeof(int) || typeof(T) == typeof(uint))
-                return length == second.Length &&
-                SpanHelpers.SequenceEqualBytes(
-                    ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(first)),
-                    ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(second)),
-                    ((nuint)length) * 4); // If this multiplication overflows, the Span we got overflows the entire address range. There's no happy outcome for this api in such a case so we choose not to take the overhead of checking. 
 
-            if (typeof(T) == typeof(long) || typeof(T) == typeof(ulong))
+            if (default(T) != null && IsTypeComparableAsBytes<T>(out nuint size))
                 return length == second.Length &&
-                SpanHelpers.SequenceEqualBytes(
+                SpanHelpers.SequenceEqual(
                     ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(first)),
                     ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(second)),
-                    ((nuint)length) * 8); // If this multiplication overflows, the Span we got overflows the entire address range. There's no happy outcome for this api in such a case so we choose not to take the overhead of checking. 
+                    ((nuint)length) * size);  // If this multiplication overflows, the Span we got overflows the entire address range. There's no happy outcome for this api in such a case so we choose not to take the overhead of checking.
 
             return length == second.Length && SpanHelpers.SequenceEqual(ref MemoryMarshal.GetReference(first), ref MemoryMarshal.GetReference(second), length);
         }
@@ -298,25 +282,8 @@ namespace System
                     first.Length,
                     ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(second)),
                     second.Length);
-            return SpanHelpers.SequenceCompareTo(ref MemoryMarshal.GetReference(first), first.Length, ref MemoryMarshal.GetReference(second), second.Length);
-        }
 
-        /// <summary>
-        /// Reverses the sequence of the elements in the entire span.
-        /// </summary>
-        public static void Reverse<T>(this Span<T> span)
-        {
-            ref T p = ref MemoryMarshal.GetReference(span);
-            int i = 0;
-            int j = span.Length - 1;
-            while (i < j)
-            {
-                T temp = Unsafe.Add(ref p, i);
-                Unsafe.Add(ref p, i) = Unsafe.Add(ref p, j);
-                Unsafe.Add(ref p, j) = temp;
-                i++;
-                j--;
-            }
+            return SpanHelpers.SequenceCompareTo(ref MemoryMarshal.GetReference(first), first.Length, ref MemoryMarshal.GetReference(second), second.Length);
         }
 
         /// <summary>
@@ -333,6 +300,7 @@ namespace System
                     ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
                     Unsafe.As<T, byte>(ref value),
                     span.Length);
+
             return SpanHelpers.IndexOf(ref MemoryMarshal.GetReference(span), value, span.Length);
         }
 
@@ -351,6 +319,7 @@ namespace System
                     span.Length,
                     ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(value)),
                     value.Length);
+
             return SpanHelpers.IndexOf(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(value), value.Length);
         }
 
@@ -368,6 +337,7 @@ namespace System
                     ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
                     Unsafe.As<T, byte>(ref value),
                     span.Length);
+
             return SpanHelpers.LastIndexOf<T>(ref MemoryMarshal.GetReference(span), value, span.Length);
         }
 
@@ -386,6 +356,7 @@ namespace System
                     span.Length,
                     ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(value)),
                     value.Length);
+
             return SpanHelpers.LastIndexOf<T>(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(value), value.Length);
         }
 
@@ -527,6 +498,7 @@ namespace System
                     Unsafe.As<T, byte>(ref value0),
                     Unsafe.As<T, byte>(ref value1),
                     span.Length);
+
             return SpanHelpers.LastIndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, span.Length);
         }
 
@@ -548,6 +520,7 @@ namespace System
                     Unsafe.As<T, byte>(ref value1),
                     Unsafe.As<T, byte>(ref value2),
                     span.Length);
+
             return SpanHelpers.LastIndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, value2, span.Length);
         }
 
@@ -566,6 +539,7 @@ namespace System
                     span.Length,
                     ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(values)),
                     values.Length);
+
             return SpanHelpers.LastIndexOfAny(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(values), values.Length);
         }
 
@@ -585,6 +559,7 @@ namespace System
                     Unsafe.As<T, byte>(ref value0),
                     Unsafe.As<T, byte>(ref value1),
                     span.Length);
+
             return SpanHelpers.LastIndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, span.Length);
         }
 
@@ -606,6 +581,7 @@ namespace System
                     Unsafe.As<T, byte>(ref value1),
                     Unsafe.As<T, byte>(ref value2),
                     span.Length);
+
             return SpanHelpers.LastIndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, value2, span.Length);
         }
 
@@ -624,6 +600,7 @@ namespace System
                     span.Length,
                     ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(values)),
                     values.Length);
+
             return SpanHelpers.LastIndexOfAny<T>(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(values), values.Length);
         }
 
@@ -635,33 +612,12 @@ namespace System
             where T : IEquatable<T>
         {
             int length = first.Length;
-            if (typeof(T) == typeof(byte) || typeof(T) == typeof(sbyte))
+            if (default(T) != null && IsTypeComparableAsBytes<T>(out nuint size))
                 return length == second.Length &&
                 SpanHelpers.SequenceEqual(
                     ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(first)),
                     ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(second)),
-                    length);
-
-            if (typeof(T) == typeof(char) || typeof(T) == typeof(short) || typeof(T) == typeof(ushort))
-                return length == second.Length &&
-                SpanHelpers.SequenceEqualBytes(
-                    ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(first)),
-                    ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(second)),
-                    ((nuint)length) * 2); // If this multiplication overflows, the Span we got overflows the entire address range. There's no happy outcome for this api in such a case so we choose not to take the overhead of checking. 
-
-            if (typeof(T) == typeof(int) || typeof(T) == typeof(uint))
-                return length == second.Length &&
-                SpanHelpers.SequenceEqualBytes(
-                    ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(first)),
-                    ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(second)),
-                    ((nuint)length) * 4); // If this multiplication overflows, the Span we got overflows the entire address range. There's no happy outcome for this api in such a case so we choose not to take the overhead of checking. 
-
-            if (typeof(T) == typeof(long) || typeof(T) == typeof(ulong))
-                return length == second.Length &&
-                SpanHelpers.SequenceEqualBytes(
-                    ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(first)),
-                    ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(second)),
-                    ((nuint)length) * 8); // If this multiplication overflows, the Span we got overflows the entire address range. There's no happy outcome for this api in such a case so we choose not to take the overhead of checking. 
+                    ((nuint)length) * size);  // If this multiplication overflows, the Span we got overflows the entire address range. There's no happy outcome for this api in such a case so we choose not to take the overhead of checking.
 
             return length == second.Length && SpanHelpers.SequenceEqual(ref MemoryMarshal.GetReference(first), ref MemoryMarshal.GetReference(second), length);
         }
@@ -679,6 +635,7 @@ namespace System
                     first.Length,
                     ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(second)),
                     second.Length);
+
             return SpanHelpers.SequenceCompareTo(ref MemoryMarshal.GetReference(first), first.Length, ref MemoryMarshal.GetReference(second), second.Length);
         }
 
@@ -690,12 +647,13 @@ namespace System
             where T : IEquatable<T>
         {
             int valueLength = value.Length;
-            if (typeof(T) == typeof(byte))
+            if (default(T) != null && IsTypeComparableAsBytes<T>(out nuint size))
                 return valueLength <= span.Length &&
                 SpanHelpers.SequenceEqual(
                     ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
                     ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(value)),
-                    valueLength);
+                    ((nuint)valueLength) * size);  // If this multiplication overflows, the Span we got overflows the entire address range. There's no happy outcome for this api in such a case so we choose not to take the overhead of checking.
+
             return valueLength <= span.Length && SpanHelpers.SequenceEqual(ref MemoryMarshal.GetReference(span), ref MemoryMarshal.GetReference(value), valueLength);
         }
 
@@ -707,12 +665,13 @@ namespace System
             where T : IEquatable<T>
         {
             int valueLength = value.Length;
-            if (typeof(T) == typeof(byte))
+            if (default(T) != null && IsTypeComparableAsBytes<T>(out nuint size))
                 return valueLength <= span.Length &&
                 SpanHelpers.SequenceEqual(
                     ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
                     ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(value)),
-                    valueLength);
+                    ((nuint)valueLength) * size);  // If this multiplication overflows, the Span we got overflows the entire address range. There's no happy outcome for this api in such a case so we choose not to take the overhead of checking.
+
             return valueLength <= span.Length && SpanHelpers.SequenceEqual(ref MemoryMarshal.GetReference(span), ref MemoryMarshal.GetReference(value), valueLength);
         }
 
@@ -725,12 +684,13 @@ namespace System
         {
             int spanLength = span.Length;
             int valueLength = value.Length;
-            if (typeof(T) == typeof(byte))
+            if (default(T) != null && IsTypeComparableAsBytes<T>(out nuint size))
                 return valueLength <= spanLength &&
                 SpanHelpers.SequenceEqual(
                     ref Unsafe.As<T, byte>(ref Unsafe.Add(ref MemoryMarshal.GetReference(span), spanLength - valueLength)),
                     ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(value)),
-                    valueLength);
+                    ((nuint)valueLength) * size);  // If this multiplication overflows, the Span we got overflows the entire address range. There's no happy outcome for this api in such a case so we choose not to take the overhead of checking.
+
             return valueLength <= spanLength &&
                 SpanHelpers.SequenceEqual(
                     ref Unsafe.Add(ref MemoryMarshal.GetReference(span), spanLength - valueLength),
@@ -747,12 +707,13 @@ namespace System
         {
             int spanLength = span.Length;
             int valueLength = value.Length;
-            if (typeof(T) == typeof(byte))
+            if (default(T) != null && IsTypeComparableAsBytes<T>(out nuint size))
                 return valueLength <= spanLength &&
                 SpanHelpers.SequenceEqual(
                     ref Unsafe.As<T, byte>(ref Unsafe.Add(ref MemoryMarshal.GetReference(span), spanLength - valueLength)),
                     ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(value)),
-                    valueLength);
+                    ((nuint)valueLength) * size);  // If this multiplication overflows, the Span we got overflows the entire address range. There's no happy outcome for this api in such a case so we choose not to take the overhead of checking.
+
             return valueLength <= spanLength &&
                 SpanHelpers.SequenceEqual(
                     ref Unsafe.Add(ref MemoryMarshal.GetReference(span), spanLength - valueLength),
@@ -761,6 +722,24 @@ namespace System
         }
 
         /// <summary>
+        /// Reverses the sequence of the elements in the entire span.
+        /// </summary>
+        public static void Reverse<T>(this Span<T> span)
+        {
+            ref T p = ref MemoryMarshal.GetReference(span);
+            int i = 0;
+            int j = span.Length - 1;
+            while (i < j)
+            {
+                T temp = Unsafe.Add(ref p, i);
+                Unsafe.Add(ref p, i) = Unsafe.Add(ref p, j);
+                Unsafe.Add(ref p, j) = temp;
+                i++;
+                j--;
+            }
+        }
+
+        /// <summary>
         /// Creates a new span over the target array.
         /// </summary>
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -1326,5 +1305,36 @@ namespace System
                 value, comparer);
             return BinarySearch(span, comparable);
         }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        private static bool IsTypeComparableAsBytes<T>(out nuint size)
+        {
+            if (typeof(T) == typeof(byte) || typeof(T) == typeof(sbyte))
+            {
+                size = (nuint)sizeof(byte);
+                return true;
+            }
+
+            if (typeof(T) == typeof(char) || typeof(T) == typeof(short) || typeof(T) == typeof(ushort))
+            {
+                size = (nuint)sizeof(char);
+                return true;
+            }
+
+            if (typeof(T) == typeof(int) || typeof(T) == typeof(uint))
+            {
+                size = (nuint)sizeof(int);
+                return true;
+            }
+
+            if (typeof(T) == typeof(long) || typeof(T) == typeof(ulong))
+            {
+                size = (nuint)sizeof(long);
+                return true;
+            }
+
+            size = default;
+            return false;
+        }
     }
 }
index 3e699dd..b47a052 100644 (file)
@@ -14,12 +14,12 @@ using System.Numerics;
 #endif
 
 #if netstandard
-using nuint=System.NUInt;
+using nuint = System.NUInt;
 #else
 #if BIT64
-using nuint=System.UInt64;
+using nuint = System.UInt64;
 #else
-using nuint=System.UInt32;
+using nuint = System.UInt32;
 #endif // BIT64
 #endif // netstandard
 
@@ -896,57 +896,53 @@ namespace System
             return (int)(byte*)(index + 7);
         }
 
-        // This overload exists to maintain the "pit of success" where apis that specializes for T being byte continue to get directed to the fast byte-based version via the C#
-        // resolution rules.
-        public static bool SequenceEqual(ref byte first, ref byte second, int length) => SequenceEqualBytes(ref first, ref second, (nuint)length);
-
         // Optimized byte-based SequenceEquals. The "length" parameter for this one is declared a nuint rather than int as we also use it for types other than byte
         // where the length can exceed 2Gb once scaled by sizeof(T).
-        public static unsafe bool SequenceEqualBytes(ref byte first, ref byte second, nuint length)
+        public static unsafe bool SequenceEqual(ref byte first, ref byte second, nuint length)
         {
             if (Unsafe.AreSame(ref first, ref second))
                 goto Equal;
 
-            IntPtr i = (IntPtr)0; // Use IntPtr and byte* for arithmetic to avoid unnecessary 64->32->64 truncations
-            IntPtr n = (IntPtr)length;
+            nuint i = (nuint)0; // Explicit conversion required for netfx (NUInt)
+            nuint n = length;
 
 #if !netstandard11
-            if (Vector.IsHardwareAccelerated && (byte*)n >= (byte*)Vector<byte>.Count)
+            if (Vector.IsHardwareAccelerated && n >= (nuint)Vector<byte>.Count)
             {
-                n -= Vector<byte>.Count;
-                while ((byte*)n > (byte*)i)
+                n -= (nuint)Vector<byte>.Count;
+                while (n > i)
                 {
-                    if (Unsafe.ReadUnaligned<Vector<byte>>(ref Unsafe.AddByteOffset(ref first, i)) !=
-                        Unsafe.ReadUnaligned<Vector<byte>>(ref Unsafe.AddByteOffset(ref second, i)))
+                    if (Unsafe.ReadUnaligned<Vector<byte>>(ref Unsafe.AddByteOffset(ref first, (IntPtr)i)) !=
+                        Unsafe.ReadUnaligned<Vector<byte>>(ref Unsafe.AddByteOffset(ref second, (IntPtr)i)))
                     {
                         goto NotEqual;
                     }
-                    i += Vector<byte>.Count;
+                    i += (nuint)Vector<byte>.Count;
                 }
-                return Unsafe.ReadUnaligned<Vector<byte>>(ref Unsafe.AddByteOffset(ref first, n)) ==
-                       Unsafe.ReadUnaligned<Vector<byte>>(ref Unsafe.AddByteOffset(ref second, n));
+                return Unsafe.ReadUnaligned<Vector<byte>>(ref Unsafe.AddByteOffset(ref first, (IntPtr)n)) ==
+                       Unsafe.ReadUnaligned<Vector<byte>>(ref Unsafe.AddByteOffset(ref second, (IntPtr)n));
             }
 #endif
 
-            if ((byte*)n >= (byte*)sizeof(UIntPtr))
+            if (n >= (nuint)sizeof(UIntPtr))
             {
-                n -= sizeof(UIntPtr);
-                while ((byte*)n > (byte*)i)
+                n -= (nuint)sizeof(UIntPtr);
+                while (n > i)
                 {
-                    if (Unsafe.ReadUnaligned<UIntPtr>(ref Unsafe.AddByteOffset(ref first, i)) !=
-                        Unsafe.ReadUnaligned<UIntPtr>(ref Unsafe.AddByteOffset(ref second, i)))
+                    if (Unsafe.ReadUnaligned<UIntPtr>(ref Unsafe.AddByteOffset(ref first, (IntPtr)i)) !=
+                        Unsafe.ReadUnaligned<UIntPtr>(ref Unsafe.AddByteOffset(ref second, (IntPtr)i)))
                     {
                         goto NotEqual;
                     }
-                    i += sizeof(UIntPtr);
+                    i += (nuint)sizeof(UIntPtr);
                 }
-                return Unsafe.ReadUnaligned<UIntPtr>(ref Unsafe.AddByteOffset(ref first, n)) ==
-                       Unsafe.ReadUnaligned<UIntPtr>(ref Unsafe.AddByteOffset(ref second, n));
+                return Unsafe.ReadUnaligned<UIntPtr>(ref Unsafe.AddByteOffset(ref first, (IntPtr)n)) ==
+                       Unsafe.ReadUnaligned<UIntPtr>(ref Unsafe.AddByteOffset(ref second, (IntPtr)n));
             }
 
-            while ((byte*)n > (byte*)i)
+            while (n > i)
             {
-                if (Unsafe.AddByteOffset(ref first, i) != Unsafe.AddByteOffset(ref second, i))
+                if (Unsafe.AddByteOffset(ref first, (IntPtr)i) != Unsafe.AddByteOffset(ref second, (IntPtr)i))
                     goto NotEqual;
                 i += 1;
             }
@@ -989,47 +985,47 @@ namespace System
             if (Unsafe.AreSame(ref first, ref second))
                 goto Equal;
 
-            var minLength = firstLength;
-            if (minLength > secondLength) minLength = secondLength;
+            nuint minLength = (nuint)firstLength;
+            if (minLength > (nuint)secondLength) minLength = (nuint)secondLength;
 
-            IntPtr i = (IntPtr)0; // Use IntPtr and byte* for arithmetic to avoid unnecessary 64->32->64 truncations
-            IntPtr n = (IntPtr)minLength;
+            nuint i = (nuint)0;  // Explicit conversion required for netfx (NUInt)
+            nuint n = minLength;
 
 #if !netstandard11
-            if (Vector.IsHardwareAccelerated && (byte*)n > (byte*)Vector<byte>.Count)
+            if (Vector.IsHardwareAccelerated && n > (nuint)Vector<byte>.Count)
             {
-                n -= Vector<byte>.Count;
-                while ((byte*)n > (byte*)i)
+                n -= (nuint)Vector<byte>.Count;
+                while (n > i)
                 {
-                    if (Unsafe.ReadUnaligned<Vector<byte>>(ref Unsafe.AddByteOffset(ref first, i)) !=
-                        Unsafe.ReadUnaligned<Vector<byte>>(ref Unsafe.AddByteOffset(ref second, i)))
+                    if (Unsafe.ReadUnaligned<Vector<byte>>(ref Unsafe.AddByteOffset(ref first, (IntPtr)i)) !=
+                        Unsafe.ReadUnaligned<Vector<byte>>(ref Unsafe.AddByteOffset(ref second, (IntPtr)i)))
                     {
                         goto NotEqual;
                     }
-                    i += Vector<byte>.Count;
+                    i += (nuint)Vector<byte>.Count;
                 }
                 goto NotEqual;
             }
 #endif
 
-            if ((byte*)n > (byte*)sizeof(UIntPtr))
+            if (n > (nuint)sizeof(UIntPtr))
             {
-                n -= sizeof(UIntPtr);
-                while ((byte*)n > (byte*)i)
+                n -= (nuint)sizeof(UIntPtr);
+                while (n > i)
                 {
-                    if (Unsafe.ReadUnaligned<UIntPtr>(ref Unsafe.AddByteOffset(ref first, i)) !=
-                        Unsafe.ReadUnaligned<UIntPtr>(ref Unsafe.AddByteOffset(ref second, i)))
+                    if (Unsafe.ReadUnaligned<UIntPtr>(ref Unsafe.AddByteOffset(ref first, (IntPtr)i)) !=
+                        Unsafe.ReadUnaligned<UIntPtr>(ref Unsafe.AddByteOffset(ref second, (IntPtr)i)))
                     {
                         goto NotEqual;
                     }
-                    i += sizeof(UIntPtr);
+                    i += (nuint)sizeof(UIntPtr);
                 }
             }
 
         NotEqual:  // Workaround for https://github.com/dotnet/coreclr/issues/13549
-            while((byte*)minLength > (byte*)i)
+            while (minLength > i)
             {
-                int result = Unsafe.AddByteOffset(ref first, i).CompareTo(Unsafe.AddByteOffset(ref second, i));
+                int result = Unsafe.AddByteOffset(ref first, (IntPtr)i).CompareTo(Unsafe.AddByteOffset(ref second, (IntPtr)i));
                 if (result != 0) return result;
                 i += 1;
             }
index d1c62c8..88938ac 100644 (file)
@@ -49,7 +49,7 @@ namespace System
             }
             return -1;
         }
-        
+
         public static unsafe int IndexOf<T>(ref T searchSpace, T value, int length)
             where T : IEquatable<T>
         {
@@ -189,21 +189,21 @@ namespace System
             }
             return -1;
 
-            Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549
+        Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549
             return index;
-            Found1:
+        Found1:
             return index + 1;
-            Found2:
+        Found2:
             return index + 2;
-            Found3:
+        Found3:
             return index + 3;
-            Found4:
+        Found4:
             return index + 4;
-            Found5:
+        Found5:
             return index + 5;
-            Found6:
+        Found6:
             return index + 6;
-            Found7:
+        Found7:
             return index + 7;
         }
 
@@ -272,21 +272,21 @@ namespace System
             }
             return -1;
 
-            Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549
+        Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549
             return index;
-            Found1:
+        Found1:
             return index + 1;
-            Found2:
+        Found2:
             return index + 2;
-            Found3:
+        Found3:
             return index + 3;
-            Found4:
+        Found4:
             return index + 4;
-            Found5:
+        Found5:
             return index + 5;
-            Found6:
+        Found6:
             return index + 6;
-            Found7:
+        Found7:
             return index + 7;
         }