/Utilities/Collections/Dequeue.cs
C# | 930 lines | 573 code | 67 blank | 290 comment | 44 complexity | deae76d0fff26c3a421b9ed577ac069d MD5 | raw file
Possible License(s): Apache-2.0
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using NUnit.Framework;
-
- namespace Delta.Utilities.Collections
- {
- /// <summary>
- /// System.Collections conform class for a ring-queue.
- /// </summary>
- /// <remarks>
- /// The collection support adding and removing at both ends and automatic
- /// expansion. The left end of the ring is referred to as head, the right
- /// end as tail. Add / Remove needs always the same time, expansion takes
- /// more time, depending on the size. Indexed access and enumeration is fast.
- /// </remarks>
- public class Dequeue<T>
- : ICollection<T>, IEnumerable<T>, ICloneable<Dequeue<T>>
- {
- #region IsReadOnly (Public)
- /// <summary>
- /// Is read only? Will always return false.
- /// </summary>
- public bool IsReadOnly
- {
- get
- {
- return false;
- } // get
- }
- #endregion
-
- #region AllowsDuplicates (Public)
- /// <summary>
- /// Allows duplicates? Will always return false.
- /// </summary>
- public bool AllowsDuplicates
- {
- get
- {
- return true;
- } // get
- }
- #endregion
-
- #region IsEmpty (Public)
- /// <summary>
- /// Is empty? Will return true if we have at least one item.
- /// </summary>
- public bool IsEmpty
- {
- get
- {
- return count != 0;
- } // get
- }
- #endregion
-
- #region Item (Public)
- /// <summary>
- /// Indexed access to all elements currently in the collection.
- /// Indexing starts at 0 (head) and ends at Count-1 (tail).
- /// </summary>
- /// <returns>Item at this index</returns>
- public T this[int index]
- {
- get
- {
- if (index < 0 ||
- index >= Count)
- {
- throw new ArgumentOutOfRangeException("index");
- }
- return innerList[(head + index) % Capacity];
- }
- set
- {
- if (index < 0 ||
- index >= Count)
- {
- throw new ArgumentOutOfRangeException("index");
- }
- innerList[(head + index) % Capacity] = value;
- version++;
- }
- }
- #endregion
-
- #region GrowthFactor (Public)
- /// <summary>
- /// The current factor by which to grow the collection in case of expansion
- /// </summary>
- /// <typeparam name="T">T</typeparam>
- public double GrowthFactor
- {
- get
- {
- return growthFactor;
- }
- set
- {
- growthFactor = value;
- }
- }
- #endregion
-
- #region Capacity (Public)
- /// <summary>
- /// The current amount of cells available to the dequeue
- /// </summary>
- /// <typeparam name="T">T</typeparam>
- public int Capacity
- {
- get
- {
- return innerList.Length;
- }
- set
- {
- if (Capacity >= Count)
- {
- SetSize(Capacity);
- }
- else
- {
- throw new ArgumentException("Capacity was smaller than Count!");
- }
- }
- }
- #endregion
-
- #region Version (Public)
- /// <summary>
- /// The current version of the dequeue. The version is increased with every
- /// changing operation. The main use is to invalidate all IEnumerators.
- /// </summary>
- /// <typeparam name="T">T</typeparam>
- public ulong Version
- {
- get
- {
- return version;
- }
- }
- #endregion
-
- #region IsSynchronized (Public)
- /// <summary>
- /// Returns true.
- /// </summary>
- /// <typeparam name="T">T</typeparam>
- public bool IsSynchronized
- {
- get
- {
- return true;
- }
- }
- #endregion
-
- #region Count (Public)
- /// <summary>
- /// The current number of elements in the queue
- /// </summary>
- /// <typeparam name="T">T</typeparam>
- public int Count
- {
- get
- {
- return count;
- }
- }
- #endregion
-
- #region SyncRoot (Public)
- /// <summary>
- /// Returns sync root for this dequeue, which is always this object.
- /// </summary>
- public object SyncRoot
- {
- get
- {
- return this;
- }
- }
- #endregion
-
- #region Protected
-
- #region innerList (Protected)
- /// <summary>
- /// Inner list for this dequeue
- /// </summary>
- /// <typeparam name="T">T</typeparam>
- protected T[] innerList;
- #endregion
-
- #region growthFactor (Protected)
- /// <summary>
- /// Grow factor
- /// </summary>
- /// <typeparam name="T">T</typeparam>
- protected double growthFactor;
- #endregion
-
- #region head (Protected)
- /// <summary>
- /// Head, tail and count of elements
- /// </summary>
- /// <typeparam name="T">T</typeparam>
- protected int head;
- #endregion
-
- #region tail (Protected)
- /// <summary>
- /// Head, tail and count of elements
- /// </summary>
- /// <typeparam name="T">T</typeparam>
- protected int tail;
- #endregion
-
- #region count (Protected)
- /// <summary>
- /// Head, tail and count of elements
- /// </summary>
- /// <typeparam name="T">T</typeparam>
- protected int count;
- #endregion
-
- #region version (Protected)
- /// <summary>
- /// Version, who needs that?
- /// </summary>
- /// <typeparam name="T">T</typeparam>
- protected ulong version;
- #endregion
-
- #endregion
-
- #region Constructors
- /// <summary>
- /// Create an empty Dequeue with capacity 32 and growth 2
- /// </summary>
- public Dequeue()
- : this(32, 2.0)
- {
- }
-
- /// <summary>
- /// Create an empty Dequeue with given capacity and growth 2
- /// </summary>
- /// <param name="capacity">the initial capacity of the collection</param>
- public Dequeue(int capacity)
- : this(capacity, 2.0)
- {
- }
-
- /// <summary>
- /// Create an empty Dequeue with given capacity and given growth
- /// </summary>
- /// <param name="capacity">The initial capacity of the collection</param>
- /// <param name="setGrowthFactor">The factor by which to grow the
- /// collection when the capacity is reached</param>
- public Dequeue(int capacity, double setGrowthFactor)
- {
- if (capacity < 1)
- {
- throw new ArgumentException("capacity", "must be at least 1.");
- }
-
- innerList = new T[capacity];
- growthFactor = setGrowthFactor;
- head = 0;
- tail = capacity - 1;
- /// <summary>
- /// Count
- /// </summary>
- count = 0;
- version = 0;
- }
-
- /// <summary>
- /// Create a new Dequeue as a copy of the given collection
- /// </summary>
- /// <param name="collection">The source collection</param>
- public Dequeue(ICollection<T> collection)
- : this(collection, collection.Count)
- {
- }
-
- /// <summary>
- /// Create a new Dequeue as a copy of the given collection and the
- /// given capacity.
- /// </summary>
- /// <param name="collection">The source collection</param>
- /// <param name="capacity">The capacity of the new Dequeue
- /// (must be bigger or equal as C.Count)</param>
- public Dequeue(ICollection<T> collection, int capacity)
- : this(capacity, 2.0)
- {
- tail = 0;
- EnqueueTailRange(collection);
- }
- #endregion
-
- #region ICloneable<Dequeue<T>> Members
- /// <summary>
- /// Standard implementation.
- /// </summary>
- /// <returns>A Dequeue with a shallow copy of this one.</returns>
- public Dequeue<T> Clone()
- {
- Dequeue<T> newDequeue = new Dequeue<T>(this, Capacity);
- newDequeue.growthFactor = growthFactor;
- newDequeue.version = Version;
- return newDequeue;
- }
- #endregion
-
- #region ICollection<T> Members
- /// <summary>
- /// Add. Not supported, do not call!
- /// </summary>
- /// <param name="item">Item to add</param>
- public void Add(T item)
- {
- throw new Exception("The method or operation is not implemented.");
- }
-
- /// <summary>
- /// Deletes all entries from the collection
- /// </summary>
- public void Clear()
- {
- head = tail = count = 0;
- version++;
- }
-
- /// <summary>
- /// Contains
- /// </summary>
- /// <param name="item">Item</param>
- /// <returns>True if the item was found, false otherwise.</returns>
- public bool Contains(T item)
- {
- for (int num = head; num < head + count; num++)
- {
- if (innerList[num % Capacity].Equals(item))
- {
- return true;
- }
- }
-
- // Not found
- return false;
- }
-
- /// <summary>
- /// Implementation of the ICollection.CopyTo function.
- /// </summary>
- /// <param name="array">Target array</param>
- /// <param name="arrayIndex">Start-Index in target array</param>
- public void CopyTo(T[] array, int arrayIndex)
- {
- if (array == null)
- {
- throw new ArgumentNullException("array");
- }
- if (arrayIndex < 0)
- {
- throw new ArgumentOutOfRangeException(
- "arrayIndex",
- "Must be at least zero: " + arrayIndex);
- }
- if (arrayIndex > count)
- {
- throw new Exception("arrayIndex=" + arrayIndex +
- " is out of range for target array (count=" + count +
- ")");
- }
- if (array.Length - arrayIndex < Count)
- {
- throw new ArgumentException("Array was to small!");
- }
- if (array.Rank > 1)
- {
- throw new ArgumentException("Array was multidimensional!");
- }
-
- for (int num = arrayIndex; num < array.Length; num++)
- {
- array[num] = innerList[(head + num) % innerList.Length];
- }
- }
-
- /// <summary>
- /// Remove. Do not call, this is not implemented!
- /// </summary>
- /// <param name="item">Item</param>
- /// <returns>
- /// True if removing the item succeeded, false otherwise.
- /// </returns>
- public bool Remove(T item)
- {
- throw new Exception("The method or operation is not implemented.");
- }
- #endregion
-
- #region IEnumerable Members
- /// <summary>
- /// System. collections. i enumerable. get enumerator
- /// </summary>
- /// <returns>System. collections. i enumerator</returns>
- IEnumerator
- IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
- #endregion
-
- #region IEnumerable<T> Members
- /// <summary>
- /// Standard implementation.
- /// </summary>
- /// <returns>A DequeueEnumerator on the current dequeue</returns>
- public IEnumerator<T> GetEnumerator()
- {
- for (int num = head; num < head + count; num++)
- {
- yield return innerList[num % innerList.Length];
- }
- }
- #endregion
-
- #region Equals (Public)
- /// <summary>
- /// Equals
- /// </summary>
- /// <param name="that">That</param>
- /// <returns>True if the other collection (that) is the same.</returns>
- public bool Equals(ICollection<T> that)
- {
- // Only compare if the reference is equal, we could also check
- // if the elements are equal, but who cares ...
- return this == that;
- }
- #endregion
-
- #region ContainsCount (Public)
- /// <summary>
- /// Contains count
- /// </summary>
- /// <param name="item">Item</param>
- /// <returns>Int</returns>
- public int ContainsCount(T item)
- {
- int contained = 0;
- for (int num = head; num < head + count; num++)
- {
- if (innerList[num % Capacity].Equals(item))
- {
- contained++;
- }
- }
- return contained;
- }
- #endregion
-
- #region ContainsAll (Public)
- /// <summary>
- /// Contains all
- /// </summary>
- /// <param name="items">Items to check</param>
- /// <returns>Returns true if all items are in this dequeue.</returns>
- public bool ContainsAll(IEnumerable<T> items)
- {
- foreach (T checkItem in items)
- {
- bool found = false;
- for (int num = head; num < head + count; num++)
- {
- if (innerList[num % Capacity].Equals(checkItem))
- {
- found = true;
- break;
- }
- }
- // Item not found, return false
- if (found == false)
- {
- return false;
- }
- }
- // All items passed, everything is in list
- return true;
- }
- #endregion
-
- #region Find (Public)
- /// <summary>
- /// Find. Do not call, this method is not implemented!
- /// </summary>
- /// <param name="item">Item</param>
- /// <returns>True if the item was found</returns>
- public bool Find(ref T item)
- {
- throw new Exception("The method or operation is not implemented.");
- }
- #endregion
-
- #region FindOrAdd (Public)
- /// <summary>
- /// Find or add. Do not call, this method is not implemented!
- /// </summary>
- /// <param name="item">Item</param>
- /// <returns>True if the item was found or could be added.</returns>
- public bool FindOrAdd(ref T item)
- {
- throw new Exception("The method or operation is not implemented.");
- }
- #endregion
-
- #region Update (Public)
- /// <summary>
- /// Update. Do not call, this method is not implemented!
- /// </summary>
- /// <param name="item">Item</param>
- /// <returns>True if the item was updated.</returns>
- public bool Update(T item)
- {
- throw new Exception("The method or operation is not implemented.");
- }
- #endregion
-
- #region UpdateOrAdd (Public)
- /// <summary>
- /// Update or add. Do not call, this method is not implemented!
- /// </summary>
- /// <param name="item">Item</param>
- /// <returns>True if the item was updated or added.</returns>
- public bool UpdateOrAdd(T item)
- {
- throw new Exception("The method or operation is not implemented.");
- }
- #endregion
-
- #region RemoveWithReturn (Public)
- /// <summary>
- /// Remove with return. Do not call, this method is not implemented!
- /// </summary>
- /// <param name="item">Item</param>
- /// <returns>True if the item was removed</returns>
- public bool RemoveWithReturn(ref T item)
- {
- throw new Exception("The method or operation is not implemented.");
- }
- #endregion
-
- #region RemoveAllCopies (Public)
- /// <summary>
- /// Remove all copies
- /// </summary>
- /// <param name="item">Item</param>
- public void RemoveAllCopies(T item)
- {
- throw new Exception("The method or operation is not implemented.");
- }
- #endregion
-
- #region RemoveAll (Public)
- /// <summary>
- /// Remove all
- /// </summary>
- /// <param name="items">Items</param>
- public void RemoveAll(IEnumerable<T> items)
- {
- throw new Exception("The method or operation is not implemented.");
- }
- #endregion
-
- #region RetainAll (Public)
- /// <summary>
- /// Retain all
- /// </summary>
- /// <param name="items">Items</param>
- public void RetainAll(IEnumerable<T> items)
- {
- throw new Exception("The method or operation is not implemented.");
- }
- #endregion
-
- #region AddAll (Public)
- /// <summary>
- /// Add all
- /// </summary>
- /// <param name="items">Items</param>
- public void AddAll(IEnumerable<T> items)
- {
- throw new Exception("The method or operation is not implemented.");
- }
-
- /// <summary>
- /// Add all
- /// </summary>
- /// <param name="items">Items</param>
- public void AddAll<U>(IEnumerable<U> items) where U : T
- {
- throw new Exception("The method or operation is not implemented.");
- }
- #endregion
-
- #region Check (Public)
- /// <summary>
- /// Check the queue. Do not call, this method is not implemented!
- /// </summary>
- /// <returns>True if the check succeeded, false otherwise.</returns>
- public bool Check()
- {
- throw new Exception("The method or operation is not implemented.");
- }
- #endregion
-
- #region ToArray (Public)
- /// <summary>
- /// To array
- /// </summary>
- /// <returns>Filled array with the same data as this dequeue</returns>
- public T[] ToArray()
- {
- T[] ret = new T[count];
- CopyTo(ret, 0);
- return ret;
- }
- #endregion
-
- #region EnqueueHead (Public)
- /// <summary>
- /// Add the given object to the collections head
- /// </summary>
- /// <param name="value">The object to enqueue</param>
- public void EnqueueHead(T value)
- {
- if (Count == Capacity)
- {
- SetSize((int)(Capacity * GrowthFactor));
- }
- head--;
- if (head < 0)
- {
- head += Capacity;
- }
- innerList[head] = value;
- count++;
- version++;
- }
- #endregion
-
- #region EnqueueTail (Public)
- /// <summary>
- /// Add the given object to the collections tail
- /// </summary>
- /// <param name="value">The object to enqueue</param>
- public void EnqueueTail(T value)
- {
- if (Count == Capacity)
- {
- SetSize((int)(Capacity * GrowthFactor));
- }
- tail++;
- tail %= Capacity;
- innerList[tail] = value;
- count++;
- version++;
- }
- #endregion
-
- #region DequeueHead (Public)
- /// <summary>
- /// Retrieve and remove the current head
- /// </summary>
- /// <returns>The removed object</returns>
- public T DequeueHead()
- {
- if (Count == 0)
- {
- throw new Exception("Dequeue was empty!");
- }
- T r = innerList[head];
- head++;
- head %= Capacity;
- count--;
- version++;
- return r;
- }
- #endregion
-
- #region DequeueTail (Public)
- /// <summary>
- /// Retrieve and remove the current tail
- /// </summary>
- /// <returns>The removed object</returns>
- public T DequeueTail()
- {
- if (Count == 0)
- {
- throw new Exception("Dequeue was empty!");
- }
- T r = innerList[tail];
- tail--;
- if (tail < 0)
- {
- tail += Capacity;
- }
- count--;
- version++;
- return r;
- }
- #endregion
-
- #region EnqueueTailRange (Public)
- /// <summary>
- /// Add the given collection to the dequeues tail
- /// </summary>
- /// <param name="collection">The source collection</param>
- public void EnqueueTailRange(ICollection<T> collection)
- {
- int cap = Capacity;
- while (cap < collection.Count)
- {
- cap = (int)(cap * GrowthFactor);
- }
- if (cap > Capacity)
- {
- SetSize(cap);
- }
-
- foreach (T obj in collection)
- {
- EnqueueTail(obj);
- }
- }
- #endregion
-
- #region EnqueueHeadRange (Public)
- /// <summary>
- /// Add the given collection to the dequeues head.
- /// To preserve the order in the collection, the entries are
- /// added in revers order.
- /// </summary>
- /// <param name="collection">The source collection</param>
- public void EnqueueHeadRange(ICollection<T> collection)
- {
- int cap = Capacity;
- while (cap < collection.Count)
- {
- cap = (int)(cap * GrowthFactor);
- }
- if (cap > Capacity)
- {
- SetSize(cap);
- }
-
- List<T> tempList = new List<T>(collection);
- tempList.Reverse();
- foreach (T obj in tempList)
- {
- EnqueueHead(obj);
- }
- }
- #endregion
-
- #region TrimToSize (Public)
- /// <summary>
- /// Sets the capacity to Count.
- /// </summary>
- public void TrimToSize()
- {
- SetSize(Count);
- }
- #endregion
-
- #region CopyTo (Public)
- /// <summary>
- /// Implementation of the ICollection.CopyTo function.
- /// </summary>
- /// <param name="array">Target array</param>
- /// <param name="index">Start-Index in target array</param>
- public void CopyTo(Array array, int index)
- {
- if (array == null)
- {
- throw new ArgumentNullException("array");
- }
- if (index < 0)
- {
- throw new ArgumentOutOfRangeException("index",
- "Must be at least zero: " + index);
- }
- if (array.Length - index < Count)
- {
- throw new ArgumentException("Array was to small!");
- }
- if (array.Rank > 1)
- {
- throw new ArgumentException("Array was multidimensional!");
- }
-
- for (int num = 0; num < Count; num++)
- {
- array.SetValue(this[num], num + index);
- }
- }
- #endregion
-
- #region Methods (Private)
-
- #region SetSize
- /// <summary>
- /// Sets the collections capacity to newSize
- /// </summary>
- /// <param name="newSize">the new collection size
- /// (must be >= Count)</param>
- protected void SetSize(int newSize)
- {
- if (newSize < Count)
- {
- throw new ArgumentException("New Size was smaller than Count!");
- }
-
- T[] newInnerList = new T[newSize];
- for (int num = 0; num < Count; num++)
- {
- newInnerList[num] = this[num];
- }
- head = 0;
- tail = Count;
- innerList = newInnerList;
- version++;
- }
- #endregion
-
- #endregion
- }
-
- /// <summary>
- /// Dequeue tests, needs to be an extra class because Dequeue is generic.
- /// </summary>
- internal class DequeueTests
- {
- #region TestDequeueGenericPerformance (Static)
- /// <summary>
- /// Test dequeue generic performance
- /// </summary>
- [Test, Category("LongRunning")]
- public static void TestDequeueGenericPerformance()
- {
- /*finish this when the Profiler in Delta.Utilities is re-enabled
- // Run 10 million loops
- const int NumOfElementsToAdd = 10000000;
-
- Profiler.BeginSection("Test linked lists", "Dequeue");
- Dequeue dequeue = new Dequeue();
- for (int num = 0; num < NumOfElementsToAdd; num++)
- {
- dequeue.EnqueueHead(num);
- if (num > 10)
- //Console.WriteLine(
- dequeue.DequeueTail();
- } // for (num)
-
- Profiler.Add("Dequeue with generics");
- Dequeue<int> dequeueGeneric = new Dequeue<int>();
- for (int num = 0; num < NumOfElementsToAdd; num++)
- {
- dequeueGeneric.EnqueueHead(num);
- if (num > 10)
- //Console.WriteLine(
- dequeueGeneric.DequeueTail();
- } // for (num)
- Profiler.EndSection();
-
- Console.WriteLine(Profiler.GetProfilerText());
-
- // Results for 10000000 (10 mio) elements to add:
- // Profiler (Total time: 1,48s)
- // Dequeue: 949,33ms (64,1%)
- // Dequeue with generics: 531,11ms (35,9%)
- */
- }
- #endregion
-
- #region TestEnqueueHead
- /// <summary>
- /// Test enqueue head
- /// </summary>
- [Test]
- public void TestEnqueueHead()
- {
- Dequeue<int> dequeue = new Dequeue<int>();
- dequeue.EnqueueHead(1);
- dequeue.EnqueueHead(2);
- dequeue.EnqueueHead(3);
- dequeue.EnqueueHead(5);
- Assert.Equal(5, dequeue.DequeueHead());
- Assert.Equal(3, dequeue.DequeueHead());
- Assert.Equal(1, dequeue.DequeueTail());
- Assert.Equal(1, dequeue.Count);
- }
- #endregion
-
- #region TestEnqueueTail
- /// <summary>
- /// Test enqueue tail
- /// </summary>
- [Test]
- public void TestEnqueueTail()
- {
- Dequeue<int> dequeue = new Dequeue<int>();
- dequeue.EnqueueTail(1);
- dequeue.EnqueueTail(2);
- dequeue.EnqueueTail(3);
- dequeue.EnqueueTail(5);
- Assert.Equal(5, dequeue.DequeueTail());
- Assert.Equal(3, dequeue.DequeueTail());
- Assert.Equal(1, dequeue.DequeueHead());
- Assert.Equal(1, dequeue.Count);
- }
- #endregion
- }
- }