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 <mmoeller@openhardwaremonitor.org>
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<T> : IEnumerable<T> {
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<T> IEnumerable<T>.GetEnumerator() {
moel@298:       return new RingCollection<T>.Enumerator(this);
moel@298:     }
moel@298: 
moel@298:     IEnumerator IEnumerable.GetEnumerator() {
moel@298:       return new RingCollection<T>.Enumerator(this);
moel@298:     }
moel@298: 
moel@298:     private struct Enumerator : IEnumerator<T>, IEnumerator {
moel@298: 
moel@298:       private RingCollection<T> collection;
moel@298:       private int index;
moel@298: 
moel@298:       public Enumerator(RingCollection<T> 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: }