// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System.Runtime.CompilerServices; using Internal.Runtime.CompilerServices; namespace System.Runtime.InteropServices { /// /// Provides a collection of methods for interoperating with , , /// , and . /// public static partial class MemoryMarshal { /// /// Casts a Span of one primitive type to Span of bytes. /// That type may not contain pointers or references. This is checked at runtime in order to preserve type safety. /// /// The source slice, of type . /// /// Thrown when contains pointers. /// /// /// Thrown if the Length property of the new Span would exceed int.MaxValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Span AsBytes(Span span) where T : struct { if (RuntimeHelpers.IsReferenceOrContainsReferences()) ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T)); return new Span( ref Unsafe.As(ref GetReference(span)), checked(span.Length * Unsafe.SizeOf())); } /// /// Casts a ReadOnlySpan of one primitive type to ReadOnlySpan of bytes. /// That type may not contain pointers or references. This is checked at runtime in order to preserve type safety. /// /// The source slice, of type . /// /// Thrown when contains pointers. /// /// /// Thrown if the Length property of the new Span would exceed int.MaxValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ReadOnlySpan AsBytes(ReadOnlySpan span) where T : struct { if (RuntimeHelpers.IsReferenceOrContainsReferences()) ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T)); return new ReadOnlySpan( ref Unsafe.As(ref GetReference(span)), checked(span.Length * Unsafe.SizeOf())); } /// Creates a from a . /// The . /// A representing the same memory as the , but writable. /// /// must be used with extreme caution. is used /// to represent immutable data and other memory that is not meant to be written to; instances created /// by should not be written to. The method exists to enable variables typed /// as but only used for reading to store a . /// public static Memory AsMemory(ReadOnlyMemory memory) => Unsafe.As, Memory>(ref memory); /// /// 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 /// would have been stored. Such a reference may or may not be null. It can be used for pinning but must never be dereferenced. /// public static ref T GetReference(Span span) => ref span._pointer.Value; /// /// Returns a reference to the 0th element of the ReadOnlySpan. If the ReadOnlySpan is empty, returns a reference to the location where the 0th element /// would have been stored. Such a reference may or may not be null. It can be used for pinning but must never be dereferenced. /// public static ref T GetReference(ReadOnlySpan span) => ref span._pointer.Value; /// /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to fake non-null pointer. Such a reference can be used /// for pinning but must never be dereferenced. This is useful for interop with methods that do not accept null pointers for zero-sized buffers. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static unsafe ref T GetNonNullPinnableReference(Span span) => ref (span.Length != 0) ? ref span._pointer.Value : ref Unsafe.AsRef((void*)1); /// /// Returns a reference to the 0th element of the ReadOnlySpan. If the ReadOnlySpan is empty, returns a reference to fake non-null pointer. Such a reference /// can be used for pinning but must never be dereferenced. This is useful for interop with methods that do not accept null pointers for zero-sized buffers. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static unsafe ref T GetNonNullPinnableReference(ReadOnlySpan span) => ref (span.Length != 0) ? ref span._pointer.Value : ref Unsafe.AsRef((void*)1); /// /// Casts a Span of one primitive type to another primitive type . /// These types may not contain pointers or references. This is checked at runtime in order to preserve type safety. /// /// /// Supported only for platforms that support misaligned memory access or when the memory block is aligned by other means. /// /// The source slice, of type . /// /// Thrown when or contains pointers. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Span Cast(Span span) where TFrom : struct where TTo : struct { if (RuntimeHelpers.IsReferenceOrContainsReferences()) ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TFrom)); if (RuntimeHelpers.IsReferenceOrContainsReferences()) ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TTo)); // Use unsigned integers - unsigned division by constant (especially by power of 2) // and checked casts are faster and smaller. uint fromSize = (uint)Unsafe.SizeOf(); uint toSize = (uint)Unsafe.SizeOf(); uint fromLength = (uint)span.Length; int toLength; if (fromSize == toSize) { // Special case for same size types - `(ulong)fromLength * (ulong)fromSize / (ulong)toSize` // should be optimized to just `length` but the JIT doesn't do that today. toLength = (int)fromLength; } else if (fromSize == 1) { // Special case for byte sized TFrom - `(ulong)fromLength * (ulong)fromSize / (ulong)toSize` // becomes `(ulong)fromLength / (ulong)toSize` but the JIT can't narrow it down to `int` // and can't eliminate the checked cast. This also avoids a 32 bit specific issue, // the JIT can't eliminate long multiply by 1. toLength = (int)(fromLength / toSize); } else { // Ensure that casts are done in such a way that the JIT is able to "see" // the uint->ulong casts and the multiply together so that on 32 bit targets // 32x32to64 multiplication is used. ulong toLengthUInt64 = (ulong)fromLength * (ulong)fromSize / (ulong)toSize; toLength = checked((int)toLengthUInt64); } return new Span( ref Unsafe.As(ref span._pointer.Value), toLength); } /// /// Casts a ReadOnlySpan of one primitive type to another primitive type . /// These types may not contain pointers or references. This is checked at runtime in order to preserve type safety. /// /// /// Supported only for platforms that support misaligned memory access or when the memory block is aligned by other means. /// /// The source slice, of type . /// /// Thrown when or contains pointers. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ReadOnlySpan Cast(ReadOnlySpan span) where TFrom : struct where TTo : struct { if (RuntimeHelpers.IsReferenceOrContainsReferences()) ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TFrom)); if (RuntimeHelpers.IsReferenceOrContainsReferences()) ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TTo)); // Use unsigned integers - unsigned division by constant (especially by power of 2) // and checked casts are faster and smaller. uint fromSize = (uint)Unsafe.SizeOf(); uint toSize = (uint)Unsafe.SizeOf(); uint fromLength = (uint)span.Length; int toLength; if (fromSize == toSize) { // Special case for same size types - `(ulong)fromLength * (ulong)fromSize / (ulong)toSize` // should be optimized to just `length` but the JIT doesn't do that today. toLength = (int)fromLength; } else if (fromSize == 1) { // Special case for byte sized TFrom - `(ulong)fromLength * (ulong)fromSize / (ulong)toSize` // becomes `(ulong)fromLength / (ulong)toSize` but the JIT can't narrow it down to `int` // and can't eliminate the checked cast. This also avoids a 32 bit specific issue, // the JIT can't eliminate long multiply by 1. toLength = (int)(fromLength / toSize); } else { // Ensure that casts are done in such a way that the JIT is able to "see" // the uint->ulong casts and the multiply together so that on 32 bit targets // 32x32to64 multiplication is used. ulong toLengthUInt64 = (ulong)fromLength * (ulong)fromSize / (ulong)toSize; toLength = checked((int)toLengthUInt64); } return new ReadOnlySpan( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), toLength); } /// /// Create a new span over a portion of a regular managed object. This can be useful /// if part of a managed object represents a "fixed array." This is dangerous because the /// is not checked. /// /// A reference to data. /// The number of elements the memory contains. /// The lifetime of the returned span will not be validated for safety by span-aware languages. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Span CreateSpan(ref T reference, int length) => new Span(ref reference, length); /// /// Create a new read-only span over a portion of a regular managed object. This can be useful /// if part of a managed object represents a "fixed array." This is dangerous because the /// is not checked. /// /// A reference to data. /// The number of elements the memory contains. /// The lifetime of the returned span will not be validated for safety by span-aware languages. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ReadOnlySpan CreateReadOnlySpan(ref T reference, int length) => new ReadOnlySpan(ref reference, length); } }