mirror of
https://github.com/Ryujinx/Ryujinx.git
synced 2025-04-27 05:50:50 -07:00
115 lines
4.5 KiB
C#
115 lines
4.5 KiB
C#
using System;
|
|
using System.Buffers;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace Ryujinx.Common.Memory
|
|
{
|
|
/// <summary>
|
|
/// A stack-only type that rents a buffer of a specified length from <seealso cref="ArrayPool{T}.Shared"/>.
|
|
/// It does not implement <see cref="IDisposable"/> 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.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of item to store.</typeparam>
|
|
public readonly ref struct SpanOwner<T>
|
|
{
|
|
private readonly int _length;
|
|
private readonly T[] _array;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="SpanOwner{T}"/> struct with the specified parameters.
|
|
/// </summary>
|
|
/// <param name="length">The length of the new memory buffer to use</param>
|
|
private SpanOwner(int length)
|
|
{
|
|
_length = length;
|
|
_array = ArrayPool<T>.Shared.Rent(length);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets an empty <see cref="SpanOwner{T}"/> instance.
|
|
/// </summary>
|
|
public static SpanOwner<T> Empty
|
|
{
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
get => new(0);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new <see cref="SpanOwner{T}"/> instance with the specified length.
|
|
/// </summary>
|
|
/// <param name="length">The length of the new memory buffer to use</param>
|
|
/// <returns>A <see cref="SpanOwner{T}"/> instance of the requested length</returns>
|
|
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="length"/> is not valid</exception>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static SpanOwner<T> Rent(int length) => new(length);
|
|
|
|
/// <summary>
|
|
/// Creates a new <see cref="SpanOwner{T}"/> instance with the length and the content cleared.
|
|
/// </summary>
|
|
/// <param name="length">The length of the new memory buffer to use</param>
|
|
/// <returns>A <see cref="SpanOwner{T}"/> instance of the requested length and the content cleared</returns>
|
|
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="length"/> is not valid</exception>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static SpanOwner<T> RentCleared(int length)
|
|
{
|
|
SpanOwner<T> result = new(length);
|
|
|
|
result._array.AsSpan(0, length).Clear();
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new <see cref="SpanOwner{T}"/> instance with the content copied from the specified buffer.
|
|
/// </summary>
|
|
/// <param name="buffer">The buffer to copy</param>
|
|
/// <returns>A <see cref="SpanOwner{T}"/> instance with the same length and content as <paramref name="buffer"/></returns>
|
|
public static SpanOwner<T> RentCopy(ReadOnlySpan<T> buffer)
|
|
{
|
|
SpanOwner<T> result = new(buffer.Length);
|
|
|
|
buffer.CopyTo(result._array);
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the number of items in the current instance
|
|
/// </summary>
|
|
public int Length
|
|
{
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
get => _length;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a <see cref="Span{T}"/> wrapping the memory belonging to the current instance.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Uses a trick made possible by the .NET 6+ runtime array layout.
|
|
/// </remarks>
|
|
public Span<T> Span
|
|
{
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
get
|
|
{
|
|
ref T firstElementRef = ref MemoryMarshal.GetArrayDataReference(_array);
|
|
|
|
return MemoryMarshal.CreateSpan(ref firstElementRef, _length);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Implements the duck-typed <see cref="IDisposable.Dispose"/> method.
|
|
/// </summary>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void Dispose()
|
|
{
|
|
ArrayPool<T>.Shared.Return(_array, RuntimeHelpers.IsReferenceOrContainsReferences<T>());
|
|
}
|
|
}
|
|
}
|