Create a Span from multiple slices

Viewed 804

Is it currently possible to create a Span<T> (and related types) based on multiple slices of another span?

What I'm trying to achieve is a type of multi-substring.

Consider the following array of chars:

[M][y][ ][b][r][i][l][l][i][a][n][t][ ][s][e][n][t][e][n][c][e]

I'd like to assemble a new sentence based on a list of ranges.

var newSentence = Span.MultiSlice(originalSentence, new List<(int start, int length)> { (3, 5), (13, 4) })

Should result in a ReadOnlySpan<char> that represents brillsent.

Also would it be possible to assemble this Span by slicing from different spans, instead of just the one originalSentence, as in the above example?

1 Answers

No, this is by-definition:

https://docs.microsoft.com/en-us/dotnet/api/system.span-1?view=netcore-3.0

Provides a type- and memory-safe representation of a contiguous region of arbitrary memory.

Your intended use-case breaks Span<T>'s contract because you aren't representing a single contiguous address space.

It sounds like you just want an IEnumerable<Char> that operates over a series of slices:

using OneOf; // https://github.com/mcintyre321/OneOf

using Run = OneOf<String,Span<Char>,IEnumerable<Char>>;

public class CompositeString
{
    private readonly List<Run> runs = new List<Run>();

    public void Add( String str ) => this.runs.Add( str );
    public void Add( Span<Char> span ) => this.runs.Add( span );
    public void Add( IEnumerable<Char> chars ) => this.runs.Add( chars ); 

    public void WriteTo( TextWriter wtr )
    {
        foreach( Run run in this.runs )
        {
            run.Switch(
                ( String s ) => wtr.Write( s ),
                ( Span<Char> span ) =>
                { // Span<T> doesn't implement IEnumerable<T>, but you can still use it with a `foreach`:
                    foreach( Char c in span ) wtr.Write( c );
                },
                ( IEnumerable<Char> chars ) =>
                {
                    foreach( Char c in chars ) wtr.Write( c );
                },
            );
        }
    }

    public override void ToString()
    {
        using( StringWriter wtr = new StringWriter() )
        {
            this.WriteTo( wtr );
            return wtr.ToString();
        }
    }
}
Related