KEMBAR78
[API Proposal]: `List<T>.Create<TState>(int, TState, SpanAction<T, TState>)` · Issue #80756 · dotnet/runtime · GitHub
Skip to content

[API Proposal]: List<T>.Create<TState>(int, TState, SpanAction<T, TState>) #80756

@neon-sunset

Description

@neon-sunset

Background and motivation

As of today, we do not have an API that would allow to safely initialize a List<T>'s underlying buffer directly.

While working on #80633 and investigating available ways to avoid using for (...) { list.Add(element); } in IListProvider<T>.ToList() implementations, there seemed to be a couple of viable options:

However, it appears we do already have an example of similar use case that solves the same issue: string.Create.
Re-using this pattern for List<T> would achieve safety (span cannot escape) and performance (no extra .Add() calls with state mutation, elided bounds check) at the same time without having to be hidden in CollectionsMarshal class.

API Proposal

namespace System.Collections.Generic;

public partial class List<T>
{
    public static List<T> Create<TState>(int count, TState state, SpanAction<T, TState> action);
}

API Usage

partial class SelectArrayIterator<TSource, TResult>
{
    public List<TResult> ToList()
    {
        return List<TResult>.Create(_source.Length, this, (span, instance) =>
        {
            TSource[] source = instance._source;
            Func<TSource, TResult> selector = instance._selector;
            
            // Assert .Length equality between span and source to elide bounds check
            for (int i = 0; i < span.Length; i++)
            {
                span[i] = _selector(source[i]);
            }
        }
    }
}

Alternative Designs

Risks

  • Possible inconvenience when using it same as with string.Create
  • Expanding a widely used type which increases code size and compilation time?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions