using System.Buffers; using System.Collections.Generic; using System.Runtime.CompilerServices; namespace System.Runtime.InteropServices; public static class MemoryMarshal { public static bool TryGetArray(ReadOnlyMemory memory, out ArraySegment segment) { int start; int length; object objectStartLength = memory.GetObjectStartLength(out start, out length); if (start < 0) { if (((MemoryManager)objectStartLength).TryGetArray(out var segment2)) { segment = new ArraySegment(segment2.Array, segment2.Offset + (start & 0x7FFFFFFF), length); return true; } } else if (objectStartLength is T[] array) { segment = new ArraySegment(array, start, length & 0x7FFFFFFF); return true; } if ((length & 0x7FFFFFFF) == 0) { segment = new ArraySegment(System.SpanHelpers.PerTypeValues.EmptyArray); return true; } segment = default(ArraySegment); return false; } public static bool TryGetMemoryManager(ReadOnlyMemory memory, out TManager manager) where TManager : MemoryManager { int start; int length; TManager val = (manager = memory.GetObjectStartLength(out start, out length) as TManager); return manager != null; } public static bool TryGetMemoryManager(ReadOnlyMemory memory, out TManager manager, out int start, out int length) where TManager : MemoryManager { TManager val = (manager = memory.GetObjectStartLength(out start, out length) as TManager); start &= int.MaxValue; if (manager == null) { start = 0; length = 0; return false; } return true; } public static IEnumerable ToEnumerable(ReadOnlyMemory memory) { for (int i = 0; i < memory.Length; i++) { yield return memory.Span[i]; } } public static bool TryGetString(ReadOnlyMemory memory, out string text, out int start, out int length) { if (memory.GetObjectStartLength(out var start2, out var length2) is string text2) { text = text2; start = start2; length = length2; return true; } text = null; start = 0; length = 0; return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T Read(ReadOnlySpan source) where T : struct { if (System.SpanHelpers.IsReferenceOrContainsReferences()) { System.ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T)); } if (Unsafe.SizeOf() > source.Length) { System.ThrowHelper.ThrowArgumentOutOfRangeException(System.ExceptionArgument.length); } return Unsafe.ReadUnaligned(in GetReference(source)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryRead(ReadOnlySpan source, out T value) where T : struct { if (System.SpanHelpers.IsReferenceOrContainsReferences()) { System.ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T)); } if (Unsafe.SizeOf() > (uint)source.Length) { value = default(T); return false; } value = Unsafe.ReadUnaligned(in GetReference(source)); return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Write(Span destination, ref T value) where T : struct { if (System.SpanHelpers.IsReferenceOrContainsReferences()) { System.ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T)); } if ((uint)Unsafe.SizeOf() > (uint)destination.Length) { System.ThrowHelper.ThrowArgumentOutOfRangeException(System.ExceptionArgument.length); } Unsafe.WriteUnaligned(ref GetReference(destination), value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryWrite(Span destination, ref T value) where T : struct { if (System.SpanHelpers.IsReferenceOrContainsReferences()) { System.ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T)); } if (Unsafe.SizeOf() > (uint)destination.Length) { return false; } Unsafe.WriteUnaligned(ref GetReference(destination), value); return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Memory CreateFromPinnedArray(T[] array, int start, int length) { if (array == null) { if (start != 0 || length != 0) { System.ThrowHelper.ThrowArgumentOutOfRangeException(); } return default(Memory); } if (default(T) == null && array.GetType() != typeof(T[])) { System.ThrowHelper.ThrowArrayTypeMismatchException(); } if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start)) { System.ThrowHelper.ThrowArgumentOutOfRangeException(); } return new Memory((object)array, start, length | int.MinValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Span AsBytes(Span span) where T : struct { if (System.SpanHelpers.IsReferenceOrContainsReferences()) { System.ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T)); } int length = checked(span.Length * Unsafe.SizeOf()); return new Span(Unsafe.As>(span.Pinnable), span.ByteOffset, length); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ReadOnlySpan AsBytes(ReadOnlySpan span) where T : struct { if (System.SpanHelpers.IsReferenceOrContainsReferences()) { System.ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T)); } int length = checked(span.Length * Unsafe.SizeOf()); return new ReadOnlySpan(Unsafe.As>(span.Pinnable), span.ByteOffset, length); } public static Memory AsMemory(ReadOnlyMemory memory) { return Unsafe.As, Memory>(ref memory); } public unsafe static ref T GetReference(Span span) { if (span.Pinnable == null) { return ref Unsafe.AsRef(span.ByteOffset.ToPointer()); } return ref Unsafe.AddByteOffset(ref span.Pinnable.Data, span.ByteOffset); } public unsafe static ref T GetReference(ReadOnlySpan span) { if (span.Pinnable == null) { return ref Unsafe.AsRef(span.ByteOffset.ToPointer()); } return ref Unsafe.AddByteOffset(ref span.Pinnable.Data, span.ByteOffset); } public static Span Cast(Span span) where TFrom : struct where TTo : struct { if (System.SpanHelpers.IsReferenceOrContainsReferences()) { System.ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(TFrom)); } if (System.SpanHelpers.IsReferenceOrContainsReferences()) { System.ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(TTo)); } checked { int length = (int)unchecked(checked(unchecked((long)span.Length) * unchecked((long)Unsafe.SizeOf())) / Unsafe.SizeOf()); return new Span(Unsafe.As>(span.Pinnable), span.ByteOffset, length); } } public static ReadOnlySpan Cast(ReadOnlySpan span) where TFrom : struct where TTo : struct { if (System.SpanHelpers.IsReferenceOrContainsReferences()) { System.ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(TFrom)); } if (System.SpanHelpers.IsReferenceOrContainsReferences()) { System.ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(TTo)); } checked { int length = (int)unchecked(checked(unchecked((long)span.Length) * unchecked((long)Unsafe.SizeOf())) / Unsafe.SizeOf()); return new ReadOnlySpan(Unsafe.As>(span.Pinnable), span.ByteOffset, length); } } }