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());
}
}
}