2021-11-28 17:41:57 +00:00
using System ;
using System.Buffers ;
namespace Ryujinx.Common.Pools
{
/// <summary>
/// A centralized, static pool for getting multipurpose buffers of any type.
/// "But why does this exist when you have <see cref="ArrayPool{T}"/>?" This actually just wraps around
2021-12-01 01:27:41 +00:00
/// ArrayPool. The difference is that the rented array is hidden inside of a <see cref="PooledBuffer{T}"/>
/// handle and is only exposed as a <see cref="Span{T}"/>. This makes it harder to leak references to the
/// pooled array, which makes it a bit easier to track ownership. The PooledBuffer handle is <see cref="IDisposable"/>
/// so code analysis can enforce better practice as well. In addition, it also tracks the initial requested
/// size of the allocated buffer, so you can pass it around and users of it know how much of the data
/// is actually valid, compared to ArrayPool which just gives you an arbitrary sized array.
2021-11-28 17:41:57 +00:00
/// </summary>
public static class BufferPool < T >
{
public const int DEFAULT_BUFFER_SIZE = 65536 ;
private static readonly PooledBuffer < T > EMPTY_POOLED_BUFFER = new PooledBuffer < T > ( Array . Empty < T > ( ) , - 1 ) ;
/// <summary>
2021-11-30 21:53:49 +00:00
/// Returns a disposable <see cref="PooledBuffer{T}" /> instance backed by a contiguous array of at least the requested number of elements.
/// The internal array is only exposed as a <see cref="Span{T}"/> to prevent user code from storing references to it outside
/// of the potential lifetime of the pooled handle.
2021-11-28 17:41:57 +00:00
/// </summary>
/// <param name="minimumRequestedSize">The minimum number of elements that you require</param>
2021-11-30 21:53:49 +00:00
/// <param name="clearArray">Whether to clear the contents of the buffer before returning. If false (by default), the buffer may initially contain garbage.</param>
/// <returns>A pooled buffer of exactly the requested size.</returns>
public static PooledBuffer < T > Rent ( int minimumRequestedSize = DEFAULT_BUFFER_SIZE , bool clearArray = false )
2021-11-28 17:41:57 +00:00
{
if ( minimumRequestedSize < 0 )
{
throw new ArgumentOutOfRangeException ( "Requested buffer size must be a positive number" ) ;
}
if ( minimumRequestedSize = = 0 )
{
return EMPTY_POOLED_BUFFER ;
}
2021-11-30 21:53:49 +00:00
T [ ] array = ArrayPool < T > . Shared . Rent ( minimumRequestedSize ) ;
if ( clearArray )
{
Array . Clear ( array , 0 , minimumRequestedSize ) ;
}
PooledBuffer < T > returnVal = new PooledBuffer < T > ( array , minimumRequestedSize ) ;
2021-12-01 00:58:31 +00:00
#if TRACK_BUFFERPOOL_LEAKS
2021-11-28 17:41:57 +00:00
returnVal . MarkRented ( ) ;
#endif
return returnVal ;
}
}
}