using System; using System.Threading; /*https://github.com/dotnet/aspnetcore/blob/main/src/ObjectPool*/ namespace MemoryPools { internal sealed class DisposableObjectPool : DefaultObjectPool, IDisposable where T : class { private volatile bool _isDisposed; public DisposableObjectPool(IPooledObjectPolicy policy) : base(policy) { } public DisposableObjectPool(IPooledObjectPolicy policy, int maximumRetained) : base(policy, maximumRetained) { } public override T Get() { if (_isDisposed) { ThrowObjectDisposedException(); } return base.Get(); void ThrowObjectDisposedException() { throw new ObjectDisposedException(GetType().Name); } } public override void Return(T obj) { // When the pool is disposed or the obj is not returned to the pool, dispose it if (_isDisposed || !ReturnCore(obj)) { DisposeItem(obj); } } private bool ReturnCore(T obj) { bool returnedTooPool = false; if (_isDefaultPolicy || (_fastPolicy?.Return(obj) ?? _policy.Return(obj))) { if (_firstItem == null && Interlocked.CompareExchange(ref _firstItem, obj, null) == null!) { returnedTooPool = true; } else { var items = _items; for (var i = 0; i < items.Length && !(returnedTooPool = Interlocked.CompareExchange(ref items[i].Element, obj, null) == null!); i++) { } } } return returnedTooPool; } public void Dispose() { _isDisposed = true; DisposeItem(_firstItem); _firstItem = null!; ObjectWrapper[] items = _items; for (var i = 0; i < items.Length; i++) { DisposeItem(items[i].Element); items[i].Element = null!; } } private static void DisposeItem(T item) { if (item != null && item is IDisposable disposable) { disposable.Dispose(); } } } }