using System;
using System.Runtime.CompilerServices;
using System.Threading;
/*https://github.com/dotnet/aspnetcore/blob/main/src/ObjectPool*/
namespace MemoryPools
{
///
/// Default implementation of .
///
/// The type to pool objects for.
/// This implementation keeps a cache of retained objects. This means that if objects are returned when the pool has already reached "maximumRetained" objects they will be available to be Garbage Collected.
public class DefaultObjectPool : ObjectPool where T : class
{
private protected readonly ObjectWrapper[] _items;
private protected readonly IPooledObjectPolicy _policy;
private protected readonly bool _isDefaultPolicy;
private protected T _firstItem;
// This class was introduced in 2.1 to avoid the interface call where possible
private protected readonly PooledObjectPolicy _fastPolicy;
///
/// Creates an instance of .
///
/// The pooling policy to use.
public DefaultObjectPool(IPooledObjectPolicy policy)
: this(policy, Environment.ProcessorCount * 2)
{
}
///
/// Creates an instance of .
///
/// The pooling policy to use.
/// The maximum number of objects to retain in the pool.
public DefaultObjectPool(IPooledObjectPolicy policy, int maximumRetained)
{
_policy = policy ?? throw new ArgumentNullException(nameof(policy));
_fastPolicy = (policy as PooledObjectPolicy)!;
_isDefaultPolicy = IsDefaultPolicy();
// -1 due to _firstItem
_items = new ObjectWrapper[maximumRetained - 1];
bool IsDefaultPolicy()
{
var type = policy.GetType();
return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(DefaultPooledObjectPolicy<>);
}
}
///
public override T Get()
{
var item = _firstItem;
if (item == null || Interlocked.CompareExchange(ref _firstItem!, null, item) != item)
{
var items = _items;
for (var i = 0; i < items.Length; i++)
{
item = items[i].Element;
if (item != null && Interlocked.CompareExchange(ref items[i].Element!, null, item) == item)
{
return item;
}
}
item = Create();
}
return item;
}
// Non-inline to improve its code quality as uncommon path
[MethodImpl(MethodImplOptions.NoInlining)]
private T Create() => _fastPolicy?.Create() ?? _policy.Create();
///
public override void Return(T obj)
{
if (_isDefaultPolicy || (_fastPolicy?.Return(obj) ?? _policy.Return(obj)))
{
if (_firstItem != null || Interlocked.CompareExchange(ref _firstItem, obj, null) != null!)
{
var items = _items;
for (var i = 0; i < items.Length && Interlocked.CompareExchange(ref items[i].Element, obj, null) != null!; ++i)
{
}
}
}
}
private protected struct ObjectWrapper
{
public T Element;
}
}
}