moel@298: /*
moel@298:   
moel@298:   Version: MPL 1.1/GPL 2.0/LGPL 2.1
moel@298: 
moel@298:   The contents of this file are subject to the Mozilla Public License Version
moel@298:   1.1 (the "License"); you may not use this file except in compliance with
moel@298:   the License. You may obtain a copy of the License at
moel@298:  
moel@298:   http://www.mozilla.org/MPL/
moel@298: 
moel@298:   Software distributed under the License is distributed on an "AS IS" basis,
moel@298:   WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
moel@298:   for the specific language governing rights and limitations under the License.
moel@298: 
moel@298:   The Original Code is the Open Hardware Monitor code.
moel@298: 
moel@298:   The Initial Developer of the Original Code is 
moel@298:   Michael Möller <m.moeller@gmx.ch>.
moel@298:   Portions created by the Initial Developer are Copyright (C) 2011
moel@298:   the Initial Developer. All Rights Reserved.
moel@298: 
moel@298:   Contributor(s):
moel@298: 
moel@298:   Alternatively, the contents of this file may be used under the terms of
moel@298:   either the GNU General Public License Version 2 or later (the "GPL"), or
moel@298:   the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
moel@298:   in which case the provisions of the GPL or the LGPL are applicable instead
moel@298:   of those above. If you wish to allow use of your version of this file only
moel@298:   under the terms of either the GPL or the LGPL, and not to allow others to
moel@298:   use your version of this file under the terms of the MPL, indicate your
moel@298:   decision by deleting the provisions above and replace them with the notice
moel@298:   and other provisions required by the GPL or the LGPL. If you do not delete
moel@298:   the provisions above, a recipient may use your version of this file under
moel@298:   the terms of any one of the MPL, the GPL or the LGPL.
moel@298:  
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: }