#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
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);
}
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);
}
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);
}
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);
}
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);
}
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>
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
{
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),
{
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),
}
/// <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)]
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;
+ }
}
}
#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
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;
}
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;
}