using System; using System.Runtime.CompilerServices; using System.Threading; /*https://github.com/dotnet/aspnetcore/blob/main/src/ObjectPool*/ namespace MemoryPools { /// <summary> /// Default implementation of <see cref="ObjectPool{T}"/>. /// </summary> /// <typeparam name="T">The type to pool objects for.</typeparam> /// <remarks>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.</remarks> public class DefaultObjectPool<T> : ObjectPool<T> where T : class { private protected readonly ObjectWrapper[] _items; private protected readonly IPooledObjectPolicy<T> _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<T> _fastPolicy; /// <summary> /// Creates an instance of <see cref="DefaultObjectPool{T}"/>. /// </summary> /// <param name="policy">The pooling policy to use.</param> public DefaultObjectPool(IPooledObjectPolicy<T> policy) : this(policy, Environment.ProcessorCount * 2) { } /// <summary> /// Creates an instance of <see cref="DefaultObjectPool{T}"/>. /// </summary> /// <param name="policy">The pooling policy to use.</param> /// <param name="maximumRetained">The maximum number of objects to retain in the pool.</param> public DefaultObjectPool(IPooledObjectPolicy<T> policy, int maximumRetained) { _policy = policy ?? throw new ArgumentNullException(nameof(policy)); _fastPolicy = (policy as PooledObjectPolicy<T>)!; _isDefaultPolicy = IsDefaultPolicy(); // -1 due to _firstItem _items = new ObjectWrapper[maximumRetained - 1]; bool IsDefaultPolicy() { var type = policy.GetType(); return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(DefaultPooledObjectPolicy<>); } } /// <inheritdoc /> 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(); /// <inheritdoc /> 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; } } }