// MIT License - Copyright (c) 2026 wallstop // Full license text: https://github.com/wallstop/unity-helpers/blob/main/LICENSE namespace WallstopStudios.UnityHelpers.Utils { using System; using System.Runtime.CompilerServices; using WallstopStudios.UnityHelpers.Core.Helper; /// /// Immutable snapshot of pool performance statistics. /// /// /// Use to retrieve the current snapshot. /// Statistics are always recorded regardless of pool configuration. /// public readonly struct PoolStatistics : IEquatable { /// /// Tolerance for floating-point equality comparisons. /// private const float FloatEqualityTolerance = 0.001f; /// /// The current number of items in the pool. /// public int CurrentSize { get; } /// /// The maximum number of items the pool has held at any point. /// public int PeakSize { get; } /// /// The total number of times items have been rented from the pool. /// public long RentCount { get; } /// /// The total number of times items have been returned to the pool. /// public long ReturnCount { get; } /// /// The total number of items purged from the pool for any reason. /// public long PurgeCount { get; } /// /// The number of items purged due to idle timeout expiration. /// public long IdleTimeoutPurges { get; } /// /// The number of items purged due to pool capacity being exceeded. /// public long CapacityPurges { get; } /// /// The number of purge operations that completed fully (purged all eligible items). /// public long FullPurgeOperations { get; } /// /// The number of purge operations that were partial (hit MaxPurgesPerOperation limit). /// Partial purges continue on subsequent Rent/Return/Periodic operations. /// public long PartialPurgeOperations { get; } /// /// The current rentals-per-minute rate based on the rolling frequency window. /// Used for intelligent purge decisions - high-frequency pools keep larger buffers. /// public float RentalsPerMinute { get; } /// /// The average time between consecutive rentals in seconds. /// This represents the inter-arrival time between rental operations, not the duration items are held. /// Returns 0 if fewer than two rentals have occurred. /// public float AverageInterRentalTimeSeconds { get; } /// /// The time of the most recent access (rent or return). /// public float LastAccessTime { get; } /// /// Whether this pool is considered high-frequency (10+ rentals/minute). /// High-frequency pools benefit from larger buffers to avoid GC churn. /// public bool IsHighFrequency { get; } /// /// Whether this pool is considered low-frequency (at most 1 rental/minute). /// Low-frequency pools can be purged more aggressively. /// public bool IsLowFrequency { get; } /// /// Whether this pool is considered unused (no access in 5+ minutes). /// Unused pools are candidates for aggressive purging. /// public bool IsUnused { get; } private readonly int _hash; /// /// Creates a new statistics snapshot. /// /// Current number of items in the pool. /// Maximum pool size reached. /// Total rent operations. /// Total return operations. /// Total purge operations. /// Purges due to idle timeout. /// Purges due to capacity limits. /// Purge operations that completed fully. /// Purge operations that were partial (hit max limit). /// Current rentals-per-minute rate. /// Average time between consecutive rentals in seconds. /// Time of most recent access. /// Whether this is a high-frequency pool. /// Whether this is a low-frequency pool. /// Whether this pool is unused. public PoolStatistics( int currentSize, int peakSize, long rentCount, long returnCount, long purgeCount, long idleTimeoutPurges, long capacityPurges, long fullPurgeOperations = 0, long partialPurgeOperations = 0, float rentalsPerMinute = 0f, float averageInterRentalTimeSeconds = 0f, float lastAccessTime = 0f, bool isHighFrequency = false, bool isLowFrequency = false, bool isUnused = false ) { CurrentSize = currentSize; PeakSize = peakSize; RentCount = rentCount; ReturnCount = returnCount; PurgeCount = purgeCount; IdleTimeoutPurges = idleTimeoutPurges; CapacityPurges = capacityPurges; FullPurgeOperations = fullPurgeOperations; PartialPurgeOperations = partialPurgeOperations; RentalsPerMinute = rentalsPerMinute; AverageInterRentalTimeSeconds = averageInterRentalTimeSeconds; LastAccessTime = lastAccessTime; IsHighFrequency = isHighFrequency; IsLowFrequency = isLowFrequency; IsUnused = isUnused; _hash = Objects.HashCode( currentSize, peakSize, rentCount, returnCount, purgeCount, idleTimeoutPurges, capacityPurges, fullPurgeOperations, partialPurgeOperations, rentalsPerMinute, averageInterRentalTimeSeconds, lastAccessTime, isHighFrequency, isLowFrequency, isUnused ); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(PoolStatistics other) { return _hash == other._hash && CurrentSize == other.CurrentSize && PeakSize == other.PeakSize && RentCount == other.RentCount && ReturnCount == other.ReturnCount && PurgeCount == other.PurgeCount && IdleTimeoutPurges == other.IdleTimeoutPurges && CapacityPurges == other.CapacityPurges && FullPurgeOperations == other.FullPurgeOperations && PartialPurgeOperations == other.PartialPurgeOperations && Math.Abs(RentalsPerMinute - other.RentalsPerMinute) < FloatEqualityTolerance && Math.Abs(AverageInterRentalTimeSeconds - other.AverageInterRentalTimeSeconds) < FloatEqualityTolerance && Math.Abs(LastAccessTime - other.LastAccessTime) < FloatEqualityTolerance && IsHighFrequency == other.IsHighFrequency && IsLowFrequency == other.IsLowFrequency && IsUnused == other.IsUnused; } /// public override bool Equals(object obj) { return obj is PoolStatistics other && Equals(other); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() { return _hash; } /// /// Equality operator. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(PoolStatistics left, PoolStatistics right) { return left.Equals(right); } /// /// Inequality operator. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(PoolStatistics left, PoolStatistics right) { return !left.Equals(right); } /// public override string ToString() { return $"PoolStatistics(CurrentSize={CurrentSize}, Peak={PeakSize}, Rents={RentCount}, " + $"Returns={ReturnCount}, Purges={PurgeCount}, IdleTimeout={IdleTimeoutPurges}, " + $"Capacity={CapacityPurges}, FullPurgeOps={FullPurgeOperations}, PartialPurgeOps={PartialPurgeOperations}, " + $"RentalsPerMin={RentalsPerMinute:F2}, AvgInterRentalTime={AverageInterRentalTimeSeconds:F3}s, " + $"LastAccess={LastAccessTime:F2}s, High={IsHighFrequency}, Low={IsLowFrequency}, Unused={IsUnused})"; } } }