Skip to content

Commit

Permalink
Avoid Unsafe.As for Memory<T> and ReadOnlyMemory<T> conversion (#…
Browse files Browse the repository at this point in the history
…111023)

* Use `Unsafe.BitCast`to cast `Memory<T>` and `ReadOnlyMemory<T>`

* remove use of `Unsafe`
  • Loading branch information
xtqqczze authored Jan 29, 2025
1 parent 1b71136 commit be91a36
Show file tree
Hide file tree
Showing 3 changed files with 5 additions and 11 deletions.
5 changes: 1 addition & 4 deletions src/libraries/System.Private.CoreLib/src/System/Memory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@ namespace System
[DebuggerDisplay("{ToString(),raw}")]
public readonly struct Memory<T> : IEquatable<Memory<T>>
{
// NOTE: With the current implementation, Memory<T> and ReadOnlyMemory<T> must have the same layout,
// as code uses Unsafe.As to cast between them.

// The highest order bit of _index is used to discern whether _object is a pre-pinned array.
// (_index < 0) => _object is a pre-pinned array, so Pin() will not allocate a new GCHandle
// (else) => Pin() needs to allocate a new GCHandle to pin the object.
Expand Down Expand Up @@ -187,7 +184,7 @@ internal Memory(object? obj, int start, int length)
/// Defines an implicit conversion of a <see cref="Memory{T}"/> to a <see cref="ReadOnlyMemory{T}"/>
/// </summary>
public static implicit operator ReadOnlyMemory<T>(Memory<T> memory) =>
Unsafe.As<Memory<T>, ReadOnlyMemory<T>>(ref memory);
new ReadOnlyMemory<T>(memory._object, memory._index, memory._length);

/// <summary>
/// Returns an empty <see cref="Memory{T}"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,12 @@ namespace System
[DebuggerDisplay("{ToString(),raw}")]
public readonly struct ReadOnlyMemory<T> : IEquatable<ReadOnlyMemory<T>>
{
// NOTE: With the current implementation, Memory<T> and ReadOnlyMemory<T> must have the same layout,
// as code uses Unsafe.As to cast between them.

// The highest order bit of _index is used to discern whether _object is a pre-pinned array.
// (_index < 0) => _object is a pre-pinned array, so Pin() will not allocate a new GCHandle
// (else) => Pin() needs to allocate a new GCHandle to pin the object.
private readonly object? _object;
private readonly int _index;
private readonly int _length;
internal readonly object? _object;
internal readonly int _index;
internal readonly int _length;

internal const int RemoveFlagsBitMask = 0x7FFFFFFF;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ ref Unsafe.As<T, byte>(ref GetReference(span)),
/// as <see cref="Memory{T}"/> but only used for reading to store a <see cref="ReadOnlyMemory{T}"/>.
/// </remarks>
public static Memory<T> AsMemory<T>(ReadOnlyMemory<T> memory) =>
Unsafe.As<ReadOnlyMemory<T>, Memory<T>>(ref memory);
new Memory<T>(memory._object, memory._index, memory._length);

/// <summary>
/// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to the location where the 0th element
Expand Down

0 comments on commit be91a36

Please sign in to comment.