Runtime: [API Proposal] API for interpretting Span<byte> as struct without copying

Created on 22 Jun 2018  路  11Comments  路  Source: dotnet/runtime

MemoryMarshal contains several APIs that allow reinterpreting Span<byte>, but none of them are a good fit for interpreting Span as struct without copying:

  • MemoryMarshal.Read allows interpreting Span<byte> as arbitrary struct. It creates a local copy that is fine and beneficial for small structs, but becomes expensive for large structs.
  • MemoryMarshal.Cast allows interpreting Span<byte> as sequence of arbitrary structs. It does not create a local copy, but comes with extra overhead required to compute the length of the resulting span.
  • MemoryMarshal.GetReference + Unsafe.As does not create a local copy, but also skips any bounds checks that is not good for security defense in depth.

Proposal

Add methods that allow interpreting Span<byte> as arbitrary large struct without copying to MemoryMarshal.

static class MemoryMarshal
{
    public static ref readonly T AsRef<T>(System.ReadOnlySpan<byte> span) where T : struct { throw null; }
    public static ref T AsRef(System.Span<byte> span) where T : struct { throw null; }
}

Implementation of these methods is going to be faster functional equivalent of ref MemoryMarshal.Cast<byte, T>(span)[0].

These APIs come with the same set of portability caveats as Memory.Cast. They can be only used when the memory block is sufficiently aligned by other means; or when the target platform does not require strong memory alignment.

api-approved area-System.Memory

Most helpful comment

Video

This API and scenarios make sense but we shouldn't use Struct in the name. It seems to make more sense to align this with Unsafe.AsRef(), thus:

static class MemoryMarshal
{
    public static ref readonly T AsRef<T>(ReadOnlySpan<byte> span) where T : struct;
    public static ref T AsRef(Span<byte> span) where T : struct;
}

All 11 comments

Related proposal for other direction dotnet/runtime#24656

dotnet/corefx#30614 has multiple examples of how these methods can be used in real-world code.

A bit like Marshal.PtrToStructure<T> Method (IntPtr) but generally safer, including a >= sizeof(T) check; and ref returning rather than copying?

Right.

Could this use the unmanaged constraint instead of the struct constraint? GC references wouldn't be a good thing with this API.

The implementation will enforce no-GC references at runtime just like MemoryMarshal.Cast and other similar APIs. unmanaged constrain is enforcing more than no-GC references. It would make this API less useful and inconsistent with the rest of the MemoryMarshal and Span methods.

Video

This API and scenarios make sense but we shouldn't use Struct in the name. It seems to make more sense to align this with Unsafe.AsRef(), thus:

static class MemoryMarshal
{
    public static ref readonly T AsRef<T>(ReadOnlySpan<byte> span) where T : struct;
    public static ref T AsRef(Span<byte> span) where T : struct;
}

@terrajobst where T : unmanaged ?

@jkotas apparently I fail at reading today, thx

Is it possible to use AsRef in .NET Standard 2.1? I was only able to use it targeting netcoreapp3.0

@virzak best to ask this in the dotnet/standard repo

Was this page helpful?
0 / 5 - 0 ratings

Related issues

bencz picture bencz  路  3Comments

aggieben picture aggieben  路  3Comments

Timovzl picture Timovzl  路  3Comments

noahfalk picture noahfalk  路  3Comments

btecu picture btecu  路  3Comments