Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I create a Memory<T> from a Span<T>?

Tags:

c#

.net

.net-core

I'm trying to overload a parsing method to use a ReadOnlySpan<char> parameter in addition to the string version. The problem is that the implementation uses a Dictionary<string, T> for the parsing logic.

I tried switching it to a Dictionary<ReadOnlySpan<char>, T> but of course that didn't work as ReadOnlySpan<char> isn't allowed as a generic parameter since it's a stack only object. I then switched it to using ReadOnlyMemory<char> which is allowed. I then implemented a basic Ordinal comparer but am now having troubles creating a ReadOnlyMemory<char> from the ReadOnlySpan<char> parameter. Is this possible?

Update

It seems that this is not possible. In order to support the scenario I've posted above I will change the dictionary to have an int key which is the hashcode of the ReadOnlySpan<char> and make the value a list with the string embedded in the element and manually have to resolve hash code collisions.

like image 900
TylerBrinkley Avatar asked Jun 29 '18 19:06

TylerBrinkley


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 is span in C sharp?

Span<T> is a ref-like type as it contains a ref field, and ref fields can refer not only to the beginning of objects like arrays, but also to the middle of them: C# Copy. var arr = new byte[100]; Span<byte> interiorRef1 = arr.

What is readonly span?

Equality(ReadOnlySpan<T>, ReadOnlySpan<T>) Returns a value that indicates whether two ReadOnlySpan<T> instances are equal. Implicit(ArraySegment<T> to ReadOnlySpan<T>) Defines an implicit conversion of an ArraySegment<T> to a ReadOnlySpan<T>. Implicit(T[] to ReadOnlySpan<T>)


1 Answers

TL;DR:

You can go Memory<T> to Span<T>, but not the other way around.

Background:

There is an informative 2018 MSDN Magazine article article that introduces Span<T> in a 2018 MSDN Magazine article

Span<T> instances can only live on the stack, not on the heap. This means you can’t box spans (and thus can’t use Span<T> with existing reflection invoke APIs, for example, as they require boxing). It means you can’t have Span<T> fields in classes, or even in non-ref-like structs. It means you can’t use spans in places where they might implicitly become fields on classes, for instance by capturing them into lambdas or as locals in async methods or iterators (as those “locals” may end up being fields on the compiler-generated state machines.) It also means you can’t use Span<T> as a generic argument, as instances of that type argument could end up getting boxed or otherwise stored to the heap (and there’s currently no “where T : ref struct” constraint available).

...

You can create a Memory<T> from an array and slice it just as you would a span, but it’s a (non-ref-like) struct and can live on the heap. Then, when you want to do synchronous processing, you can get a Span<T> from it, for example:

static async Task<int> ChecksumReadAsync(Memory<byte> buffer, Stream stream)
{
  int bytesRead = await stream.ReadAsync(buffer);
  return Checksum(buffer.Span.Slice(0, bytesRead));
  // Or buffer.Slice(0, bytesRead).Span
}
static int Checksum(Span<byte> buffer) { ... }

I think his article clears it up better than me writing my own answer.

like image 132
Svek Avatar answered Sep 22 '22 16:09

Svek