using System; using System.Runtime.CompilerServices; namespace MemoryPools.Collections.Specialized { public abstract class PoolingQueue : IDisposable { private IPoolingNode _enqueueTo; private IPoolingNode _dequeueFrom; private int _enqueueIndex, _dequeueIndex; protected PoolingQueue() { Count = 0; _enqueueIndex = 0; _dequeueIndex = 0; _enqueueTo = _dequeueFrom = null; } public bool IsEmpty => Count == 0; public int Count { get; private set; } public void Dispose() { Clear(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Enqueue(T obj) { if (Count == 0 && _enqueueTo == null) _enqueueTo = _dequeueFrom = CreateNodeHolder(); _enqueueTo[_enqueueIndex] = obj; _enqueueIndex++; Count++; if (_enqueueIndex == PoolsDefaults.DefaultPoolBucketSize) { var enqueue = _enqueueTo; _enqueueTo = CreateNodeHolder(); enqueue.Next = _enqueueTo; _enqueueIndex = 0; } } protected abstract IPoolingNode CreateNodeHolder(); /// /// Tries to return queue element if any available via `val` parameter. /// /// /// true if element found or false otherwise /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool TryDequeue(out T val) { if (IsEmpty) { val = default; return false; } val = Dequeue(); return true; } /// /// Returns queue element /// /// /// Returns element or throws IndexOutOfRangeException if no element found /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public T Dequeue() { if (IsEmpty) throw new IndexOutOfRangeException(); var obj = _dequeueFrom[_dequeueIndex]; _dequeueFrom[_dequeueIndex] = default; _dequeueIndex++; Count--; if (_dequeueIndex == PoolsDefaults.DefaultPoolBucketSize) { var dequeue = _dequeueFrom; _dequeueFrom = _dequeueFrom.Next; _dequeueIndex = 0; dequeue.Dispose(); } if (Count == 0) { // return back to pool if (_enqueueTo != _dequeueFrom) { var empty = _dequeueFrom; _dequeueFrom = _dequeueFrom.Next; _dequeueIndex = 0; empty.Dispose(); } else // reset to pool start { _enqueueIndex = 0; _dequeueIndex = 0; } } return obj; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Clear() { while (_enqueueTo != null) { var next = _enqueueTo.Next; _enqueueTo.Dispose(); _enqueueTo = next; } _dequeueFrom = null; } } }