Skip to content
This repository has been archived by the owner on Aug 2, 2023. It is now read-only.

Adding Span IndexOf that takes an index and count #1278

Closed
wants to merge 9 commits into from
100 changes: 84 additions & 16 deletions src/System.Slices/System/SpanExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,36 +12,104 @@ namespace System
/// </summary>
public static partial class SpanExtensionsLabs
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool StartsWith(this ReadOnlySpan<byte> bytes, ReadOnlySpan<byte> slice)
{
if (slice.Length > bytes.Length)
{
return false;
}

for (int i = 0; i < slice.Length; i++)
{
if (bytes[i] != slice[i])
{
return false;
}
}

return true;
int length = slice.Length;
return bytes.Length >= length && (length == 0 || bytes.Slice(0, length).SequenceEqual(slice));
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool StartsWith<T>(this ReadOnlySpan<T> items, ReadOnlySpan<T> slice)
where T : struct, IEquatable<T>
{
if (slice.Length > items.Length) return false;
return items.Slice(0, slice.Length).SequenceEqual(slice);
int length = slice.Length;
return items.Length >= length && (length == 0 || items.Slice(0, length).SequenceEqual(slice));
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int IndexOf(this ReadOnlyMemory<byte> memory, ReadOnlySpan<byte> values)
{
return SpanExtensions.IndexOf(memory.Span, values);
}

/// <summary>
/// Searches for the specified value starting at the specified index and returns the index of its first occurrence. If not found, returns -1.
/// </summary>
/// <param name="span">The span to search.</param>
/// <param name="index">The index within the span from where to start the search.</param>
/// <param name="count">The number of bytes to search starting from the index.</param>
/// <param name="value">The value to search for.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int IndexOf(this Span<byte> span, byte value, int startIndex, int count)
{
return IndexOfHelper(ref span.DangerousGetPinnableReference(), startIndex, count, value, span.Length);
}

/// <summary>
/// Searches for the specified value starting at the specified index and returns the index of its first occurrence. If not found, returns -1.
/// </summary>
/// <param name="span">The span to search.</param>
/// <param name="index">The index within the span from where to start the search.</param>
/// <param name="count">The number of bytes to search starting from the index.</param>
/// <param name="value">The value to search for.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int IndexOf(this ReadOnlySpan<byte> span, byte value, int startIndex, int count)
{
return IndexOfHelper(ref span.DangerousGetPinnableReference(), startIndex, count, value, span.Length);
}

private static int IndexOfHelper(ref byte searchSpace, int startIndex, int count, byte value, int length)
{
Debug.Assert(length >= 0);

int index = startIndex - 1;
int remainingLength = Math.Min(count, length - startIndex);
while (remainingLength >= 8)
{
if (value == Unsafe.Add(ref searchSpace, ++index))
return index;
if (value == Unsafe.Add(ref searchSpace, ++index))
return index;
if (value == Unsafe.Add(ref searchSpace, ++index))
return index;
if (value == Unsafe.Add(ref searchSpace, ++index))
return index;
if (value == Unsafe.Add(ref searchSpace, ++index))
return index;
if (value == Unsafe.Add(ref searchSpace, ++index))
return index;
if (value == Unsafe.Add(ref searchSpace, ++index))
return index;
if (value == Unsafe.Add(ref searchSpace, ++index))
return index;

remainingLength -= 8;
}

while (remainingLength >= 4)
{
if (value == Unsafe.Add(ref searchSpace, ++index))
return index;
if (value == Unsafe.Add(ref searchSpace, ++index))
return index;
if (value == Unsafe.Add(ref searchSpace, ++index))
return index;
if (value == Unsafe.Add(ref searchSpace, ++index))
return index;

remainingLength -= 4;
}

while (remainingLength > 0)
{
if (value == Unsafe.Add(ref searchSpace, ++index))
return index;

remainingLength--;
}
return -1;
}
}
}

17 changes: 3 additions & 14 deletions src/System.Slices/System/SpanExtensions_text.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,22 +106,11 @@ public struct SplitEnumerator
{
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool StartsWith(this ReadOnlySpan<char> str, ReadOnlySpan<char> value)
{
if (value.Length > str.Length)
{
return false;
}

for (int i = 0; i < value.Length; i++)
{
if (str[i] != value[i])
{
return false;
}
}

return true;
int length = value.Length;
return str.Length >= length && (length == 0 || str.Slice(0, length).SequenceEqual(value));
}
}
}
Expand Down
Loading