// 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.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using Internal.Runtime.CompilerServices;
#if BIT64
using nuint = System.UInt64;
#else
using nuint = System.UInt32;
#endif // BIT64
namespace System
{
///
/// Extension methods for Span{T}, Memory{T}, and friends.
///
public static partial class MemoryExtensions
{
///
/// Indicates whether the specified span contains only white-space characters.
///
public static bool IsWhiteSpace(this ReadOnlySpan span)
{
for (int i = 0; i < span.Length; i++)
{
if (!char.IsWhiteSpace(span[i]))
return false;
}
return true;
}
///
/// Searches for the specified value and returns true if found. If not found, returns false. Values are compared using IEquatable{T}.Equals(T).
///
///
/// The span to search.
/// The value to search for.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Contains(this Span span, T value)
#nullable disable // to enable use with both T and T? for reference types due to IEquatable being invariant
where T : IEquatable
#nullable restore
{
if (RuntimeHelpers.IsBitwiseEquatable())
{
if (Unsafe.SizeOf() == sizeof(byte))
return SpanHelpers.Contains(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
Unsafe.As(ref value),
span.Length);
if (Unsafe.SizeOf() == sizeof(char))
return SpanHelpers.Contains(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
Unsafe.As(ref value),
span.Length);
}
return SpanHelpers.Contains(ref MemoryMarshal.GetReference(span), value, span.Length);
}
///
/// Searches for the specified value and returns true if found. If not found, returns false. Values are compared using IEquatable{T}.Equals(T).
///
///
/// The span to search.
/// The value to search for.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Contains(this ReadOnlySpan span, T value)
#nullable disable // to enable use with both T and T? for reference types due to IEquatable being invariant
where T : IEquatable
#nullable restore
{
if (RuntimeHelpers.IsBitwiseEquatable())
{
if (Unsafe.SizeOf() == sizeof(byte))
return SpanHelpers.Contains(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
Unsafe.As(ref value),
span.Length);
if (Unsafe.SizeOf() == sizeof(char))
return SpanHelpers.Contains(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
Unsafe.As(ref value),
span.Length);
}
return SpanHelpers.Contains(ref MemoryMarshal.GetReference(span), value, span.Length);
}
///
/// Searches for the specified value and returns the index of its first occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
///
/// The span to search.
/// The value to search for.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int IndexOf(this Span span, T value)
#nullable disable // to enable use with both T and T? for reference types due to IEquatable being invariant
where T : IEquatable
#nullable restore
{
if (RuntimeHelpers.IsBitwiseEquatable())
{
if (Unsafe.SizeOf() == sizeof(byte))
return SpanHelpers.IndexOf(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
Unsafe.As(ref value),
span.Length);
if (Unsafe.SizeOf() == sizeof(char))
return SpanHelpers.IndexOf(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
Unsafe.As(ref value),
span.Length);
}
return SpanHelpers.IndexOf(ref MemoryMarshal.GetReference(span), value, span.Length);
}
///
/// Searches for the specified sequence and returns the index of its first occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
///
/// The span to search.
/// The sequence to search for.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int IndexOf(this Span span, ReadOnlySpan value)
#nullable disable // to enable use with both T and T? for reference types due to IEquatable being invariant
where T : IEquatable
#nullable restore
{
if (RuntimeHelpers.IsBitwiseEquatable())
{
if (Unsafe.SizeOf() == sizeof(byte))
return SpanHelpers.IndexOf(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
span.Length,
ref Unsafe.As(ref MemoryMarshal.GetReference(value)),
value.Length);
if (Unsafe.SizeOf() == sizeof(char))
return SpanHelpers.IndexOf(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
span.Length,
ref Unsafe.As(ref MemoryMarshal.GetReference(value)),
value.Length);
}
return SpanHelpers.IndexOf(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(value), value.Length);
}
///
/// Searches for the specified value and returns the index of its last occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
///
/// The span to search.
/// The value to search for.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int LastIndexOf(this Span span, T value)
#nullable disable // to enable use with both T and T? for reference types due to IEquatable being invariant
where T : IEquatable
#nullable restore
{
if (RuntimeHelpers.IsBitwiseEquatable())
{
if (Unsafe.SizeOf() == sizeof(byte))
return SpanHelpers.LastIndexOf(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
Unsafe.As(ref value),
span.Length);
if (Unsafe.SizeOf() == sizeof(char))
return SpanHelpers.LastIndexOf(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
Unsafe.As(ref value),
span.Length);
}
return SpanHelpers.LastIndexOf(ref MemoryMarshal.GetReference(span), value, span.Length);
}
///
/// Searches for the specified sequence and returns the index of its last occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
///
/// The span to search.
/// The sequence to search for.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int LastIndexOf(this Span span, ReadOnlySpan value)
#nullable disable // to enable use with both T and T? for reference types due to IEquatable being invariant
where T : IEquatable
#nullable restore
{
if (Unsafe.SizeOf() == sizeof(byte) && RuntimeHelpers.IsBitwiseEquatable())
return SpanHelpers.LastIndexOf(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
span.Length,
ref Unsafe.As(ref MemoryMarshal.GetReference(value)),
value.Length);
return SpanHelpers.LastIndexOf(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(value), value.Length);
}
///
/// Determines whether two sequences are equal by comparing the elements using IEquatable{T}.Equals(T).
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool SequenceEqual(this Span span, ReadOnlySpan other)
#nullable disable // to enable use with both T and T? for reference types due to IEquatable being invariant
where T : IEquatable
#nullable restore
{
int length = span.Length;
if (RuntimeHelpers.IsBitwiseEquatable())
{
nuint size = (nuint)Unsafe.SizeOf();
return length == other.Length &&
SpanHelpers.SequenceEqual(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
ref Unsafe.As(ref MemoryMarshal.GetReference(other)),
((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 == other.Length && SpanHelpers.SequenceEqual(ref MemoryMarshal.GetReference(span), ref MemoryMarshal.GetReference(other), length);
}
///
/// Determines the relative order of the sequences being compared by comparing the elements using IComparable{T}.CompareTo(T).
///
public static int SequenceCompareTo(this Span span, ReadOnlySpan other)
where T : IComparable
{
// Can't use IsBitwiseEquatable() below because that only tells us about
// equality checks, not about CompareTo checks.
if (typeof(T) == typeof(byte))
return SpanHelpers.SequenceCompareTo(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
span.Length,
ref Unsafe.As(ref MemoryMarshal.GetReference(other)),
other.Length);
if (typeof(T) == typeof(char))
return SpanHelpers.SequenceCompareTo(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
span.Length,
ref Unsafe.As(ref MemoryMarshal.GetReference(other)),
other.Length);
return SpanHelpers.SequenceCompareTo(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(other), other.Length);
}
///
/// Searches for the specified value and returns the index of its first occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
///
/// The span to search.
/// The value to search for.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int IndexOf(this ReadOnlySpan span, T value)
#nullable disable // to enable use with both T and T? for reference types due to IEquatable being invariant
where T : IEquatable
#nullable restore
{
if (RuntimeHelpers.IsBitwiseEquatable())
{
if (Unsafe.SizeOf() == sizeof(byte))
return SpanHelpers.IndexOf(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
Unsafe.As(ref value),
span.Length);
if (Unsafe.SizeOf() == sizeof(char))
return SpanHelpers.IndexOf(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
Unsafe.As(ref value),
span.Length);
}
return SpanHelpers.IndexOf(ref MemoryMarshal.GetReference(span), value, span.Length);
}
///
/// Searches for the specified sequence and returns the index of its first occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
///
/// The span to search.
/// The sequence to search for.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int IndexOf(this ReadOnlySpan span, ReadOnlySpan value)
#nullable disable // to enable use with both T and T? for reference types due to IEquatable being invariant
where T : IEquatable
#nullable restore
{
if (RuntimeHelpers.IsBitwiseEquatable())
{
if (Unsafe.SizeOf() == sizeof(byte))
return SpanHelpers.IndexOf(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
span.Length,
ref Unsafe.As(ref MemoryMarshal.GetReference(value)),
value.Length);
if (Unsafe.SizeOf() == sizeof(char))
return SpanHelpers.IndexOf(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
span.Length,
ref Unsafe.As(ref MemoryMarshal.GetReference(value)),
value.Length);
}
return SpanHelpers.IndexOf(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(value), value.Length);
}
///
/// Searches for the specified value and returns the index of its last occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
///
/// The span to search.
/// The value to search for.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int LastIndexOf(this ReadOnlySpan span, T value)
#nullable disable // to enable use with both T and T? for reference types due to IEquatable being invariant
where T : IEquatable
#nullable restore
{
if (RuntimeHelpers.IsBitwiseEquatable())
{
if (Unsafe.SizeOf() == sizeof(byte))
return SpanHelpers.LastIndexOf(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
Unsafe.As(ref value),
span.Length);
if (Unsafe.SizeOf() == sizeof(char))
return SpanHelpers.LastIndexOf(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
Unsafe.As(ref value),
span.Length);
}
return SpanHelpers.LastIndexOf(ref MemoryMarshal.GetReference(span), value, span.Length);
}
///
/// Searches for the specified sequence and returns the index of its last occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
///
/// The span to search.
/// The sequence to search for.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int LastIndexOf(this ReadOnlySpan span, ReadOnlySpan value)
#nullable disable // to enable use with both T and T? for reference types due to IEquatable being invariant
where T : IEquatable
#nullable restore
{
if (Unsafe.SizeOf() == sizeof(byte) && RuntimeHelpers.IsBitwiseEquatable())
return SpanHelpers.LastIndexOf(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
span.Length,
ref Unsafe.As(ref MemoryMarshal.GetReference(value)),
value.Length);
return SpanHelpers.LastIndexOf(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(value), value.Length);
}
///
/// Searches for the first index of any of the specified values similar to calling IndexOf several times with the logical OR operator. If not found, returns -1.
///
/// The span to search.
/// One of the values to search for.
/// One of the values to search for.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int IndexOfAny(this Span span, T value0, T value1)
#nullable disable // to enable use with both T and T? for reference types due to IEquatable being invariant
where T : IEquatable
#nullable restore
{
if (RuntimeHelpers.IsBitwiseEquatable())
{
if (Unsafe.SizeOf() == sizeof(byte))
return SpanHelpers.IndexOfAny(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
Unsafe.As(ref value0),
Unsafe.As(ref value1),
span.Length);
if (Unsafe.SizeOf() == sizeof(char))
return SpanHelpers.IndexOfAny(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
Unsafe.As(ref value0),
Unsafe.As(ref value1),
span.Length);
}
return SpanHelpers.IndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, span.Length);
}
///
/// Searches for the first index of any of the specified values similar to calling IndexOf several times with the logical OR operator. If not found, returns -1.
///
/// The span to search.
/// One of the values to search for.
/// One of the values to search for.
/// One of the values to search for.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int IndexOfAny(this Span span, T value0, T value1, T value2)
#nullable disable // to enable use with both T and T? for reference types due to IEquatable being invariant
where T : IEquatable
#nullable restore
{
if (RuntimeHelpers.IsBitwiseEquatable())
{
if (Unsafe.SizeOf() == sizeof(byte))
return SpanHelpers.IndexOfAny(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
Unsafe.As(ref value0),
Unsafe.As(ref value1),
Unsafe.As(ref value2),
span.Length);
if (Unsafe.SizeOf() == sizeof(char))
return SpanHelpers.IndexOfAny(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
Unsafe.As(ref value0),
Unsafe.As(ref value1),
Unsafe.As(ref value2),
span.Length);
}
return SpanHelpers.IndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, value2, span.Length);
}
///
/// Searches for the first index of any of the specified values similar to calling IndexOf several times with the logical OR operator. If not found, returns -1.
///
/// The span to search.
/// The set of values to search for.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int IndexOfAny(this Span span, ReadOnlySpan values)
#nullable disable // to enable use with both T and T? for reference types due to IEquatable being invariant
where T : IEquatable
#nullable restore
{
if (RuntimeHelpers.IsBitwiseEquatable())
{
if (Unsafe.SizeOf() == sizeof(byte))
{
ref byte valueRef = ref Unsafe.As(ref MemoryMarshal.GetReference(values));
if (values.Length == 2)
{
return SpanHelpers.IndexOfAny(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
valueRef,
Unsafe.Add(ref valueRef, 1),
span.Length);
}
else if (values.Length == 3)
{
return SpanHelpers.IndexOfAny(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
valueRef,
Unsafe.Add(ref valueRef, 1),
Unsafe.Add(ref valueRef, 2),
span.Length);
}
else
{
return SpanHelpers.IndexOfAny(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
span.Length,
ref valueRef,
values.Length);
}
}
if (Unsafe.SizeOf() == sizeof(char))
{
ref var valueRef = ref Unsafe.As(ref MemoryMarshal.GetReference(values));
if (values.Length == 5)
{
// Length 5 is a common length for FileSystemName expression (", <, >, *, ?) and in preference to 2 as it has an explicit overload
return SpanHelpers.IndexOfAny(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
valueRef,
Unsafe.Add(ref valueRef, 1),
Unsafe.Add(ref valueRef, 2),
Unsafe.Add(ref valueRef, 3),
Unsafe.Add(ref valueRef, 4),
span.Length);
}
else if (values.Length == 2)
{
// Length 2 is a common length for simple wildcards (*, ?), directory separators (/, \), quotes (", '), brackets, etc
return SpanHelpers.IndexOfAny(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
valueRef,
Unsafe.Add(ref valueRef, 1),
span.Length);
}
else if (values.Length == 4)
{
// Length 4 before 3 as 3 has an explicit overload
return SpanHelpers.IndexOfAny(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
valueRef,
Unsafe.Add(ref valueRef, 1),
Unsafe.Add(ref valueRef, 2),
Unsafe.Add(ref valueRef, 3),
span.Length);
}
else if (values.Length == 3)
{
return SpanHelpers.IndexOfAny(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
valueRef,
Unsafe.Add(ref valueRef, 1),
Unsafe.Add(ref valueRef, 2),
span.Length);
}
else if (values.Length == 1)
{
// Length 1 last, as ctoring a ReadOnlySpan to call this overload for a single value
// is already throwing away a bunch of performance vs just calling IndexOf
return SpanHelpers.IndexOf(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
valueRef,
span.Length);
}
}
}
return SpanHelpers.IndexOfAny(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(values), values.Length);
}
///
/// Searches for the first index of any of the specified values similar to calling IndexOf several times with the logical OR operator. If not found, returns -1.
///
/// The span to search.
/// One of the values to search for.
/// One of the values to search for.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int IndexOfAny(this ReadOnlySpan span, T value0, T value1)
#nullable disable // to enable use with both T and T? for reference types due to IEquatable being invariant
where T : IEquatable
#nullable restore
{
if (RuntimeHelpers.IsBitwiseEquatable())
{
if (Unsafe.SizeOf() == sizeof(byte))
return SpanHelpers.IndexOfAny(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
Unsafe.As(ref value0),
Unsafe.As(ref value1),
span.Length);
if (Unsafe.SizeOf() == sizeof(char))
return SpanHelpers.IndexOfAny(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
Unsafe.As(ref value0),
Unsafe.As(ref value1),
span.Length);
}
return SpanHelpers.IndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, span.Length);
}
///
/// Searches for the first index of any of the specified values similar to calling IndexOf several times with the logical OR operator. If not found, returns -1.
///
/// The span to search.
/// One of the values to search for.
/// One of the values to search for.
/// One of the values to search for.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int IndexOfAny(this ReadOnlySpan span, T value0, T value1, T value2)
#nullable disable // to enable use with both T and T? for reference types due to IEquatable being invariant
where T : IEquatable
#nullable restore
{
if (RuntimeHelpers.IsBitwiseEquatable())
{
if (Unsafe.SizeOf() == sizeof(byte))
return SpanHelpers.IndexOfAny(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
Unsafe.As(ref value0),
Unsafe.As(ref value1),
Unsafe.As(ref value2),
span.Length);
if (Unsafe.SizeOf() == sizeof(char))
return SpanHelpers.IndexOfAny(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
Unsafe.As(ref value0),
Unsafe.As(ref value1),
Unsafe.As(ref value2),
span.Length);
}
return SpanHelpers.IndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, value2, span.Length);
}
///
/// Searches for the first index of any of the specified values similar to calling IndexOf several times with the logical OR operator. If not found, returns -1.
///
/// The span to search.
/// The set of values to search for.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int IndexOfAny(this ReadOnlySpan span, ReadOnlySpan values)
#nullable disable // to enable use with both T and T? for reference types due to IEquatable being invariant
where T : IEquatable
#nullable restore
{
if (RuntimeHelpers.IsBitwiseEquatable())
{
if (Unsafe.SizeOf() == sizeof(byte))
{
ref byte valueRef = ref Unsafe.As(ref MemoryMarshal.GetReference(values));
if (values.Length == 2)
{
return SpanHelpers.IndexOfAny(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
valueRef,
Unsafe.Add(ref valueRef, 1),
span.Length);
}
else if (values.Length == 3)
{
return SpanHelpers.IndexOfAny(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
valueRef,
Unsafe.Add(ref valueRef, 1),
Unsafe.Add(ref valueRef, 2),
span.Length);
}
else
{
return SpanHelpers.IndexOfAny(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
span.Length,
ref valueRef,
values.Length);
}
}
if (Unsafe.SizeOf() == sizeof(char))
{
ref var valueRef = ref Unsafe.As(ref MemoryMarshal.GetReference(values));
if (values.Length == 5)
{
// Length 5 is a common length for FileSystemName expression (", <, >, *, ?) and in preference to 2 as it has an explicit overload
return SpanHelpers.IndexOfAny(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
valueRef,
Unsafe.Add(ref valueRef, 1),
Unsafe.Add(ref valueRef, 2),
Unsafe.Add(ref valueRef, 3),
Unsafe.Add(ref valueRef, 4),
span.Length);
}
else if (values.Length == 2)
{
// Length 2 is a common length for simple wildcards (*, ?), directory separators (/, \), quotes (", '), brackets, etc
return SpanHelpers.IndexOfAny(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
valueRef,
Unsafe.Add(ref valueRef, 1),
span.Length);
}
else if (values.Length == 4)
{
// Length 4 before 3 as 3 has an explicit overload
return SpanHelpers.IndexOfAny(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
valueRef,
Unsafe.Add(ref valueRef, 1),
Unsafe.Add(ref valueRef, 2),
Unsafe.Add(ref valueRef, 3),
span.Length);
}
else if (values.Length == 3)
{
return SpanHelpers.IndexOfAny(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
valueRef,
Unsafe.Add(ref valueRef, 1),
Unsafe.Add(ref valueRef, 2),
span.Length);
}
else if (values.Length == 1)
{
// Length 1 last, as ctoring a ReadOnlySpan to call this overload for a single value
// is already throwing away a bunch of performance vs just calling IndexOf
return SpanHelpers.IndexOf(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
valueRef,
span.Length);
}
}
}
return SpanHelpers.IndexOfAny(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(values), values.Length);
}
///
/// Searches for the last index of any of the specified values similar to calling LastIndexOf several times with the logical OR operator. If not found, returns -1.
///
/// The span to search.
/// One of the values to search for.
/// One of the values to search for.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int LastIndexOfAny(this Span span, T value0, T value1)
#nullable disable // to enable use with both T and T? for reference types due to IEquatable being invariant
where T : IEquatable
#nullable restore
{
if (Unsafe.SizeOf() == sizeof(byte) && RuntimeHelpers.IsBitwiseEquatable())
return SpanHelpers.LastIndexOfAny(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
Unsafe.As(ref value0),
Unsafe.As(ref value1),
span.Length);
return SpanHelpers.LastIndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, span.Length);
}
///
/// Searches for the last index of any of the specified values similar to calling LastIndexOf several times with the logical OR operator. If not found, returns -1.
///
/// The span to search.
/// One of the values to search for.
/// One of the values to search for.
/// One of the values to search for.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int LastIndexOfAny(this Span span, T value0, T value1, T value2)
#nullable disable // to enable use with both T and T? for reference types due to IEquatable being invariant
where T : IEquatable
#nullable restore
{
if (Unsafe.SizeOf() == sizeof(byte) && RuntimeHelpers.IsBitwiseEquatable())
return SpanHelpers.LastIndexOfAny(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
Unsafe.As(ref value0),
Unsafe.As(ref value1),
Unsafe.As(ref value2),
span.Length);
return SpanHelpers.LastIndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, value2, span.Length);
}
///
/// Searches for the last index of any of the specified values similar to calling LastIndexOf several times with the logical OR operator. If not found, returns -1.
///
/// The span to search.
/// The set of values to search for.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int LastIndexOfAny(this Span span, ReadOnlySpan values)
#nullable disable // to enable use with both T and T? for reference types due to IEquatable being invariant
where T : IEquatable
#nullable restore
{
if (Unsafe.SizeOf() == sizeof(byte) && RuntimeHelpers.IsBitwiseEquatable())
return SpanHelpers.LastIndexOfAny(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
span.Length,
ref Unsafe.As(ref MemoryMarshal.GetReference(values)),
values.Length);
return SpanHelpers.LastIndexOfAny(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(values), values.Length);
}
///
/// Searches for the last index of any of the specified values similar to calling LastIndexOf several times with the logical OR operator. If not found, returns -1.
///
/// The span to search.
/// One of the values to search for.
/// One of the values to search for.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int LastIndexOfAny(this ReadOnlySpan span, T value0, T value1)
#nullable disable // to enable use with both T and T? for reference types due to IEquatable being invariant
where T : IEquatable