Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add MemoryExtension APIs to get parity with array APIs #24420

Closed
ahsonkhan opened this issue Dec 12, 2017 · 1 comment
Closed

Add MemoryExtension APIs to get parity with array APIs #24420

ahsonkhan opened this issue Dec 12, 2017 · 1 comment
Assignees
Labels
api-approved API was approved in API review, it can be implemented area-System.Memory
Milestone

Comments

@ahsonkhan
Copy link
Member

As part of completing the MemoryExtensions feature - https://github.com/dotnet/corefx/issues/24880 - here are the proposed Span extension APIs that should get added to get parity with the available APIs on array.

Proposed API Additions

public static class MemoryExtensions
{
    // Slice + CopyTo APIs can be used instead, hence we don't need the overloads
    //public static void Copy<T>(this ReadOnlySpan<T> sourceSpan, Span<T> destinationSpan, int length);
    //public static void Copy<T>(this ReadOnlySpan<T> sourceSpan, int sourceIndex, Span<T> destinationSpan, int destinationIndex, int length);
    
    // Span CopyTo API is already "constrained" in that if it throws an exception, the destination remains unchanged. Hence, we don't need this API
    //public static void ConstrainedCopy<T>(this ReadOnlySpan<T> sourceSpan, int sourceIndex, Span<T> destinationSpan, int destinationIndex, int length);
    
    public static bool Exists<T>(this ReadOnlySpan<T> span, Predicate<T> match);

    public static T Find<T>(this ReadOnlySpan<T> span, Predicate<T> match);
    public static int FindIndex<T>(this ReadOnlySpan<T> span, Predicate<T> match);
    // Slice the span before calling the method above, hence we don't need the overloads
    //public static int FindIndex<T>(this ReadOnlySpan<T> span, int startIndex, Predicate<T> match);
    //public static int FindIndex<T>(this ReadOnlySpan<T> span, int startIndex, int count, Predicate<T> match);
    
    public static T FindLast<T>(this ReadOnlySpan<T> span, Predicate<T> match);
    public static int FindLastIndex<T>(this ReadOnlySpan<T> span, Predicate<T> match);
    // Slice the span before calling the method above, hence we don't need the overloads
    //public static int FindLastIndex<T>(this ReadOnlySpan<T> span, int startIndex, Predicate<T> match);
    //public static int FindLastIndex<T>(this ReadOnlySpan<T> span, int startIndex, int count, Predicate<T> match);
    
    // Requires allocation
    public static T[] FindAll<T>(this ReadOnlySpan<T> span, Predicate<T> match);
    // Alternative to avoid allocation
    public static bool TryFindAll<T>(this ReadOnlySpan<T> span, Predicate<T> match, Span<T> result);

    public static void Reverse<T>(this Span<T>);
    // Slice the span before calling the method above, hence we don't need the overload
    //public static void Reverse<T>(this Span<T>, int index, int length); 

    public static bool TrueForAll<T>(this ReadOnlySpan<T> span, Predicate<T> match);

}

Sample Usage and Rationale

The API usage should be almost identical to the Array API usage. Getting API parity with array makes it easier for customers to port their array-based code to Span wherever possible.

Example sample usage:

public static void UseTrueForAll()
{
    ReadOnlySpan<string> values1 = new string[] { "Y2K", "A2000", "DC2A6", "MMXIV", "0C3" };
    ReadOnlySpan<string> values2 = new string[] { "Y2", "A2000", "DC2A6", "MMXIV_0", "0C3" };

    Assert.False(values1.TrueForAll(value => 
    {
        return int.TryParse(value.Substring(value.Length - 1), out int s);
    }));
    Assert.True(values2.TrueForAll(value => 
    {
        return int.TryParse(value.Substring(value.Length - 1), out int s);
    }));

    Assert.False(values1.TrueForAll(EndsWithANumber));
    Assert.True(values2.TrueForAll(EndsWithANumber));
}

private static bool EndsWithANumber(string value)
{
    return int.TryParse(value.Substring(value.Length - 1), out int s);
}

cc @KrzysztofCwalina, @dotnet/corefxlab-contrib, @stephentoub, @jkotas

@terrajobst
Copy link
Member

terrajobst commented Jan 12, 2018

Video

Let's only add Reverse and not the rest. Reason being that delegate invocations could potentially become a perf trap; the have obvious 1 - 5 line replacements for the caller. Reverse can be optimized and seems generally useful.

@ahsonkhan ahsonkhan self-assigned this Jan 16, 2018
@msftgits msftgits transferred this issue from dotnet/corefx Jan 31, 2020
@msftgits msftgits added this to the 2.1.0 milestone Jan 31, 2020
@dotnet dotnet locked as resolved and limited conversation to collaborators Dec 19, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api-approved API was approved in API review, it can be implemented area-System.Memory
Projects
None yet
Development

No branches or pull requests

3 participants