// MIT License - Copyright (c) 2026 wallstop // Full license text: https://github.com/wallstop/unity-helpers/blob/main/LICENSE namespace WallstopStudios.UnityHelpers.Core.DataStructure { using System; using System.Runtime.CompilerServices; using WallstopStudios.UnityHelpers.Core.Helper; /// /// Immutable snapshot of cache performance statistics. /// /// /// Statistics are only recorded when is enabled. /// Use to retrieve the current snapshot. /// public readonly struct CacheStatistics : IEquatable { /// /// The number of times a requested key was found in the cache. /// public long HitCount { get; } /// /// The number of times a requested key was not found in the cache. /// public long MissCount { get; } /// /// The total number of entries evicted from the cache (for any reason). /// public long EvictionCount { get; } /// /// The number of times the cache loaded a value using the factory function. /// public long LoadCount { get; } /// /// The number of entries that were evicted due to TTL expiration. /// public long ExpiredCount { get; } /// /// The current number of entries in the cache. /// public int CurrentSize { get; } /// /// The maximum number of entries the cache has held at any point. /// public int PeakSize { get; } /// /// The number of times the cache has grown due to thrash detection. /// public int GrowthEvents { get; } private readonly int _hash; /// /// The cache hit rate as a value between 0.0 and 1.0. /// Returns 0.0 if no requests have been made. /// public double HitRate { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { long total = HitCount + MissCount; return total > 0 ? HitCount / (double)total : 0.0; } } /// /// The cache miss rate as a value between 0.0 and 1.0. /// Returns 0.0 if no requests have been made. /// public double MissRate { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => 1.0 - HitRate; } /// /// Creates a new statistics snapshot. /// public CacheStatistics( long hitCount, long missCount, long evictionCount, long loadCount, long expiredCount, int currentSize, int peakSize, int growthEvents ) { HitCount = hitCount; MissCount = missCount; EvictionCount = evictionCount; LoadCount = loadCount; ExpiredCount = expiredCount; CurrentSize = currentSize; PeakSize = peakSize; GrowthEvents = growthEvents; _hash = Objects.HashCode( hitCount, missCount, evictionCount, loadCount, expiredCount, currentSize, peakSize, growthEvents ); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(CacheStatistics other) { return _hash == other._hash && HitCount == other.HitCount && MissCount == other.MissCount && EvictionCount == other.EvictionCount && LoadCount == other.LoadCount && ExpiredCount == other.ExpiredCount && CurrentSize == other.CurrentSize && PeakSize == other.PeakSize && GrowthEvents == other.GrowthEvents; } /// public override bool Equals(object obj) { return obj is CacheStatistics other && Equals(other); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() { return _hash; } /// /// Equality operator. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(CacheStatistics left, CacheStatistics right) { return left.Equals(right); } /// /// Inequality operator. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(CacheStatistics left, CacheStatistics right) { return !left.Equals(right); } /// public override string ToString() { return $"CacheStatistics(Hits={HitCount}, Misses={MissCount}, Evictions={EvictionCount}, " + $"Size={CurrentSize}, Peak={PeakSize}, HitRate={HitRate:P2})"; } } }