Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[API Proposal] Allow easier access to binary representation of blittable types #24656

Closed
GrabYourPitchforks opened this issue Jan 13, 2018 · 11 comments

Comments

@GrabYourPitchforks
Copy link
Member

Occasionally advanced developers may have a need to view the binary representation of a blittable value type. For instance, the UTF-8 parsers and formatters have the need to treat a GUID as a sequence of binary data so that it can be efficiently inspected and converted to wire format. This currently involves using pointers and reinterpreting casts, or it involves the use of Unsafe.As<,>, or it involves creating a temporary Span<byte> so that the value can be copied directly into that buffer for future inspection. The framework currently lacks a copyless, type-safe API for performing this operation.

Proposal

Add a new single method to the existing MemoryMarshal class.

public static class MemoryMarshal {
    public static Span<byte> Blit<T>(ref T value) where T : struct;
}

This is very similar to the existing BinaryPrimitives.WriteMachineEndianness<T>(Span<byte> buffer, ref T value) method. The key difference is that the existing WriteMachineEndianness method copies the contents of a blittable struct to an existing Span<byte>, whereas the new method being proposed is a zero-copy API that simply presents a binary data view over an existing blittable struct.

Alternatively, if this method does not belong on the MemoryMarshal class, the BinaryPrimitives class could be a useful home for it.

I do not believe this method belongs on the Unsafe class. Even though the method itself is implemented in terms of unsafe code, it's intended to be presented as a type-safe facade since it fails if the requested type is not blittable. (This method could be used to circumvent visibility, just like other methods on BinaryPrimitives, but it can't be used to stomp on arbitrary object references.)

A sample implementation of this function is provided at the reference below.
https://github.com/GrabYourPitchforks/corefx/blob/e30a8cca02b26b7116fc85f7d4e47bcfab1fe514/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/FormattingHelpers.cs#L32-L55

@jkotas
Copy link
Member

jkotas commented Jan 13, 2018

It is not possible to implement this API with slow Span. This API can only exist with fast Span.

@GrabYourPitchforks
Copy link
Member Author

Ugh, that's unfortunate. :(

@benaadams
Copy link
Member

Would there be value in having it as a platform api? (netcoreapp2.1, net47x, e.g non-netstandard)

@ahsonkhan
Copy link
Member

Regarding the name, how about BitBlit to be more explicit since blitting is a relatively esoteric concept, imo, and the wikipedia page even suggests going to BitBlit:

@tannergooding
Copy link
Member

This specifically calls out "blittable" types, but does it actually refer to "unmanaged" types instead?

@jkotas
Copy link
Member

jkotas commented Jul 23, 2018

The API for Snap<byte>->ref reinterpretation is called AsRef (#30613).

This is API the ref->Snap<byte> reinterpretation (other direction). Would it make sense to call it AsSpan to follow the pattern?

@ektrah
Copy link
Member

ektrah commented Jul 23, 2018

Isn't this equivalent to turning a ref T into a Span<T> followed by Cast<T, byte>? I thought turning a ref T into a Span<T> is not possible, even with fast span.

@jkotas
Copy link
Member

jkotas commented Jul 23, 2018

I thought turning a ref T into a Span is not possible, even with fast span.

It is possible using MemoryMarshal.CreateSpan API. Note that all APIs on MemoryMarshal are unsafe API. You have to be careful to not create a dangling pointer when using this API.

@ektrah
Copy link
Member

ektrah commented Jul 23, 2018

Is AsSpan<T> followed by Cast<T, byte> an option then?

public static Span<T> AsSpan<T>(ref T value) where T : struct;

@ahsonkhan
Copy link
Member

ahsonkhan commented Jul 24, 2018

This is API the ref->Snap<byte> reinterpretation (other direction). Would it make sense to call it AsSpan to follow the pattern?

How about AsBytes, similar to the existing overloads:

public static System.Span<byte> AsBytes<T>(System.Span<T> span) where T : struct { throw null; }
public static System.Span<byte> AsBytes<T>(ref T value) where T : struct { throw null; }

@terrajobst
Copy link
Member

terrajobst commented Jul 24, 2018

Video

Isn't this equivalent to turning a ref T into a Span<T> followed by Cast<T, byte>? I thought turning a ref T into a Span<T> is not possible, even with fast span.

Right. Thus we don't believe we need a dedicated API for this. Yet.

@msftgits msftgits transferred this issue from dotnet/corefx Jan 31, 2020
@msftgits msftgits added this to the 3.0 milestone Jan 31, 2020
@dotnet dotnet locked as resolved and limited conversation to collaborators Dec 18, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

8 participants