diff --git a/Nuclex.Support (PC).csproj b/Nuclex.Support (PC).csproj
index 3949a0d..f5b56eb 100644
--- a/Nuclex.Support (PC).csproj
+++ b/Nuclex.Support (PC).csproj
@@ -65,6 +65,10 @@
+
+ false
+ UnintrusivePriorityQueue
+
false
Parentable
@@ -77,6 +81,11 @@
false
PriorityQueue
+
+ false
+ PriorityQueue.Test
+ PriorityQueue.cs
+
false
RingMemoryStream
@@ -87,6 +96,11 @@
RingMemoryStream.Test
RingMemoryStream.cs
+
+ false
+ UnintrusivePriorityQueue.Test
+ UnintrusivePriorityQueue.cs
+
false
BinarySerializer.Test
diff --git a/Source/Collections/ParentingCollection.cs b/Source/Collections/ParentingCollection.cs
index 9fe4e65..9d0cd1f 100644
--- a/Source/Collections/ParentingCollection.cs
+++ b/Source/Collections/ParentingCollection.cs
@@ -14,15 +14,10 @@ namespace Nuclex.Support.Collections {
///
/// Type of the parent object to assign to items
/// Type of the items being managed in the collection
- public class ParentingCollection : Collection, IDisposable
+ public class ParentingCollection : Collection
where ItemType : Parentable
where ParentType : class {
- /// Called when the object is garbage-collected
- ~ParentingCollection() {
- Dispose(false); // called from GC
- }
-
/// Reparents all elements in the collection
/// New parent to take ownership of the items
protected void Reparent(ParentType parent) {
@@ -32,37 +27,6 @@ namespace Nuclex.Support.Collections {
base[index].SetParent(parent);
}
- /// Called when the asset needs to release its resources
- ///
- /// Whether the mehod has been called from user code. If this argument
- /// is false, the object is being disposed by the garbage collector and
- /// it mustn't access other objects (including the attempt to Dispose() them)
- /// as these might have already been destroyed by the GC.
- ///
- protected virtual void Dispose(bool calledByUser) {
-
- // Only destroy the other resources when we're not being called from
- // the garbage collector, otherwise we'd risk accessing objects that
- // have already been disposed
- if(calledByUser) {
-
- // Have the items do their cleanup work
- Reparent(null);
-
- // Dispose of all the items in the collection
- foreach(ItemType item in this) {
- IDisposable disposable = item as IDisposable;
- if(disposable != null)
- disposable.Dispose();
- }
-
- // Remove all items from the collection
- base.ClearItems();
-
- }
-
- }
-
/// Clears all elements from the collection
protected override void ClearItems() {
for(int index = 0; index < Count; ++index)
@@ -94,9 +58,32 @@ namespace Nuclex.Support.Collections {
item.SetParent(this.parent);
}
- /// Release all resources owned by the instance explicitely
- public void Dispose() {
- Dispose(true); // Called by user
+ /// Disposes the collection and optionally all items contained therein
+ /// Whether to try calling Dispose() on all items
+ ///
+ /// This method is intended to support collections that need to dispose their
+ /// items. The ParentingCollection will first detach all items from the parent
+ /// object and them call Dispose() on any item that implements IDisposable.
+ ///
+ protected void InternalDispose(bool disposeItems) {
+
+ if(disposeItems) {
+
+ // Have the items do their cleanup work
+ Reparent(null);
+
+ // Dispose of all the items in the collection that implement IDisposable
+ foreach(ItemType item in this) {
+ IDisposable disposable = item as IDisposable;
+ if(disposable != null)
+ disposable.Dispose();
+ }
+
+ }
+
+ // Remove all items from the collection
+ base.ClearItems();
+
}
/// Parent this collection currently belongs to
diff --git a/Source/Collections/PriorityQueue.Test.cs b/Source/Collections/PriorityQueue.Test.cs
new file mode 100644
index 0000000..ccbb247
--- /dev/null
+++ b/Source/Collections/PriorityQueue.Test.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Collections.Generic;
+
+#if UNITTEST
+
+using NUnit.Framework;
+
+namespace Nuclex.Support.Collections {
+
+ /// Unit Test for the priority queue class
+ [TestFixture]
+ public class PriorityQueueTest {
+
+ private class FloatComparer : IComparer {
+
+ public int Compare(float left, float right) {
+ return Math.Sign(left - right);
+ }
+
+ public static readonly FloatComparer Default = new FloatComparer();
+
+ }
+
+ /// Tests to ensure the count property is properly updated
+ [Test]
+ public void TestCount() {
+ PriorityQueue testQueue = new PriorityQueue(FloatComparer.Default);
+
+ Assert.AreEqual(0, testQueue.Count);
+ testQueue.Enqueue(12.34f);
+ Assert.AreEqual(1, testQueue.Count);
+ testQueue.Enqueue(56.78f);
+ Assert.AreEqual(2, testQueue.Count);
+ testQueue.Dequeue();
+ Assert.AreEqual(1, testQueue.Count);
+ testQueue.Enqueue(9.0f);
+ Assert.AreEqual(2, testQueue.Count);
+ testQueue.Clear();
+ Assert.AreEqual(0, testQueue.Count);
+ }
+
+ /// Tests to ensure that the priority collection actually sorts items
+ [Test]
+ public void TestOrdering() {
+ PriorityQueue testQueue = new PriorityQueue(FloatComparer.Default);
+
+ testQueue.Enqueue(1.0f);
+ testQueue.Enqueue(9.0f);
+ testQueue.Enqueue(2.0f);
+ testQueue.Enqueue(8.0f);
+ testQueue.Enqueue(3.0f);
+ testQueue.Enqueue(7.0f);
+ testQueue.Enqueue(4.0f);
+ testQueue.Enqueue(6.0f);
+ testQueue.Enqueue(5.0f);
+
+ Assert.AreEqual(9.0f, testQueue.Dequeue());
+ Assert.AreEqual(8.0f, testQueue.Dequeue());
+ Assert.AreEqual(7.0f, testQueue.Dequeue());
+ Assert.AreEqual(6.0f, testQueue.Dequeue());
+ Assert.AreEqual(5.0f, testQueue.Dequeue());
+ Assert.AreEqual(4.0f, testQueue.Dequeue());
+ Assert.AreEqual(3.0f, testQueue.Dequeue());
+ Assert.AreEqual(2.0f, testQueue.Dequeue());
+ Assert.AreEqual(1.0f, testQueue.Dequeue());
+ }
+
+ }
+
+} // namespace Nuclex.Support.Collections
+
+#endif // UNITTEST
diff --git a/Source/Collections/PriorityQueue.cs b/Source/Collections/PriorityQueue.cs
index f61d845..fade547 100644
--- a/Source/Collections/PriorityQueue.cs
+++ b/Source/Collections/PriorityQueue.cs
@@ -3,391 +3,224 @@ using System.Collections.Generic;
using System.Collections;
namespace Nuclex.Support.Collections {
- /*
- public class PriorityQueue : ICollection {
- private struct HeapEntry {
+ /// Queue that dequeues items in order of their priority
+ public class PriorityQueue : ICollection, IEnumerable {
- public HeapEntry(object item, int priority) {
- this.item = item;
- this.priority = priority;
- }
- public object Item {
- get { return item; }
- }
- public int Priority {
- get { return priority; }
+ #region class Enumerator
+
+ /// Enumerates all items contained in a priority queue
+ private class Enumerator : IEnumerator {
+
+ /// Initializes a new priority queue enumerator
+ /// Priority queue to be enumerated
+ public Enumerator(PriorityQueue priorityQueue) {
+ this.priorityQueue = priorityQueue;
+ Reset();
}
- private object item;
- private int priority;
+ /// Resets the enumerator to its initial state
+ public void Reset() {
+ index = -1;
+ version = priorityQueue.version;
+ }
+
+ /// The current item being enumerated
+ ItemType IEnumerator.Current {
+ get {
+ checkVersion();
+ return priorityQueue.heap[index];
+ }
+ }
+
+ /// Moves to the next item in the priority queue
+ /// True if a next item was found, false if the end has been reached
+ public bool MoveNext() {
+ checkVersion();
+
+ if(index + 1 == priorityQueue.count)
+ return false;
+
+ ++index;
+
+ return true;
+ }
+
+ /// Releases all resources used by the enumerator
+ public void Dispose() { }
+
+ /// Ensures that the priority queue has not changed
+ private void checkVersion() {
+ if(version != priorityQueue.version)
+ throw new InvalidOperationException("Priority queue has been modified");
+ }
+
+ /// The current item being enumerated
+ object IEnumerator.Current {
+ get {
+ checkVersion();
+ return priorityQueue.heap[index];
+ }
+ }
+
+ /// Index of the current item in the priority queue
+ private int index;
+ /// The priority queue whose items this instance enumerates
+ private PriorityQueue priorityQueue;
+ /// Expected version of the priority queue
+ private int version;
}
- private int count;
- private int capacity;
- private int version;
- private HeapEntry[] heap;
+ #endregion // class Enumerator
- public PriorityQueue() {
+ /// Initializes a new priority queue
+ /// Comparer to use for ordering the items
+ public PriorityQueue(IComparer comparer) {
+ this.comparer = comparer;
capacity = 15; // 15 is equal to 4 complete levels
- heap = new HeapEntry[capacity];
+ heap = new ItemType[capacity];
}
- public object Dequeue() {
+ /// Takes the item with the highest priority off from the queue
+ /// The item with the highest priority in the list
+ public ItemType Dequeue() {
if(count == 0)
- throw new InvalidOperationException();
+ throw new InvalidOperationException("No items available to dequeue");
- object result = heap[0].Item;
- count--;
+ ItemType result = heap[0];
+ --count;
trickleDown(0, heap[count]);
- version++;
+
+ ++version;
+
return result;
}
- public void Enqueue(object item, int priority) {
+ /// Puts an item into the priority queue
+ /// Item to be queued
+ public void Enqueue(ItemType item) {
if(count == capacity)
growHeap();
- count++;
- bubbleUp(count - 1, new HeapEntry(item, priority));
- version++;
+
+ ++count;
+ bubbleUp(count - 1, item);
+ ++version;
}
- private void bubbleUp(int index, HeapEntry he) {
- int parent = getParent(index);
- // note: (index > 0) means there is a parent
- while((index > 0) && (heap[parent].Priority < he.Priority)) {
- heap[index] = heap[parent];
- index = parent;
- parent = getParent(index);
- }
- heap[index] = he;
+ /// Removes all items from the priority queue
+ public void Clear() {
+ this.count = 0;
+ ++version;
}
- private int getLeftChild(int index) {
- return (index * 2) + 1;
- }
- private int getParent(int index) {
- return (index - 1) / 2;
- }
-
- private void growHeap() {
- capacity = (capacity * 2) + 1;
- HeapEntry[] newHeap = new HeapEntry[capacity];
- System.Array.Copy(heap, 0, newHeap, 0, count);
- heap = newHeap;
- }
-
- private void trickleDown(int index, HeapEntry he) {
- int child = getLeftChild(index);
- while(child < count) {
- if(((child + 1) < count) &&
- (heap[child].Priority < heap[child + 1].Priority)) {
- child++;
- }
- heap[index] = heap[child];
- index = child;
- child = getLeftChild(index);
- }
- bubbleUp(index, he);
- }
-
- #region IEnumerable implementation
- public IEnumerator GetEnumerator() {
- return new PriorityQueueEnumerator(this);
- }
- #endregion
-
- #region ICollection implementation
+ /// Total number of items in the priority queue
public int Count {
- get { return count; }
+ get { return this.count; }
}
+ /// Copies the contents of the priority queue into an array
+ /// Array to copy the priority queue into
+ /// Starting index for the destination array
public void CopyTo(Array array, int index) {
- System.Array.Copy(heap, 0, array, index, count);
+ Array.Copy(heap, 0, array, index, count);
}
+ ///
+ /// Obtains an object that can be used to synchronize accesses to the priority queue
+ /// from different threads
+ ///
public object SyncRoot {
get { return this; }
}
+ /// Whether operations performed on this priority queue are thread safe
public bool IsSynchronized {
get { return false; }
}
- #endregion
- #region Priority Queue enumerator
- private class PriorityQueueEnumerator : IEnumerator {
- private int index;
- private PriorityQueue pq;
- private int version;
-
- public PriorityQueueEnumerator(PriorityQueue pq) {
- this.pq = pq;
- Reset();
- }
-
- private void checkVersion() {
- if(version != pq.version)
- throw new InvalidOperationException();
- }
-
- #region IEnumerator Members
-
- public void Reset() {
- index = -1;
- version = pq.version;
- }
-
- public object Current {
- get {
- checkVersion();
- return pq.heap[index].Item;
- }
- }
-
- public bool MoveNext() {
- checkVersion();
- if(index + 1 == pq.count)
- return false;
- index++;
- return true;
- }
-
- #endregion
+ /// Returns a typesafe enumerator for the priority queue
+ /// A new enumerator for the priority queue
+ public IEnumerator GetEnumerator() {
+ return new Enumerator(this);
}
- #endregion
+
+ /// Moves an item upwards in the heap tree
+ /// Index of the item to be moved
+ /// Item to be moved
+ private void bubbleUp(int index, ItemType item) {
+ int parent = getParent(index);
+
+ // note: (index > 0) means there is a parent
+ while((index > 0) && (this.comparer.Compare(heap[parent], item) < 0)) {
+ heap[index] = heap[parent];
+ index = parent;
+ parent = getParent(index);
+ }
+
+ heap[index] = item;
+ }
+
+ /// Moved the item downwards in the heap tree
+ /// Index of the item to be moved
+ /// Item to be moved
+ private void trickleDown(int index, ItemType item) {
+ int child = getLeftChild(index);
+
+ while(child < count) {
+
+ if(((child + 1) < count) && (this.comparer.Compare(heap[child], heap[child + 1]) < 0))
+ ++child;
+
+ heap[index] = heap[child];
+ index = child;
+ child = getLeftChild(index);
+ }
+
+ bubbleUp(index, item);
+ }
+
+ /// Obtains the left child item in the heap tree
+ /// Index of the item whose left child to return
+ /// The left child item of the provided parent item
+ private int getLeftChild(int index) {
+ return (index * 2) + 1;
+ }
+
+ /// Calculates the parent entry of the item on the heap
+ /// Index of the item whose parent to calculate
+ /// The index of the parent to the specified item
+ private int getParent(int index) {
+ return (index - 1) / 2;
+ }
+
+ /// Increases the size of the priority collection's heap
+ private void growHeap() {
+ capacity = (capacity * 2) + 1;
+
+ ItemType[] newHeap = new ItemType[capacity];
+ Array.Copy(heap, 0, newHeap, 0, count);
+ heap = newHeap;
+ }
+
+ /// Returns an enumerator for the priority queue
+ /// A new enumerator for the priority queue
+ IEnumerator IEnumerable.GetEnumerator() {
+ return new Enumerator(this);
+ }
+
+ /// Comparer used to order the items in the priority queue
+ private IComparer comparer;
+ /// Total number of items in the priority queue
+ private int count;
+ /// Available space in the priority queue
+ private int capacity;
+ /// Incremented whenever the priority queue is modified
+ private int version;
+ /// Tree containing the items in the priority queue
+ private ItemType[] heap;
}
- */
- /*
- /// Queue that dequeues items in order of their priority
- public class PriorityQueue : ICollection, IEnumerable {
- public static PriorityQueue Syncronized(PriorityQueue P) {
- return new PriorityQueue(ArrayList.Synchronized(P.InnerList), P.Comparer, false);
- }
- public static PriorityQueue ReadOnly(PriorityQueue P) {
- return new PriorityQueue(ArrayList.ReadOnly(P.InnerList), P.Comparer, false);
- }
-
- public PriorityQueue()
- : this(Comparer.Default) { }
-
- public PriorityQueue(int C)
- : this(Comparer.Default, C) { }
-
- public PriorityQueue(IComparer c) {
- Comparer = c;
- }
-
- public PriorityQueue(IComparer c, int Capacity) {
- Comparer = c;
- InnerList.Capacity = Capacity;
- }
-
- protected PriorityQueue(ArrayList Core, IComparer Comp, bool Copy) {
- if(Copy)
- InnerList = Core.Clone() as ArrayList;
- else
- InnerList = Core;
- Comparer = Comp;
- }
-
- protected void SwitchElements(int i, int j) {
- object h = InnerList[i];
- InnerList[i] = InnerList[j];
- InnerList[j] = h;
- }
-
- protected virtual int OnCompare(int i, int j) {
- return Comparer.Compare(InnerList[i], InnerList[j]);
- }
-
- #region public methods
- ///
- /// Push an object onto the PQ
- ///
- /// The new object
- ///
- /// The index in the list where the object is _now_. This will change when
- /// objects are taken from or put onto the PQ.
- ///
- public int Queue(object O) {
- int p = InnerList.Count, p2;
- InnerList.Add(O); // E[p] = O
- do {
- if(p == 0)
- break;
- p2 = (p - 1) / 2;
- if(OnCompare(p, p2) < 0) {
- SwitchElements(p, p2);
- p = p2;
- } else
- break;
- } while(true);
- return p;
- }
-
- ///
- /// Get the smallest object and remove it.
- ///
- /// The smallest object
- public object Dequeue() {
- object result = InnerList[0];
- int p = 0, p1, p2, pn;
- InnerList[0] = InnerList[InnerList.Count - 1];
- InnerList.RemoveAt(InnerList.Count - 1);
- do {
- pn = p;
- p1 = 2 * p + 1;
- p2 = 2 * p + 2;
- if(InnerList.Count > p1 && OnCompare(p, p1) > 0) // links kleiner
- p = p1;
- if(InnerList.Count > p2 && OnCompare(p, p2) > 0) // rechts noch kleiner
- p = p2;
-
- if(p == pn)
- break;
- SwitchElements(p, pn);
- } while(true);
- return result;
- }
-
- ///
- /// Notify the PQ that the object at position i has changed
- /// and the PQ needs to restore order.
- /// Since you dont have access to any indexes (except by using the
- /// explicit IList.this) you should not call this function without knowing exactly
- /// what you do.
- ///
- /// The index of the changed object.
- public void Update(int i) {
- int p = i, pn;
- int p1, p2;
- do // aufsteigen
- {
- if(p == 0)
- break;
- p2 = (p - 1) / 2;
- if(OnCompare(p, p2) < 0) {
- SwitchElements(p, p2);
- p = p2;
- } else
- break;
- } while(true);
- if(p < i)
- return;
- do // absteigen
- {
- pn = p;
- p1 = 2 * p + 1;
- p2 = 2 * p + 2;
- if(InnerList.Count > p1 && OnCompare(p, p1) > 0) // links kleiner
- p = p1;
- if(InnerList.Count > p2 && OnCompare(p, p2) > 0) // rechts noch kleiner
- p = p2;
-
- if(p == pn)
- break;
- SwitchElements(p, pn);
- } while(true);
- }
-
- ///
- /// Get the smallest object without removing it.
- ///
- /// The smallest object
- public object Peek() {
- if(InnerList.Count > 0)
- return InnerList[0];
- return null;
- }
-
- public bool Contains(object value) {
- return InnerList.Contains(value);
- }
-
- public void Clear() {
- InnerList.Clear();
- }
-
- public int Count {
- get {
- return InnerList.Count;
- }
- }
- IEnumerator IEnumerable.GetEnumerator() {
- return InnerList.GetEnumerator();
- }
-
- public void CopyTo(Array array, int index) {
- InnerList.CopyTo(array, index);
- }
-
- public object Clone() {
- return new PriorityQueue(InnerList, Comparer, true);
- }
-
- public bool IsSynchronized {
- get {
- return InnerList.IsSynchronized;
- }
- }
-
- public object SyncRoot {
- get {
- return this;
- }
- }
- #endregion
- #region explicit implementation
- bool IList.IsReadOnly {
- get {
- return false;
- }
- }
-
- object IList.this[int index] {
- get {
- return InnerList[index];
- }
- set {
- InnerList[index] = value;
- Update(index);
- }
- }
-
- int IList.Add(object o) {
- return Queue(o);
- }
-
- void IList.RemoveAt(int index) {
- throw new NotSupportedException();
- }
-
- void IList.Insert(int index, object value) {
- throw new NotSupportedException();
- }
-
- void IList.Remove(object value) {
- throw new NotSupportedException();
- }
-
- int IList.IndexOf(object value) {
- throw new NotSupportedException();
- }
-
- bool IList.IsFixedSize {
- get {
- return false;
- }
- }
- #endregion
-
- protected ArrayList InnerList = new ArrayList();
- protected IComparer Comparer;
- }
- */
} // namespace Nuclex.Support.Collections
diff --git a/Source/Collections/UnintrusivePriorityQueue.Test.cs b/Source/Collections/UnintrusivePriorityQueue.Test.cs
new file mode 100644
index 0000000..0d2b732
--- /dev/null
+++ b/Source/Collections/UnintrusivePriorityQueue.Test.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+
+#if UNITTEST
+
+using NUnit.Framework;
+
+namespace Nuclex.Support.Collections {
+
+ /// Unit Test for the priority queue class
+ [TestFixture]
+ public class UnintrusivePriorityQueueTest {
+
+ /// Tests to ensure the count property is properly updated
+ [Test]
+ public void TestCount() {
+ UnintrusivePriorityQueue testQueue =
+ new UnintrusivePriorityQueue();
+
+ Assert.AreEqual(0, testQueue.Count);
+ testQueue.Enqueue("a", 12.34f);
+ Assert.AreEqual(1, testQueue.Count);
+ testQueue.Enqueue("b", 56.78f);
+ Assert.AreEqual(2, testQueue.Count);
+ testQueue.Dequeue();
+ Assert.AreEqual(1, testQueue.Count);
+ testQueue.Enqueue("c", 9.0f);
+ Assert.AreEqual(2, testQueue.Count);
+ testQueue.Clear();
+ Assert.AreEqual(0, testQueue.Count);
+ }
+
+ /// Tests to ensure that the priority collection actually sorts items
+ [Test]
+ public void TestOrdering() {
+ UnintrusivePriorityQueue testQueue =
+ new UnintrusivePriorityQueue();
+
+ testQueue.Enqueue("a", 1.0f);
+ testQueue.Enqueue("i", 9.0f);
+ testQueue.Enqueue("b", 2.0f);
+ testQueue.Enqueue("h", 8.0f);
+ testQueue.Enqueue("c", 3.0f);
+ testQueue.Enqueue("g", 7.0f);
+ testQueue.Enqueue("d", 4.0f);
+ testQueue.Enqueue("f", 6.0f);
+ testQueue.Enqueue("e", 5.0f);
+
+ Assert.AreEqual("i", testQueue.Dequeue());
+ Assert.AreEqual("h", testQueue.Dequeue());
+ Assert.AreEqual("g", testQueue.Dequeue());
+ Assert.AreEqual("f", testQueue.Dequeue());
+ Assert.AreEqual("e", testQueue.Dequeue());
+ Assert.AreEqual("d", testQueue.Dequeue());
+ Assert.AreEqual("c", testQueue.Dequeue());
+ Assert.AreEqual("b", testQueue.Dequeue());
+ Assert.AreEqual("a", testQueue.Dequeue());
+ }
+
+ }
+
+} // namespace Nuclex.Support.Collections
+
+#endif // UNITTEST
diff --git a/Source/Collections/UnintrusivePriorityQueue.cs b/Source/Collections/UnintrusivePriorityQueue.cs
new file mode 100644
index 0000000..e17ba0f
--- /dev/null
+++ b/Source/Collections/UnintrusivePriorityQueue.cs
@@ -0,0 +1,169 @@
+using System;
+using System.Collections.Generic;
+using System.Collections;
+
+namespace Nuclex.Support.Collections {
+
+ /// Queue that dequeues items in order of their priority
+ public class UnintrusivePriorityQueue
+ : ICollection, IEnumerable where PriorityType : IComparable {
+
+ #region struct Entry
+
+ /// An entry in the priority queue
+ private struct Entry {
+
+ /// Initializes a new priority queue entry
+ /// Item to be stored in the entry
+ /// Priority of the item in the entry
+ public Entry(ItemType item, PriorityType priority) {
+ this.Item = item;
+ this.Priority = priority;
+ }
+
+ /// Item contained in this priority queue entry
+ public ItemType Item;
+ /// Priority assigned to this entry
+ public PriorityType Priority;
+
+ }
+
+ #endregion // struct Entry
+
+ #region class EntryComparer
+
+ /// Compares two priority queue entries based on their priority
+ private class EntryComparer : IComparer {
+
+ /// Compares the left entry to the right entry
+ /// Entry on the left side
+ /// Entry on the right side
+ /// The relationship of the two entries
+ public int Compare(Entry left, Entry right) {
+ return left.Priority.CompareTo(right.Priority);
+ }
+
+ /// Default instance for this comparer
+ public static readonly EntryComparer Instance = new EntryComparer();
+
+ }
+
+ #endregion // class EntryComparer
+
+ #region class UnwrappingEnumerator
+
+ /// Enumerates all items contained in a priority queue
+ private class UnwrappingEnumerator : IEnumerator {
+
+ /// Initializes a new priority queue enumerator
+ /// Enumerator of entries to unwrap
+ public UnwrappingEnumerator(IEnumerator entryEnumerator) {
+ this.entryEnumerator = entryEnumerator;
+ }
+
+ /// Resets the enumerator to its initial state
+ public void Reset() {
+ this.entryEnumerator.Reset();
+ }
+
+ /// The current item being enumerated
+ ItemType IEnumerator.Current {
+ get { return this.entryEnumerator.Current.Item; }
+ }
+
+ /// Releases all resources used by the enumerator
+ public void Dispose() {
+ this.entryEnumerator.Dispose();
+ }
+
+ /// Moves to the next item in the priority queue
+ /// True if a next item was found, false if the end has been reached
+ public bool MoveNext() {
+ return this.entryEnumerator.MoveNext();
+ }
+
+ /// The current item being enumerated
+ object IEnumerator.Current {
+ get { return this.entryEnumerator.Current.Item; }
+ }
+
+ /// Enumerator for entries to be unwrapped by this enumerator
+ private IEnumerator entryEnumerator;
+
+ }
+
+ #endregion // class Enumerator
+
+ /// Initializes a new non-intrusive priority queue
+ public UnintrusivePriorityQueue() {
+ this.intrusiveQueue = new PriorityQueue(EntryComparer.Instance);
+ }
+
+ /// Takes the item with the highest priority off from the queue
+ /// The item with the highest priority in the list
+ public ItemType Dequeue() {
+ return this.intrusiveQueue.Dequeue().Item;
+ }
+
+ /// Puts an item into the priority queue
+ /// Item to be queued
+ /// Priority of the item to be queued
+ public void Enqueue(ItemType item, PriorityType priority) {
+ this.intrusiveQueue.Enqueue(new Entry(item, priority));
+ }
+
+ /// Removes all items from the priority queue
+ public void Clear() {
+ this.intrusiveQueue.Clear();
+ }
+
+ /// Total number of items in the priority queue
+ public int Count {
+ get { return this.intrusiveQueue.Count; }
+ }
+
+ /// Copies the contents of the priority queue into an array
+ /// Array to copy the priority queue into
+ /// Starting index for the destination array
+ public void CopyTo(Array array, int index) {
+
+ Entry[] entries = new Entry[this.intrusiveQueue.Count];
+
+ this.intrusiveQueue.CopyTo(array, 0);
+
+ for(int entryIndex = 0; entryIndex < this.intrusiveQueue.Count; ++entryIndex)
+ array.SetValue(entries[entryIndex], entryIndex + index);
+
+ }
+
+ ///
+ /// Obtains an object that can be used to synchronize accesses to the priority queue
+ /// from different threads
+ ///
+ public object SyncRoot {
+ get { return this.intrusiveQueue.SyncRoot; }
+ }
+
+ /// Whether operations performed on this priority queue are thread safe
+ public bool IsSynchronized {
+ get { return this.intrusiveQueue.IsSynchronized; }
+ }
+
+ /// Returns a typesafe enumerator for the priority queue
+ /// A new enumerator for the priority queue
+ public IEnumerator GetEnumerator() {
+ return new UnwrappingEnumerator(this.intrusiveQueue.GetEnumerator());
+ }
+
+ /// Returns an enumerator for the priority queue
+ /// A new enumerator for the priority queue
+ IEnumerator IEnumerable.GetEnumerator() {
+ return new UnwrappingEnumerator(this.intrusiveQueue.GetEnumerator());
+ }
+
+ /// Intrusive priority queue being wrapped by this class
+ private PriorityQueue intrusiveQueue;
+
+ }
+
+} // namespace Nuclex.Support.Collections