Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

span<T> and streams

Tags:

I have been reading about span for a while now, and just tried to implement it. However, while I can get span to work I cannot figure out how to get a stream to accept it like they do in the examples. Other examples show int.parse supporting spans as well but I can't find overloads or extensions that make it possible.

I have tried it in both .net standard 2.0 and .net core 2.0

Please point me in the right direction to make this work.

Code example

Span<Byte> buffer = new Span<byte>();
int bytesRead = stream.Read(buffer);
like image 202
Christopher James Woods Avatar asked Apr 28 '18 16:04

Christopher James Woods


People also ask

What is span T?

A Span<T> represents a contiguous region of arbitrary memory. A Span<T> instance is often used to hold the elements of an array or a portion of an array. Unlike an array, however, a Span<T> instance can point to managed memory, native memory, or memory managed on the stack.

What are C# streams?

CSharp Online Training The stream is basically the sequence of bytes passing through the communication path. There are two main streams: the input stream and the output stream. The input stream is used for reading data from file (read operation) and the output stream is used for writing into the file (write operation).


2 Answers

Let's look at an example that I have handy, where the Span<T> happens to come from PipeWriter.

var bufferSpan = pipeWriter.GetSpan(count);
stream.Write( /* Darn, I need an array, because no Span<T> overloads outside Core 2.1! */ );

Try to get a Memory<T> instead of Span<T>, for which you can get the underlying array (except under some exotic circumstances).

var bufferMemory = pipeWriter.GetMemory(count); // Instead of GetSpan()
var bufferArraySegment = bufferMemory.GetUnderlyingArray();
stream.Write(bufferArraySegment.Array, bufferArraySegment.Offset, bufferArraySegment.Count); // Yay!

GetUnderlyingArray() here is a small extension method:

/// <summary>
/// Memory extensions for framework versions that do not support the new Memory overloads on various framework methods.
/// </summary>
internal static class MemoryExtensions
{
    public static ArraySegment<byte> GetUnderlyingArray(this Memory<byte> bytes) => GetUnderlyingArray((ReadOnlyMemory<byte>)bytes);
    public static ArraySegment<byte> GetUnderlyingArray(this ReadOnlyMemory<byte> bytes)
    {
        if (!MemoryMarshal.TryGetArray(bytes, out var arraySegment)) throw new NotSupportedException("This Memory does not support exposing the underlying array.");
        return arraySegment;
    }
}

All in all, this lets you use the methods with a 'modern' return type in combination with the 'old' framework overloads - without any copying. :)

like image 29
Timo Avatar answered Sep 28 '22 11:09

Timo


Span results from streams are supported in .NET Core 2.1. If you check the current source code of eg Stream you'll see it has overloads like Read(Span) that read into a Span<byte> instead of byte[], or Write(ReadOnlySpan) that can write out a ReadOnlySpan<byte> instead of a byte[], overloads that use Memory etc.

To target .NET Core 2.1, you'll have to install at least Visual Studio 2017 15.7 Preview 4 or the latest SDK for .NET Core 2.1

like image 65
Panagiotis Kanavos Avatar answered Sep 28 '22 11:09

Panagiotis Kanavos