< Summary

Information
Class: SwiftCollections.Pool.SwiftObjectPool<T>
Assembly: SwiftCollections
File(s): /home/runner/work/SwiftCollections/SwiftCollections/src/SwiftCollections/Pool/SwiftObjectPool.cs
Line coverage
100%
Covered lines: 62
Uncovered lines: 0
Coverable lines: 62
Total lines: 187
Line coverage: 100%
Branch coverage
87%
Covered branches: 21
Total branches: 24
Branch coverage: 87.5%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
get_CountAll()100%11100%
get_CountActive()100%11100%
get_CountInactive()100%11100%
Rent()75%88100%
Rent(...)100%11100%
Release(...)83.33%66100%
Release(...)100%22100%
Clear()100%66100%
Dispose()100%22100%
Finalize()100%11100%

File(s)

/home/runner/work/SwiftCollections/SwiftCollections/src/SwiftCollections/Pool/SwiftObjectPool.cs

#LineLine coverage
 1using System;
 2using System.Collections.Concurrent;
 3using System.Collections.Generic;
 4using System.Runtime.CompilerServices;
 5
 6namespace SwiftCollections.Pool;
 7
 8/// <summary>
 9/// A generic object pooling class designed to efficiently reuse objects, reducing memory allocation overhead
 10/// and improving performance. Provides thread-safe operations for creating, renting, and releasing objects.
 11/// </summary>
 12/// <typeparam name="T">The type of object to pool. Must be a reference type.</typeparam>
 13public sealed class SwiftObjectPool<T> : IDisposable, ISwiftObjectPool<T> where T : class
 14{
 15    #region Fields
 16
 17    private readonly ConcurrentStack<T> _pool;
 18    private readonly Func<T> _createFunc;
 19    private readonly Action<T> _actionOnGet;
 20    private readonly Action<T> _actionOnRelease;
 21    private readonly Action<T> _actionOnDestroy;
 22    private readonly int _maxSize;
 23
 24    private volatile bool _disposed;
 25
 26    #endregion
 27
 28    #region Constructor
 29
 30    /// <summary>
 31    /// Initializes a new instance of the <see cref="SwiftObjectPool{T}"/> class.
 32    /// </summary>
 33    /// <param name="createFunc">A function used to create new instances of the object type.</param>
 34    /// <param name="actionOnGet">An optional action to perform when an object is rented from the pool.</param>
 35    /// <param name="actionOnRelease">An optional action to perform when an object is returned to the pool.</param>
 36    /// <param name="actionOnDestroy">An optional action to perform when an object is destroyed due to pool size constra
 37    /// <param name="maxSize">The maximum number of objects the pool can hold.</param>
 38    /// <exception cref="ArgumentNullException">Thrown if <paramref name="createFunc"/> is null.</exception>
 39    /// <exception cref="ArgumentException">Thrown if <paramref name="maxSize"/> is less than or equal to 0.</exception>
 4640    public SwiftObjectPool(
 4641        Func<T> createFunc,
 4642        Action<T> actionOnGet = null,
 4643        Action<T> actionOnRelease = null,
 4644        Action<T> actionOnDestroy = null,
 4645        int maxSize = 100)
 4646    {
 4647        SwiftThrowHelper.ThrowIfNull(createFunc, nameof(createFunc));
 4648        SwiftThrowHelper.ThrowIfNegativeOrZero(maxSize, nameof(maxSize));
 49
 4650        _pool = new ConcurrentStack<T>();
 4651        _createFunc = createFunc;
 4652        _actionOnGet = actionOnGet;
 4653        _actionOnRelease = actionOnRelease;
 4654        _actionOnDestroy = actionOnDestroy;
 4655        _maxSize = maxSize;
 4656    }
 57
 58    #endregion
 59
 60    #region Properties
 61
 62    /// <summary>
 63    /// Gets the total number of objects created by the pool, including both active and inactive objects.
 64    /// </summary>
 13965    public int CountAll { get; private set; }
 66
 67    /// <summary>
 68    /// Gets the number of objects currently in use (rented from the pool).
 69    /// </summary>
 470    public int CountActive => CountAll - CountInactive;
 71
 72    /// <summary>
 73    /// Gets the number of objects currently available in the pool for rent.
 74    /// </summary>
 775    public int CountInactive => _pool.Count;
 76
 77    #endregion
 78
 79    #region Collection Manipulation
 80
 81    /// <summary>
 82    /// Rents an object from the pool. If the pool is empty, a new object is created using the factory function.
 83    /// </summary>
 84    /// <returns>An instance of <typeparamref name="T"/>.</returns>
 85    /// <exception cref="InvalidOperationException">Thrown if object creation fails.</exception>
 86    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 87    public T Rent()
 6688    {
 6689        SwiftThrowHelper.ThrowIfDisposed(_disposed, nameof(SwiftObjectPool<T>));
 90
 6591        if (_pool.TryPop(out var obj))
 1292        {
 1293            _actionOnGet?.Invoke(obj);
 1294            return obj;
 95        }
 96
 5397        var newObj = _createFunc();
 5498        if (newObj == null) throw new InvalidOperationException("Failed to create a new object.");
 5299        CountAll++;
 52100        _actionOnGet?.Invoke(newObj);
 52101        return newObj;
 64102    }
 103
 104    /// <summary>
 105    /// Rents an object from the pool and wraps it in a <see cref="SwiftPooledObject{T}"/> for automatic release.
 106    /// </summary>
 107    /// <param name="value">The rented object.</param>
 108    /// <returns>A <see cref="SwiftPooledObject{T}"/> instance wrapping the rented object.</returns>
 109    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 3110    public SwiftPooledObject<T> Rent(out T value) => new SwiftPooledObject<T>(value = Rent(), this);
 111
 112    /// <summary>
 113    /// Releases an object back to the pool for reuse. If the pool has reached its maximum size, the object
 114    /// is destroyed using the configured destroy action.
 115    /// </summary>
 116    /// <param name="element">The object to release.</param>
 117    /// <exception cref="ArgumentNullException">Thrown if <paramref name="element"/> is null.</exception>
 118    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 119    public void Release(T element)
 37120    {
 37121        SwiftThrowHelper.ThrowIfDisposed(_disposed, nameof(SwiftObjectPool<T>));
 37122        SwiftThrowHelper.ThrowIfNull(element, nameof(element));
 123
 36124        _actionOnRelease?.Invoke(element);
 125
 36126        if (_pool.Count < _maxSize)
 35127            _pool.Push(element);
 128        else
 1129        {
 1130            _actionOnDestroy?.Invoke(element);
 1131            CountAll--;
 1132        }
 36133    }
 134
 135    /// <summary>
 136    /// Releases all objects back to the pool for reuse.  If the pool has reached its maximum size, objects
 137    /// are destroyed using the configured destroy action.
 138    /// </summary>
 139    /// <param name="elements"></param>
 140    /// <exception cref="ArgumentNullException">Thrown if any object in <paramref name="elements"/> is null.</exception>
 141    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 142    public void Release(IEnumerable<T> elements)
 1143    {
 1144        SwiftThrowHelper.ThrowIfDisposed(_disposed, nameof(SwiftObjectPool<T>));
 145
 7146        foreach (T item in elements)
 2147            Release(item);
 1148    }
 149
 150    /// <summary>
 151    /// Clears all objects from the pool, destroying any active objects if a destroy action is configured.
 152    /// </summary>
 153    public void Clear()
 36154    {
 47155        if (_disposed) return;
 156
 42157        while (_pool.TryPop(out var obj))
 17158            _actionOnDestroy?.Invoke(obj);
 159
 25160        CountAll = 0;
 36161    }
 162
 163    #endregion
 164
 165    #region IDisposable Implementation
 166
 167    /// <summary>
 168    /// Releases all resources used by the SwiftObjectPool.
 169    /// It is important to call Dispose() to release pooled arrays, preventing potential memory leaks.
 170    /// </summary>
 171    public void Dispose()
 91172    {
 91173        if (_disposed)
 45174            return;
 175
 46176        _pool.Clear();
 177
 46178        _disposed = true;
 179
 180        // Suppress finalization to prevent unnecessary GC overhead
 46181        GC.SuppressFinalize(this);
 91182    }
 183
 26184    ~SwiftObjectPool() => Dispose();
 185
 186    #endregion
 187}