using System; using System.Collections; using System.Collections.Generic; namespace ReClassNET.Util { /// /// A circular buffer with a fixed size. /// public class CircularBuffer : IEnumerable { private readonly T[] buffer; private int head; private int tail; public CircularBuffer(int capacity) { if (capacity < 0) { throw new ArgumentOutOfRangeException(nameof(capacity)); } buffer = new T[capacity]; head = capacity - 1; } public int Count { get; private set; } public int Capacity => buffer.Length; public T Head => buffer[head]; public T Tail => buffer[tail]; public T Enqueue(T item) { head = (head + 1) % Capacity; var overwritten = buffer[head]; buffer[head] = item; if (Count == Capacity) { tail = (tail + 1) % Capacity; } else { ++Count; } return overwritten; } public T Dequeue() { if (Count == 0) { throw new InvalidOperationException(); } var dequeued = buffer[head]; buffer[head] = default; if (head == 0) { head = Capacity - 1; } else { head = (head - 1) % Capacity; } --Count; return dequeued; } public void Clear() { head = Capacity - 1; tail = 0; Count = 0; } public T this[int index] { get { if (index < 0 || index >= Count) { throw new ArgumentOutOfRangeException(nameof(index)); } return buffer[(tail + index) % Capacity]; } set { if (index < 0 || index >= Count) { throw new ArgumentOutOfRangeException(nameof(index)); } buffer[(tail + index) % Capacity] = value; } } public int IndexOf(T item) { for (var i = 0; i < Count; ++i) { if (Equals(item, this[i])) { return i; } } return -1; } public void Insert(int index, T item) { if (index < 0 || index > Count) { throw new ArgumentOutOfRangeException(nameof(index)); } if (Count == index) { Enqueue(item); } else { var last = this[Count - 1]; for (var i = index; i < Count - 2; ++i) { this[i + 1] = this[i]; } this[index] = item; Enqueue(last); } } public void RemoveAt(int index) { if (index < 0 || index >= Count) { throw new ArgumentOutOfRangeException(nameof(index)); } for (var i = index; i > 0; --i) { this[i] = this[i - 1]; } Dequeue(); } public IEnumerator GetEnumerator() { if (Count == 0 || Capacity == 0) { yield break; } for (var i = 0; i < Count; ++i) { yield return this[i]; } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } }