using System; namespace FishNet.Utility.Performance { /// /// Unity 2022 has a bug where codegen will not compile when referencing a Queue type, /// while also targeting .Net as the framework API. /// As a work around this class is used for queues instead. /// public class BasicQueue { /// /// Maximum size of the collection. /// public int Capacity => Collection.Length; /// /// Number of elements in the queue. /// public int Count => _written; /// /// Collection containing data. /// private T[] Collection = new T[4]; /// /// Current write index of the collection. /// public int WriteIndex { get; private set; } /// /// Buffer for resizing. /// private T[] _resizeBuffer = new T[0]; /// /// Read position of the next Dequeue. /// private int _read; /// /// Length of the queue. /// private int _written; /// /// Enqueues an entry. /// /// public void Enqueue(T data) { if (_written == Collection.Length) Resize(); if (WriteIndex >= Collection.Length) WriteIndex = 0; Collection[WriteIndex] = data; WriteIndex++; _written++; } /// /// Tries to dequeue the next entry. /// /// Dequeued entry. /// True if an entry existed to dequeue. public bool TryDequeue(out T result) { if (_written == 0) { result = default; return false; } result = Dequeue(); return true; } /// /// Dequeues the next entry. /// /// public T Dequeue() { if (_written == 0) throw new Exception($"Queue of type {typeof(T).Name} is empty."); T result = Collection[_read]; _written--; _read++; if (_read >= Collection.Length) _read = 0; return result; } /// /// Tries to peek the next entry. /// /// Peeked entry. /// True if an entry existed to peek. public bool TryPeek(out T result) { if (_written == 0) { result = default; return false; } result = Peek(); return true; } /// /// Peeks the next queue entry. /// /// public T Peek() { if (_written == 0) throw new Exception($"Queue of type {typeof(T).Name} is empty."); return Collection[_read]; } /// /// Clears the queue. /// /// True to make buffer entries default. public void Clear() { _read = 0; WriteIndex = 0; _written = 0; DefaultCollection(Collection); DefaultCollection(_resizeBuffer); void DefaultCollection(T[] array) { int count = array.Length; for (int i = 0; i < count; i++) array[i] = default; } } /// /// Doubles the queue size. /// private void Resize() { int length = _written; int doubleLength = (length * 2); int read = _read; /* Make sure copy array is the same size as current * and copy contents into it. */ //Ensure large enough to fit contents. T[] resizeBuffer = _resizeBuffer; if (resizeBuffer.Length < doubleLength) Array.Resize(ref resizeBuffer, doubleLength); //Copy from the read of queue first. int copyLength = (length - read); Array.Copy(Collection, read, resizeBuffer, 0, copyLength); /* If read index was higher than 0 * then copy remaining data as well from 0. */ if (read > 0) Array.Copy(Collection, 0, resizeBuffer, copyLength, read); //Set _array to resize. Collection = resizeBuffer; //Reset positions. _read = 0; WriteIndex = length; } /// /// Returns value in actual index as it relates to simulated index. /// /// Simulated index to return. A value of 0 would return the first simulated index in the collection. /// public T this[int simulatedIndex] { get { int offset = (Capacity - _written) + simulatedIndex + WriteIndex; if (offset >= Capacity) offset -= Capacity; return Collection[offset]; } set { int offset = (Capacity - _written) + simulatedIndex + WriteIndex; if (offset >= Capacity) offset -= Capacity; Collection[offset] = value; } } } }