using Internal.Runtime.CompilerServices;
#endif
+#if netstandard
+using nuint=System.NUInt;
+#else
+#if BIT64
+using nuint=System.UInt64;
+#else
+using nuint=System.UInt32;
+#endif // BIT64
+#endif // netstandard
+
namespace System
{
/// <summary>
where T : IEquatable<T>
{
int length = first.Length;
- if (typeof(T) == typeof(byte))
+ 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))
+ 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.
+
return length == second.Length && SpanHelpers.SequenceEqual(ref MemoryMarshal.GetReference(first), ref MemoryMarshal.GetReference(second), length);
}
using System.Numerics;
#endif
+#if netstandard
+using nuint=System.NUInt;
+#else
+#if BIT64
+using nuint=System.UInt64;
+#else
+using nuint=System.UInt32;
+#endif // BIT64
+#endif // netstandard
+
namespace System
{
internal static partial class SpanHelpers
return (int)(byte*)(index + 7);
}
- public static unsafe bool SequenceEqual(ref byte first, ref byte second, int length)
- {
- Debug.Assert(length >= 0);
+ // 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)
+ {
if (Unsafe.AreSame(ref first, ref second))
goto Equal;