moel@298: /* moel@298: moel@344: This Source Code Form is subject to the terms of the Mozilla Public moel@344: License, v. 2.0. If a copy of the MPL was not distributed with this moel@344: file, You can obtain one at http://mozilla.org/MPL/2.0/. moel@298: moel@344: Copyright (C) 2011 Michael Möller moel@344: moel@298: */ moel@298: moel@298: using System; moel@298: using System.Collections; moel@298: using System.Collections.Generic; moel@298: moel@298: namespace OpenHardwareMonitor.Collections { moel@298: public class RingCollection : IEnumerable { moel@298: moel@298: private T[] array; moel@298: moel@298: // first item of collection moel@298: private int head; moel@298: moel@298: // index after the last item of the collection moel@298: private int tail; moel@298: moel@298: // number of items in the collection moel@298: private int size; moel@298: moel@298: public RingCollection() : this(0) { } moel@298: moel@298: public RingCollection(int capacity) { moel@298: if (capacity < 0) moel@298: throw new ArgumentOutOfRangeException("capacity"); moel@298: this.array = new T[capacity]; moel@298: this.head = 0; moel@298: this.tail = 0; moel@298: this.size = 0; moel@298: } moel@298: moel@298: public int Capacity { moel@298: get { moel@298: return array.Length; moel@298: } moel@298: set { moel@298: T[] newArray = new T[value]; moel@298: if (size > 0) { moel@298: if (head < tail) { moel@298: Array.Copy(array, head, newArray, 0, size); moel@298: } else { moel@298: Array.Copy(array, head, newArray, 0, array.Length - head); moel@298: Array.Copy(array, 0, newArray, array.Length - head, tail); moel@298: } moel@298: } moel@298: this.array = newArray; moel@298: this.head = 0; moel@298: this.tail = size == value ? 0 : size; moel@298: } moel@298: } moel@298: moel@298: public void Clear() { moel@298: moel@298: // remove potential references moel@298: if (head < tail) { moel@298: Array.Clear(array, head, size); moel@298: } else { moel@298: Array.Clear(array, 0, tail); moel@298: Array.Clear(array, head, array.Length - head); moel@298: } moel@298: moel@298: this.head = 0; moel@298: this.tail = 0; moel@298: this.size = 0; moel@298: } moel@298: moel@298: public void Append(T item) { moel@298: if (size == array.Length) { moel@298: int newCapacity = array.Length * 3 / 2; moel@298: if (newCapacity < array.Length + 8) moel@298: newCapacity = array.Length + 8; moel@298: Capacity = newCapacity; moel@298: } moel@298: moel@298: array[tail] = item; moel@298: tail = tail + 1 == array.Length ? 0 : tail + 1; moel@298: size++; moel@298: } moel@298: moel@298: public T Remove() { moel@298: if (size == 0) moel@298: throw new InvalidOperationException(); moel@298: moel@298: T result = array[head]; moel@298: array[head] = default(T); moel@298: head = head + 1 == array.Length ? 0 : head + 1; moel@298: size--; moel@298: moel@298: return result; moel@298: } moel@298: moel@298: public int Count { moel@298: get { moel@298: return size; moel@298: } moel@298: } moel@298: moel@298: public T this[int index] { moel@298: get { moel@298: if (index < 0 || index >= size) moel@298: throw new IndexOutOfRangeException(); moel@298: int i = head + index; moel@298: if (i >= array.Length) moel@298: i -= array.Length; moel@298: return array[i]; moel@298: } moel@298: set { moel@298: if (index < 0 || index >= size) moel@298: throw new IndexOutOfRangeException(); moel@298: int i = head + index; moel@298: if (i >= array.Length) moel@298: i -= array.Length; moel@298: array[i] = value; moel@298: } moel@298: } moel@298: moel@298: public T First { moel@298: get { moel@298: if (size == 0) moel@298: throw new InvalidOperationException(); moel@298: return array[head]; moel@298: } moel@298: set { moel@298: if (size == 0) moel@298: throw new InvalidOperationException(); moel@298: array[head] = value; moel@298: } moel@298: } moel@298: moel@298: public T Last { moel@298: get { moel@298: if (size == 0) moel@298: throw new InvalidOperationException(); moel@298: return array[tail == 0 ? array.Length - 1 : tail - 1]; moel@298: } moel@298: set { moel@298: if (size == 0) moel@298: throw new InvalidOperationException(); moel@298: array[tail == 0 ? array.Length - 1 : tail - 1] = value; moel@298: } moel@298: } moel@298: moel@298: IEnumerator IEnumerable.GetEnumerator() { moel@298: return new RingCollection.Enumerator(this); moel@298: } moel@298: moel@298: IEnumerator IEnumerable.GetEnumerator() { moel@298: return new RingCollection.Enumerator(this); moel@298: } moel@298: moel@298: private struct Enumerator : IEnumerator, IEnumerator { moel@298: moel@298: private RingCollection collection; moel@298: private int index; moel@298: moel@298: public Enumerator(RingCollection collection) { moel@298: this.collection = collection; moel@298: this.index = -1; moel@298: } moel@298: moel@298: public void Dispose() { moel@298: this.index = -2; moel@298: } moel@298: moel@298: public void Reset() { moel@298: this.index = -1; moel@298: } moel@298: moel@298: public T Current { moel@298: get { moel@298: if (index < 0) moel@298: throw new InvalidOperationException(); moel@298: return collection[index]; moel@298: } moel@298: } moel@298: moel@298: object IEnumerator.Current { moel@298: get { moel@298: if (index < 0) moel@298: throw new InvalidOperationException(); moel@298: return collection[index]; moel@298: } moel@298: } moel@298: moel@298: public bool MoveNext() { moel@298: if (index == -2) moel@298: return false; moel@298: moel@298: index++; moel@298: moel@298: if (index == collection.size) { moel@298: index = -2; moel@298: return false; moel@298: } moel@298: moel@298: return true; moel@298: } moel@298: } moel@298: } moel@298: }