Skip to content

Change IndexOf<T>([ReadOnly]Span<T>, ref/in T) to return -1 instead of throwing #189

@DaZombieKiller

Description

@DaZombieKiller

Overview

Currently, the by-ref IndexOf extensions for [ReadOnly]Span<T> throw when the supplied value does not lie within the span. This is not very intuitive, one would normally expect the API to return -1 in this scenario (especially given that the returned index is a signed integer.)

API breakdown

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int IndexOf<T>(this Span<T> span, ref T value)
{
    ref T r0 = ref MemoryMarshal.GetReference(span);
    IntPtr byteOffset = Unsafe.ByteOffset(ref r0, ref value);

    nint elementOffset = byteOffset / (nint)(uint)Unsafe.SizeOf<T>();

    if ((nuint)elementOffset >= (uint)span.Length)
    {
-        ThrowArgumentOutOfRangeExceptionForInvalidReference();
+        return -1;
    }

    return (int)elementOffset;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int IndexOf<T>(this ReadOnlySpan<T> span, in T value)
{
    ref T r0 = ref MemoryMarshal.GetReference(span);
    ref T r1 = ref Unsafe.AsRef(value);
    IntPtr byteOffset = Unsafe.ByteOffset(ref r0, ref r1);

    nint elementOffset = byteOffset / (nint)(uint)Unsafe.SizeOf<T>();

    if ((nuint)elementOffset >= (uint)span.Length)
    {
-        SpanExtensions.ThrowArgumentOutOfRangeExceptionForInvalidReference();
+        return -1;
    }

    return (int)elementOffset;
}

Usage example

int index = span.IndexOf(ref value);

if (index == -1)
{
    // value does not exist
}

// value exists

Breaking change?

Yes

Alternatives

Alternatively, a non-throwing variant of the API could be provided.

Additional context

No response

Help us help you

No, just wanted to propose this

Metadata

Metadata

Assignees

No one assigned

    Labels

    api-approved 🚀A proposal that has been approved: PRs are a gofeature request 📬A request for new changes to improve functionalityhigh-performance 🚂Issues/PRs for the HighPerformance packageintroduce breaking changes 💥This change would be a breaking changenext preview ✈️This changes will be available in the upcoming preview

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions