-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
Move Span.NonPortableCast to MemoryMarshal and rename to Cast #24689
Comments
The API on MemoryMarshal should not be an extension method. |
@jkotas, what's the code we recommend people write when they want to use this API in a reusable library? i.e. How should they check if the cast is safe or not? If it turns out it's not, what should the fallback code do? |
Options:
Options:
|
A couple more questions:
|
For .NET Core today - yes. For Mono - the matrix is much larger.
Are you sure that they are not produced? I think ARM stopped iterating on the base line designs sometime around 2006, but I believe these older ARM version are still produced in huge quantities, e.g. RPi0, Lego Mindstorm, ... .
Unless you pass the unaligned memory to the OS, read floating point values from it, or perform interlocked operations on it - I believe all these fault even on latest ARM. (The list may be incomplete.)
It is case-by-case. Many places read one byte a time today and they work just fine. The reading one byte at a time is far from being a performance bottleneck in many cases. |
For example, we have switched System.Reflection.Metadata to read one byte a time in most places to make it portable and uses special paths in a few bulkier places : dotnet/corefx#16583 . The performance impact of this change was non-measurable. |
From what I read, ARM7 can in general read unaligned, but some read instructions cannot. ARM9+ all instructions support unaligned reads, but the feature can be turned on/off (at processor level) and so software cannot assume any given settings. Supposedly most OSes have the setting on, but some don't. |
I kind of wish we made it possible to write Span<byte> bytes = ...
if(!bytes.CanCast<int>()){
bytes = bytes.ToArray();
}
Span<int> ints = bytes.Cast<int>(); // fails is misaligned on all processors |
Why not |
I do not think it is the case. My copy of the ARM manual has a big table in chapter |
How would we discern when to return false (i.e. whether the platform supports misaligned memory access) without significant perf regression? |
For slow span, it would be slow like everything else. For fast span, it would need to be special crafted in the runtime per platform to be fast. |
Just noticed a problem with this:
To be portable, you would rather want allocate array of the destination type and then copy the bytes to it. The array of bytes may not have sufficient alignment for the destination type. |
I like the idea of TryCast. |
I like TryCast too. Updated the proposal. |
so, the idiomatic code would be: Span<int> ints;
if(!bytes.TryCast(out ints)){
ints = new int[bytes.Length/sizeof(int)];
bytes.Slice(0, ints.Length * sizeof(int)).CopyTo(ints.AsBytes());
} As a side note, I again wish out Copyto copied as much as it could and returned the number of items copied as opposed to demanding the right fit, i.e. Span<int> ints;
if(!bytes.TryCast(out ints)){
ints = new int[bytes.Length/sizeof(int)];
bytes.CopyTo(ints.AsBytes);
} |
It wouldn't be an extension method if its in MemoryMarshal though, so an example would be more like: Span<int> ints;
if(!MemoryMarshal.TryCast<byte, int>(bytes, out ints)){
ints = new int[bytes.Length/sizeof(int)];
bytes.Slice(0, ints.Length * sizeof(int)).CopyTo(ints.AsBytes());
} |
Edit: removed. |
Looks good as proposed. We can add a more specialized API that handles the namespace System
{
public static partial class MemoryExtensions
{
public static bool TryCast<TFrom, TTo>(this ReadOnlySpan<TFrom> source, out ReadOnlySpan<TTo> output) where TFrom : struct where TTo : struct;
public static bool TryCast<TFrom, TTo>(this Span<TFrom> source, out Span<TTo> output) where TFrom : struct where TTo : struct;
}
} We'll also leave the |
I split the TryCast addition to https://github.com/dotnet/corefx/issues/26465 to make tracking easier. This issue will track just the move and rename of |
Consume Span moves - [Move Span.DangerousCreate to MemoryMarshal.CreateSpan](#26139) - [Move ReadOnlySpan.DangerousCreate to MemoryMarshal.CreateReadOnlySpan](#26139) - [Move Span.NonPortableCast to MemoryMarshal.Cast](#26368) - [Move ReadOnlySpan.NonPortableCast to MemoryMarshal.Cast](#26368) - [Add ToString override to Span and ReadOnlySpan](#26295) - [Add ToEnumerable function to MemoryMarshal that takes a Memory](#24854)
From https://github.com/dotnet/corefx/issues/26139#issuecomment-358090527:
Move and rename NonPortableCast to MemoryMarshal.Cast
Current API:
Proposed API:
Edit: Removed
this
Edit by @ianhays: Changed
Cast
toTryCast
per discussioncc @jkotas, @KrzysztofCwalina
The text was updated successfully, but these errors were encountered: