using System; using System.Buffers; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace Ryujinx.Common.Memory { /// /// A stack-only type that rents a buffer of a specified length from . /// It does not implement to avoid being boxed, but should still be disposed. This /// is easy since C# 8, which allows use of C# `using` constructs on any type that has a public Dispose() method. /// To keep this type simple, fast, and read-only, it does not check or guard against multiple disposals. /// For all these reasons, all usage should be with a `using` block or statement. /// /// The type of item to store. public readonly ref struct SpanOwner { private readonly int _length; private readonly T[] _array; /// /// Initializes a new instance of the struct with the specified parameters. /// /// The length of the new memory buffer to use private SpanOwner(int length) { _length = length; _array = ArrayPool.Shared.Rent(length); } /// /// Gets an empty instance. /// public static SpanOwner Empty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(0); } /// /// Creates a new instance with the specified length. /// /// The length of the new memory buffer to use /// A instance of the requested length /// Thrown when is not valid [MethodImpl(MethodImplOptions.AggressiveInlining)] public static SpanOwner Rent(int length) => new(length); /// /// Creates a new instance with the length and the content cleared. /// /// The length of the new memory buffer to use /// A instance of the requested length and the content cleared /// Thrown when is not valid [MethodImpl(MethodImplOptions.AggressiveInlining)] public static SpanOwner RentCleared(int length) { SpanOwner result = new(length); result._array.AsSpan(0, length).Clear(); return result; } /// /// Creates a new instance with the content copied from the specified buffer. /// /// The buffer to copy /// A instance with the same length and content as public static SpanOwner RentCopy(ReadOnlySpan buffer) { SpanOwner result = new(buffer.Length); buffer.CopyTo(result._array); return result; } /// /// Gets the number of items in the current instance /// public int Length { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _length; } /// /// Gets a wrapping the memory belonging to the current instance. /// /// /// Uses a trick made possible by the .NET 6+ runtime array layout. /// public Span Span { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { ref T firstElementRef = ref MemoryMarshal.GetArrayDataReference(_array); return MemoryMarshal.CreateSpan(ref firstElementRef, _length); } } /// /// Implements the duck-typed method. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Dispose() { ArrayPool.Shared.Return(_array, RuntimeHelpers.IsReferenceOrContainsReferences()); } } }