using System.Collections.Concurrent; using System.Runtime.CompilerServices; using System.Threading; namespace Best.HTTP.Shared.PlatformSupport.Memory { internal struct Bucket { #if UNITY_EDITOR /// /// Size the Bucket is associated with. Serves mostly debug purposes. /// public readonly int Size; #endif /// /// What was Items' minimum Count between two checks. /// public int MinCount; /// /// Direct access to a buffer, without going throug ConcurrentStack's pop/push logic. /// public byte[] FastItem; private int _count; private readonly ConcurrentStack _items; public Bucket(int size) { #if UNITY_EDITOR this.Size = size; #endif this.FastItem = null; this._items = new ConcurrentStack(); this.MinCount = int.MaxValue; this._count = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool TryPop(out byte[] item) { if (this._items.TryPop(out item)) { Interlocked.Decrement(ref this._count); return true; } return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Push(byte[] item) { this._items.Push(item); Interlocked.Increment(ref this._count); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Clear() { this._items.Clear(); Interlocked.Exchange(ref this._count, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void UpdateMinCount(int fastItem) { int newMinCount = _count + fastItem; int oldMinCount = MinCount; while (newMinCount < oldMinCount && Interlocked.CompareExchange(ref MinCount, newMinCount, oldMinCount) != oldMinCount) oldMinCount = MinCount; } #if UNITY_EDITOR public override string ToString() => $"[{Size}, {(FastItem != null ? "y" : "n")}, {_count}, {MinCount}]"; #endif } }