using System; using System.Linq; using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Collections; namespace DataStructures.CircularBufferSpace { [Serializable] public class CircularBuffer : IEnumerable { private int getIndex, addIndex; private T[] buffer; public int Count { get; private set; } public int Capacity { get; private set; } public bool IsEmpty { get { return (Count == 0); } } [ContractInvariantMethod] private void ObjectInvariant() { Contract.Invariant(Capacity > 0); Contract.Invariant(Count >= 0); Contract.Invariant(Count <= Capacity); } /// /// Instantiates a new circular buffer. /// /// The maximum size of the buffer before it begins overwriting itself. public CircularBuffer(int capacity) { Contract.Requires(capacity > 0); buffer = new T[capacity]; Capacity = capacity; Count = 0; addIndex = 0; getIndex = 0; } /// /// Instantiates a new circular buffer with the input collection's capacity and elements. /// /// The collection with elements to insert into the buffer. public CircularBuffer(ICollection collection) { Contract.Requires(collection != null && collection.Count > 0); buffer = new T[collection.Count]; Capacity = buffer.Length; Count = 0; addIndex = 0; getIndex = 0; foreach (T item in collection) { Add(item); } } /// /// Instantiates a new circular buffer with the input enumerable's capacity and elements. /// /// The enumerable with elements to insert into the buffer. public CircularBuffer(IEnumerable enumerable) { var enumCount = enumerable.Count(); Contract.Requires(enumerable != null && enumCount > 0); buffer = new T[enumCount]; Capacity = buffer.Length; Count = 0; addIndex = 0; getIndex = 0; foreach (T item in enumerable) { Add(item); } } /// /// Adds an element to the circular buffer. /// public void Add(T item) { Contract.Requires(item != null); buffer[addIndex] = item; if (Count < Capacity) Count++; if (addIndex == getIndex) getIndex = getIndex < Capacity - 1 ? getIndex + 1 : 0; addIndex = addIndex < Capacity - 1 ? addIndex + 1 : 0; } /// /// Clears the circular buffer of all elements. /// public void Clear() { for (int i = 0; i < buffer.Length; i++) buffer[i] = default(T); Count = 0; addIndex = 0; getIndex = 0; } /// /// Determines whether a sequence contains a specified element by using the default equality comparer. /// public bool Contains(T item) { Contract.Requires(item != null); return buffer.Contains(item); } /// /// Copies the circular buffer to an array starting at the specified index in the destination array. /// public void CopyTo(T[] array, int index = 0) { Contract.Requires(array != null); Contract.Requires(index + Count < array.Length); buffer.CopyTo(array, index); } /// /// Gets the oldest element in the circular buffer. /// public T Get() { Contract.Requires(Count > 0); var retVal = buffer[getIndex]; buffer[getIndex] = default(T); getIndex = getIndex < Capacity - 1 ? getIndex + 1 : 0; return retVal; } /// /// Supports a simple iteration over a generic collection. /// public IEnumerator GetEnumerator() { for (int i = 0; i < buffer.Length; i++) yield return buffer[i]; } /// /// Supports a simple iteration over a nongeneric collection. /// System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return this.GetEnumerator(); } } }