< Summary

Information
Class: SwiftCollections.Pool.SwiftArrayPool<T>
Assembly: SwiftCollections
File(s): /home/runner/work/SwiftCollections/SwiftCollections/src/SwiftCollections/Pool/Default/SwiftArrayPool.cs
Line coverage
100%
Covered lines: 44
Uncovered lines: 0
Coverable lines: 44
Total lines: 199
Line coverage: 100%
Branch coverage
100%
Covered branches: 22
Total branches: 22
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
get_Shared()100%11100%
.ctor(...)100%88100%
Rent(...)100%11100%
Release(...)100%66100%
Clear()100%44100%
CreatePoolForSize(...)100%11100%
Dispose()100%44100%
Finalize()100%11100%

File(s)

/home/runner/work/SwiftCollections/SwiftCollections/src/SwiftCollections/Pool/Default/SwiftArrayPool.cs

#LineLine coverage
 1//=======================================================================
 2// SwiftArrayPool.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2024–present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using SwiftCollections.Diagnostics;
 9using SwiftCollections.Lazy;
 10using System;
 11using System.Collections.Concurrent;
 12using System.Runtime.CompilerServices;
 13using System.Threading;
 14
 15namespace SwiftCollections.Pool;
 16
 17/// <summary>
 18/// A thread-safe pool designed to manage arrays of a specific size.
 19/// The pool optimizes memory usage by reusing arrays, reducing allocations and improving performance.
 20/// </summary>
 21/// <typeparam name="T">The type of elements in the arrays being pooled. Must have a parameterless constructor.</typepar
 22public sealed class SwiftArrayPool<T> : IDisposable where T : new()
 23{
 24    #region Singleton Instance
 25
 26    /// <summary>
 27    /// A lazily initialized singleton instance of the array pool.
 28    /// </summary>
 129    private static readonly SwiftLazyDisposable<SwiftArrayPool<T>> _instance =
 130        new(() => new SwiftArrayPool<T>(), LazyThreadSafetyMode.ExecutionAndPublication);
 31
 32    /// <summary>
 33    /// Gets the shared instance of the pool.
 34    /// </summary>
 235    public static SwiftArrayPool<T> Shared => _instance.Value;
 36
 37    #endregion
 38
 39    #region Fields
 40
 41    /// <summary>
 42    /// A collection of object pools, keyed by the size of the arrays they manage.
 43    /// </summary>
 44    private readonly ConcurrentDictionary<int, SwiftObjectPool<T[]>> _sizePools;
 45
 46    /// <summary>
 47    /// Tracks whether the pool has been disposed.
 48    /// </summary>
 49    private volatile bool _disposed;
 50
 51    #endregion
 52
 53    #region Constructor
 54
 55    /// <summary>
 56    /// Initializes a new instance of the <see cref="SwiftArrayPool{T}"/> class with customizable behavior.
 57    /// </summary>
 58    /// <param name="createFunc">A function used to create new arrays (default: creates arrays of the specified size).</
 59    /// <param name="actionOnRelease">An action performed when an array is released back to the pool (default: clears th
 60    /// <param name="actionOnDestroy">An action performed when an array is removed from the pool (default: no action).</
 61    /// <param name="poolMaxCapacity">The maximum number of arrays each pool can hold for a specific size (default: 100)
 1462    public SwiftArrayPool(
 1463        Func<int, T[]>? createFunc = null,
 1464        Action<T[]>? actionOnRelease = null,
 1465        Action<T[]>? actionOnDestroy = null,
 1466        int poolMaxCapacity = 100)
 67    {
 1468        SwiftThrowHelper.ThrowIfNegativeOrZero(poolMaxCapacity, nameof(poolMaxCapacity));
 69
 1470        _sizePools = new ConcurrentDictionary<int, SwiftObjectPool<T[]>>();
 1471        PoolMaxCapacity = poolMaxCapacity;
 72
 1473        CreateFunc = createFunc ?? (size => new T[size]);
 1474        ActionOnRelease = actionOnRelease ?? (array =>
 1475            Array.Clear(array, 0, array.Length));
 1476        ActionOnDestroy = actionOnDestroy;
 1477    }
 78
 79    #endregion
 80
 81    #region Properties
 82
 83    /// <summary>
 84    /// Gets the function used to create new arrays.
 85    /// </summary>
 86    public Func<int, T[]> CreateFunc { get; }
 87
 88    /// <summary>
 89    /// Gets the action performed when an array is released back to the pool.
 90    /// </summary>
 91    public Action<T[]>? ActionOnRelease { get; }
 92
 93    /// <summary>
 94    /// Gets the action performed when an array is removed from the pool.
 95    /// </summary>
 96    public Action<T[]>? ActionOnDestroy { get; }
 97
 98    /// <summary>
 99    /// Gets the maximum number of arrays each pool can hold for a specific size.
 100    /// </summary>
 101    public int PoolMaxCapacity { get; }
 102
 103    #endregion
 104
 105    #region Collection Manipulation
 106
 107    /// <summary>
 108    /// Rents an array of the specified size from the pool. If no pool exists for the size, a new one is created.
 109    /// </summary>
 110    /// <param name="size">The desired size of the array.</param>
 111    /// <returns>An array of the specified size, either newly created or retrieved from the pool.</returns>
 112    /// <exception cref="ArgumentException">Thrown if the specified size is less than or equal to 0.</exception>
 113    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 114    public T[] Rent(int size)
 115    {
 20116        SwiftThrowHelper.ThrowIfDisposed(_disposed, nameof(SwiftArrayPool<T>));
 17117        SwiftThrowHelper.ThrowIfNegativeOrZero(size, nameof(size));
 118
 15119        return _sizePools.GetOrAdd(size, key => CreatePoolForSize(key)).Rent();
 120    }
 121
 122    /// <summary>
 123    /// Releases an array back to the pool for reuse. If no pool exists for the array's size, it is cleared and discarde
 124    /// </summary>
 125    /// <param name="array">The array to release back to the pool.</param>
 126    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 127    public void Release(T[] array)
 128    {
 13129        SwiftThrowHelper.ThrowIfDisposed(_disposed, nameof(SwiftArrayPool<T>));
 130
 13131        if (array == null || array.Length == 0) return;
 132
 9133        if (_sizePools.TryGetValue(array.Length, out var pool))
 8134            pool.Release(array);
 135        else
 1136            Array.Clear(array, 0, array.Length);  // Handle large or unusual sizes by discarding
 1137    }
 138
 139    /// <summary>
 140    /// Clears all object pools, releasing any pooled arrays and resetting the state.
 141    /// </summary>
 142    public void Clear()
 143    {
 4144        if (_disposed) return;
 145
 10146        foreach (SwiftObjectPool<T[]> pool in _sizePools.Values)
 3147            pool.Clear();
 148
 2149        _sizePools.Clear();
 2150    }
 151
 152    /// <summary>
 153    /// Creates a new object pool for managing arrays of the specified size.
 154    /// </summary>
 155    /// <param name="size">The size of arrays to be managed by the pool.</param>
 156    /// <returns>A new instance of <see cref="SwiftObjectPool{T}"/> for managing arrays of the specified size.</returns>
 157    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 158    private SwiftObjectPool<T[]> CreatePoolForSize(int size)
 159    {
 13160        return new SwiftObjectPool<T[]>(
 13161            createFunc: () => CreateFunc(size),
 13162            actionOnRelease: ActionOnRelease,
 13163            actionOnDestroy: ActionOnDestroy,
 13164            maxSize: PoolMaxCapacity
 13165        );
 166    }
 167
 168    #endregion
 169
 170    #region IDisposable Implementation
 171
 172    /// <summary>
 173    /// Releases all resources used by the SwiftArrayPool.
 174    /// It is important to call Dispose() to release pooled arrays, preventing potential memory leaks.
 175    /// </summary>
 176    public void Dispose()
 177    {
 15178        if (_disposed) return;
 179
 13180        _disposed = true;
 46181        foreach (SwiftObjectPool<T[]> pool in _sizePools.Values)
 10182            pool.Dispose();
 13183        _sizePools.Clear();
 184
 185        // Suppress finalization to prevent unnecessary GC overhead
 13186        GC.SuppressFinalize(this);
 13187    }
 188
 189    /// <summary>
 190    /// Releases the resources used by the SwiftArrayPool instance.
 191    /// </summary>
 192    /// <remarks>
 193    /// This finalizer ensures that unmanaged resources are released if Dispose was not called explicitly.
 194    /// It is recommended to call Dispose to release resources deterministically.
 195    /// </remarks>
 10196    ~SwiftArrayPool() => Dispose();
 197
 198    #endregion
 199}