Renamed UnintrusivePriorityQueue to PairPriorityQueue; Switched PairPriorityQueue to work on PriorityItemPairs instead of eating up the priority value once the item was added; PriorityQueue and PairPriorityQueue now both work on the default comparer or use a custom comparer specified in the constructor
git-svn-id: file:///srv/devel/repo-conversion/nusu@45 d2e56fa2-650e-0410-a79f-9358c0239efd
This commit is contained in:
parent
4b0d3d26cc
commit
c230f0ce7c
|
@ -78,6 +78,10 @@
|
||||||
<Name>ObservableCollection.Test</Name>
|
<Name>ObservableCollection.Test</Name>
|
||||||
<DependentUpon>ObservableCollection.cs</DependentUpon>
|
<DependentUpon>ObservableCollection.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Source\Collections\PriorityItemPair.cs">
|
||||||
|
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
||||||
|
<Name>PriorityItemPair</Name>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Source\Collections\TransformingReadOnlyCollection.cs">
|
<Compile Include="Source\Collections\TransformingReadOnlyCollection.cs">
|
||||||
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
||||||
<Name>TransformingReadOnlyCollection</Name>
|
<Name>TransformingReadOnlyCollection</Name>
|
||||||
|
@ -87,9 +91,9 @@
|
||||||
<Name>TransformingReadOnlyCollection.Interfaces</Name>
|
<Name>TransformingReadOnlyCollection.Interfaces</Name>
|
||||||
<DependentUpon>TransformingReadOnlyCollection.cs</DependentUpon>
|
<DependentUpon>TransformingReadOnlyCollection.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Source\Collections\UnintrusivePriorityQueue.cs">
|
<Compile Include="Source\Collections\PairPriorityQueue.cs">
|
||||||
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
||||||
<Name>UnintrusivePriorityQueue</Name>
|
<Name>PairPriorityQueue</Name>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Source\Collections\Parentable.cs">
|
<Compile Include="Source\Collections\Parentable.cs">
|
||||||
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
||||||
|
@ -121,10 +125,10 @@
|
||||||
<Name>RingMemoryStream.Test</Name>
|
<Name>RingMemoryStream.Test</Name>
|
||||||
<DependentUpon>RingMemoryStream.cs</DependentUpon>
|
<DependentUpon>RingMemoryStream.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Source\Collections\UnintrusivePriorityQueue.Test.cs">
|
<Compile Include="Source\Collections\PairPriorityQueue.Test.cs">
|
||||||
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
||||||
<Name>UnintrusivePriorityQueue.Test</Name>
|
<Name>PairPriorityQueue.Test</Name>
|
||||||
<DependentUpon>UnintrusivePriorityQueue.cs</DependentUpon>
|
<DependentUpon>PairPriorityQueue.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Source\Licensing\LicenseKey.cs">
|
<Compile Include="Source\Licensing\LicenseKey.cs">
|
||||||
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
||||||
|
|
|
@ -29,22 +29,22 @@ namespace Nuclex.Support.Collections {
|
||||||
|
|
||||||
/// <summary>Unit Test for the priority queue class</summary>
|
/// <summary>Unit Test for the priority queue class</summary>
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class UnintrusivePriorityQueueTest {
|
public class PairPriorityQueueTest {
|
||||||
|
|
||||||
/// <summary>Tests to ensure the count property is properly updated</summary>
|
/// <summary>Tests to ensure the count property is properly updated</summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void TestCount() {
|
public void TestCount() {
|
||||||
UnintrusivePriorityQueue<string, float> testQueue =
|
PairPriorityQueue<float, string> testQueue =
|
||||||
new UnintrusivePriorityQueue<string, float>();
|
new PairPriorityQueue<float, string>();
|
||||||
|
|
||||||
Assert.AreEqual(0, testQueue.Count);
|
Assert.AreEqual(0, testQueue.Count);
|
||||||
testQueue.Enqueue("a", 12.34f);
|
testQueue.Enqueue(12.34f, "a");
|
||||||
Assert.AreEqual(1, testQueue.Count);
|
Assert.AreEqual(1, testQueue.Count);
|
||||||
testQueue.Enqueue("b", 56.78f);
|
testQueue.Enqueue(56.78f, "b");
|
||||||
Assert.AreEqual(2, testQueue.Count);
|
Assert.AreEqual(2, testQueue.Count);
|
||||||
testQueue.Dequeue();
|
testQueue.Dequeue();
|
||||||
Assert.AreEqual(1, testQueue.Count);
|
Assert.AreEqual(1, testQueue.Count);
|
||||||
testQueue.Enqueue("c", 9.0f);
|
testQueue.Enqueue(9.0f, "c");
|
||||||
Assert.AreEqual(2, testQueue.Count);
|
Assert.AreEqual(2, testQueue.Count);
|
||||||
testQueue.Clear();
|
testQueue.Clear();
|
||||||
Assert.AreEqual(0, testQueue.Count);
|
Assert.AreEqual(0, testQueue.Count);
|
||||||
|
@ -53,28 +53,28 @@ namespace Nuclex.Support.Collections {
|
||||||
/// <summary>Tests to ensure that the priority collection actually sorts items</summary>
|
/// <summary>Tests to ensure that the priority collection actually sorts items</summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void TestOrdering() {
|
public void TestOrdering() {
|
||||||
UnintrusivePriorityQueue<string, float> testQueue =
|
PairPriorityQueue<float, string> testQueue =
|
||||||
new UnintrusivePriorityQueue<string, float>();
|
new PairPriorityQueue<float, string>();
|
||||||
|
|
||||||
testQueue.Enqueue("a", 1.0f);
|
testQueue.Enqueue(1.0f, "a");
|
||||||
testQueue.Enqueue("i", 9.0f);
|
testQueue.Enqueue(9.0f, "i");
|
||||||
testQueue.Enqueue("b", 2.0f);
|
testQueue.Enqueue(2.0f, "b");
|
||||||
testQueue.Enqueue("h", 8.0f);
|
testQueue.Enqueue(8.0f, "h");
|
||||||
testQueue.Enqueue("c", 3.0f);
|
testQueue.Enqueue(3.0f, "c");
|
||||||
testQueue.Enqueue("g", 7.0f);
|
testQueue.Enqueue(7.0f, "g");
|
||||||
testQueue.Enqueue("d", 4.0f);
|
testQueue.Enqueue(4.0f, "d");
|
||||||
testQueue.Enqueue("f", 6.0f);
|
testQueue.Enqueue(6.0f, "f");
|
||||||
testQueue.Enqueue("e", 5.0f);
|
testQueue.Enqueue(5.0f, "e");
|
||||||
|
|
||||||
Assert.AreEqual("i", testQueue.Dequeue());
|
Assert.AreEqual("i", testQueue.Dequeue().Item);
|
||||||
Assert.AreEqual("h", testQueue.Dequeue());
|
Assert.AreEqual("h", testQueue.Dequeue().Item);
|
||||||
Assert.AreEqual("g", testQueue.Dequeue());
|
Assert.AreEqual("g", testQueue.Dequeue().Item);
|
||||||
Assert.AreEqual("f", testQueue.Dequeue());
|
Assert.AreEqual("f", testQueue.Dequeue().Item);
|
||||||
Assert.AreEqual("e", testQueue.Dequeue());
|
Assert.AreEqual("e", testQueue.Dequeue().Item);
|
||||||
Assert.AreEqual("d", testQueue.Dequeue());
|
Assert.AreEqual("d", testQueue.Dequeue().Item);
|
||||||
Assert.AreEqual("c", testQueue.Dequeue());
|
Assert.AreEqual("c", testQueue.Dequeue().Item);
|
||||||
Assert.AreEqual("b", testQueue.Dequeue());
|
Assert.AreEqual("b", testQueue.Dequeue().Item);
|
||||||
Assert.AreEqual("a", testQueue.Dequeue());
|
Assert.AreEqual("a", testQueue.Dequeue().Item);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
138
Source/Collections/PairPriorityQueue.cs
Normal file
138
Source/Collections/PairPriorityQueue.cs
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
#region CPL License
|
||||||
|
/*
|
||||||
|
Nuclex Framework
|
||||||
|
Copyright (C) 2002-2007 Nuclex Development Labs
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the IBM Common Public License as
|
||||||
|
published by the IBM Corporation; either version 1.0 of the
|
||||||
|
License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
IBM Common Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the IBM Common Public
|
||||||
|
License along with this library
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections;
|
||||||
|
|
||||||
|
namespace Nuclex.Support.Collections {
|
||||||
|
|
||||||
|
/// <summary>Queue that dequeues items in order of their priority</summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This variant of the priority queue uses an external priority value. If the
|
||||||
|
/// priority data type implements the IComparable interface, the user does not
|
||||||
|
/// even
|
||||||
|
/// </remarks>
|
||||||
|
public class PairPriorityQueue<PriorityType, ItemType>
|
||||||
|
: ICollection, IEnumerable<PriorityItemPair<PriorityType, ItemType>> {
|
||||||
|
|
||||||
|
#region class PairComparer
|
||||||
|
|
||||||
|
/// <summary>Compares two priority queue entries based on their priority</summary>
|
||||||
|
private class PairComparer : IComparer<PriorityItemPair<PriorityType, ItemType>> {
|
||||||
|
|
||||||
|
/// <summary>Initializes a new entry comparer</summary>
|
||||||
|
/// <param name="priorityComparer">Comparer used to compare entry priorities</param>
|
||||||
|
public PairComparer(IComparer<PriorityType> priorityComparer) {
|
||||||
|
this.priorityComparer = priorityComparer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Compares the left entry to the right entry</summary>
|
||||||
|
/// <param name="left">Entry on the left side</param>
|
||||||
|
/// <param name="right">Entry on the right side</param>
|
||||||
|
/// <returns>The relationship of the two entries</returns>
|
||||||
|
public int Compare(
|
||||||
|
PriorityItemPair<PriorityType, ItemType> left,
|
||||||
|
PriorityItemPair<PriorityType, ItemType> right
|
||||||
|
) {
|
||||||
|
return this.priorityComparer.Compare(left.Priority, right.Priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Comparer used to compare the priorities of the entries</summary>
|
||||||
|
private IComparer<PriorityType> priorityComparer;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion // class EntryComparer
|
||||||
|
|
||||||
|
/// <summary>Initializes a new non-intrusive priority queue</summary>
|
||||||
|
public PairPriorityQueue() : this(Comparer<PriorityType>.Default) { }
|
||||||
|
|
||||||
|
/// <summary>Initializes a new non-intrusive priority queue</summary>
|
||||||
|
/// <param name="priorityComparer">Comparer used to compare the item priorities</param>
|
||||||
|
public PairPriorityQueue(IComparer<PriorityType> priorityComparer) {
|
||||||
|
this.internalQueue = new PriorityQueue<PriorityItemPair<PriorityType, ItemType>>(
|
||||||
|
new PairComparer(priorityComparer)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Takes the item with the highest priority off from the queue</summary>
|
||||||
|
/// <returns>The item with the highest priority in the list</returns>
|
||||||
|
public PriorityItemPair<PriorityType, ItemType> Dequeue() {
|
||||||
|
return this.internalQueue.Dequeue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Puts an item into the priority queue</summary>
|
||||||
|
/// <param name="priority">Priority of the item to be queued</param>
|
||||||
|
/// <param name="item">Item to be queued</param>
|
||||||
|
public void Enqueue(PriorityType priority, ItemType item) {
|
||||||
|
this.internalQueue.Enqueue(
|
||||||
|
new PriorityItemPair<PriorityType, ItemType>(priority, item)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Removes all items from the priority queue</summary>
|
||||||
|
public void Clear() {
|
||||||
|
this.internalQueue.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Total number of items in the priority queue</summary>
|
||||||
|
public int Count {
|
||||||
|
get { return this.internalQueue.Count; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Copies the contents of the priority queue into an array</summary>
|
||||||
|
/// <param name="array">Array to copy the priority queue into</param>
|
||||||
|
/// <param name="index">Starting index for the destination array</param>
|
||||||
|
public void CopyTo(Array array, int index) {
|
||||||
|
this.internalQueue.CopyTo(array, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Obtains an object that can be used to synchronize accesses to the priority queue
|
||||||
|
/// from different threads
|
||||||
|
/// </summary>
|
||||||
|
public object SyncRoot {
|
||||||
|
get { return this.internalQueue.SyncRoot; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Whether operations performed on this priority queue are thread safe</summary>
|
||||||
|
public bool IsSynchronized {
|
||||||
|
get { return this.internalQueue.IsSynchronized; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Returns a typesafe enumerator for the priority queue</summary>
|
||||||
|
/// <returns>A new enumerator for the priority queue</returns>
|
||||||
|
public IEnumerator<PriorityItemPair<PriorityType, ItemType>> GetEnumerator() {
|
||||||
|
return this.internalQueue.GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Returns an enumerator for the priority queue</summary>
|
||||||
|
/// <returns>A new enumerator for the priority queue</returns>
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() {
|
||||||
|
return this.internalQueue.GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Intrusive priority queue being wrapped by this class</summary>
|
||||||
|
private PriorityQueue<PriorityItemPair<PriorityType, ItemType>> internalQueue;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Nuclex.Support.Collections
|
76
Source/Collections/PriorityItemPair.cs
Normal file
76
Source/Collections/PriorityItemPair.cs
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
#region CPL License
|
||||||
|
/*
|
||||||
|
Nuclex Framework
|
||||||
|
Copyright (C) 2002-2007 Nuclex Development Labs
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the IBM Common Public License as
|
||||||
|
published by the IBM Corporation; either version 1.0 of the
|
||||||
|
License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
IBM Common Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the IBM Common Public
|
||||||
|
License along with this library
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Nuclex.Support.Collections {
|
||||||
|
|
||||||
|
/// <summary>An pair of a priority and an item</summary>
|
||||||
|
public struct PriorityItemPair<PriorityType, ItemType> {
|
||||||
|
|
||||||
|
/// <summary>Initializes a new priority / item pair</summary>
|
||||||
|
/// <param name="priority">Priority of the item in the pair</param>
|
||||||
|
/// <param name="item">Item to be stored in the pair</param>
|
||||||
|
public PriorityItemPair(PriorityType priority, ItemType item) {
|
||||||
|
this.Priority = priority;
|
||||||
|
this.Item = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Priority assigned to this priority / item pair</summary>
|
||||||
|
public PriorityType Priority;
|
||||||
|
/// <summary>Item contained in this priority / item pair</summary>
|
||||||
|
public ItemType Item;
|
||||||
|
|
||||||
|
/// <summary>Converts the priority / item pair into a string</summary>
|
||||||
|
/// <returns>A string describing the priority / item pair</returns>
|
||||||
|
public override string ToString() {
|
||||||
|
int length = 4;
|
||||||
|
|
||||||
|
// Convert the priority value into a string or use the empty string
|
||||||
|
// constant if the ToString() overload returns null
|
||||||
|
string priorityString = this.Priority.ToString();
|
||||||
|
if(priorityString != null)
|
||||||
|
length += priorityString.Length;
|
||||||
|
else
|
||||||
|
priorityString = string.Empty;
|
||||||
|
|
||||||
|
// Convert the item value into a string or use the empty string
|
||||||
|
// constant if the ToString() overload returns null
|
||||||
|
string itemString = this.Item.ToString();
|
||||||
|
if(itemString != null)
|
||||||
|
length += itemString.Length;
|
||||||
|
else
|
||||||
|
itemString = string.Empty;
|
||||||
|
|
||||||
|
// Concatenate priority and item into a single string
|
||||||
|
StringBuilder builder = new StringBuilder(length);
|
||||||
|
builder.Append('[');
|
||||||
|
builder.Append(priorityString);
|
||||||
|
builder.Append(", ");
|
||||||
|
builder.Append(itemString);
|
||||||
|
builder.Append(']');
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Nuclex.Support.Collections
|
|
@ -94,6 +94,11 @@ namespace Nuclex.Support.Collections {
|
||||||
|
|
||||||
#endregion // class Enumerator
|
#endregion // class Enumerator
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new priority queue using IComparable for comparing items
|
||||||
|
/// </summary>
|
||||||
|
public PriorityQueue() : this(Comparer<ItemType>.Default) { }
|
||||||
|
|
||||||
/// <summary>Initializes a new priority queue</summary>
|
/// <summary>Initializes a new priority queue</summary>
|
||||||
/// <param name="comparer">Comparer to use for ordering the items</param>
|
/// <param name="comparer">Comparer to use for ordering the items</param>
|
||||||
public PriorityQueue(IComparer<ItemType> comparer) {
|
public PriorityQueue(IComparer<ItemType> comparer) {
|
||||||
|
|
|
@ -123,7 +123,7 @@ namespace Nuclex.Support.Collections {
|
||||||
setEmpty();
|
setEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the end index lies before the start index, the data in the
|
// The end index lies before the start index, so the data in the
|
||||||
// ring memory stream is fragmented. Example: |#####>-------<#####|
|
// ring memory stream is fragmented. Example: |#####>-------<#####|
|
||||||
} else {
|
} else {
|
||||||
int linearAvailable = (int)this.ringBuffer.Length - this.startIndex;
|
int linearAvailable = (int)this.ringBuffer.Length - this.startIndex;
|
||||||
|
@ -166,7 +166,7 @@ namespace Nuclex.Support.Collections {
|
||||||
public override void Write(byte[] buffer, int offset, int count) {
|
public override void Write(byte[] buffer, int offset, int count) {
|
||||||
|
|
||||||
// The end index lies behind the start index (usual case), so the
|
// The end index lies behind the start index (usual case), so the
|
||||||
// ring memory is not fragmented. Example: |-----<#######>-----|
|
// unused buffer space is fragmented. Example: |-----<#######>-----|
|
||||||
if((this.startIndex < this.endIndex) || this.empty) {
|
if((this.startIndex < this.endIndex) || this.empty) {
|
||||||
int linearAvailable = (int)(this.ringBuffer.Length - this.endIndex);
|
int linearAvailable = (int)(this.ringBuffer.Length - this.endIndex);
|
||||||
|
|
||||||
|
@ -193,9 +193,9 @@ namespace Nuclex.Support.Collections {
|
||||||
|
|
||||||
this.empty = false;
|
this.empty = false;
|
||||||
|
|
||||||
// If the end index lies before the start index, the ring memory stream
|
// The end index lies before the start index, so the data in the ring memory
|
||||||
// has been fragmented. Hence, this means the gap into which we are about
|
// stream has been fragmented. This means the gap into which we are about
|
||||||
// to write cannot be fragmented. Example: |#####>-------<#####|
|
// to write is not fragmented. Example: |#####>-------<#####|
|
||||||
} else {
|
} else {
|
||||||
if(count > (this.startIndex - this.endIndex))
|
if(count > (this.startIndex - this.endIndex))
|
||||||
throw new OverflowException("Data does not fit in buffer");
|
throw new OverflowException("Data does not fit in buffer");
|
||||||
|
|
|
@ -1,190 +0,0 @@
|
||||||
#region CPL License
|
|
||||||
/*
|
|
||||||
Nuclex Framework
|
|
||||||
Copyright (C) 2002-2007 Nuclex Development Labs
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the IBM Common Public License as
|
|
||||||
published by the IBM Corporation; either version 1.0 of the
|
|
||||||
License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
IBM Common Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the IBM Common Public
|
|
||||||
License along with this library
|
|
||||||
*/
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections;
|
|
||||||
|
|
||||||
namespace Nuclex.Support.Collections {
|
|
||||||
|
|
||||||
/// <summary>Queue that dequeues items in order of their priority</summary>
|
|
||||||
public class UnintrusivePriorityQueue<ItemType, PriorityType>
|
|
||||||
: ICollection, IEnumerable<ItemType>
|
|
||||||
where PriorityType : IComparable<PriorityType> {
|
|
||||||
|
|
||||||
#region struct Entry
|
|
||||||
|
|
||||||
/// <summary>An entry in the priority queue</summary>
|
|
||||||
private struct Entry {
|
|
||||||
|
|
||||||
/// <summary>Initializes a new priority queue entry</summary>
|
|
||||||
/// <param name="item">Item to be stored in the entry</param>
|
|
||||||
/// <param name="priority">Priority of the item in the entry</param>
|
|
||||||
public Entry(ItemType item, PriorityType priority) {
|
|
||||||
this.Item = item;
|
|
||||||
this.Priority = priority;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Item contained in this priority queue entry</summary>
|
|
||||||
public ItemType Item;
|
|
||||||
/// <summary>Priority assigned to this entry</summary>
|
|
||||||
public PriorityType Priority;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion // struct Entry
|
|
||||||
|
|
||||||
#region class EntryComparer
|
|
||||||
|
|
||||||
/// <summary>Compares two priority queue entries based on their priority</summary>
|
|
||||||
private class EntryComparer : IComparer<Entry> {
|
|
||||||
|
|
||||||
/// <summary>Compares the left entry to the right entry</summary>
|
|
||||||
/// <param name="left">Entry on the left side</param>
|
|
||||||
/// <param name="right">Entry on the right side</param>
|
|
||||||
/// <returns>The relationship of the two entries</returns>
|
|
||||||
public int Compare(Entry left, Entry right) {
|
|
||||||
return left.Priority.CompareTo(right.Priority);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Default instance for this comparer</summary>
|
|
||||||
public static readonly EntryComparer Instance = new EntryComparer();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion // class EntryComparer
|
|
||||||
|
|
||||||
#region class UnwrappingEnumerator
|
|
||||||
|
|
||||||
/// <summary>Enumerates all items contained in a priority queue</summary>
|
|
||||||
private class UnwrappingEnumerator : IEnumerator<ItemType> {
|
|
||||||
|
|
||||||
/// <summary>Initializes a new priority queue enumerator</summary>
|
|
||||||
/// <param name="entryEnumerator">Enumerator of entries to unwrap</param>
|
|
||||||
public UnwrappingEnumerator(IEnumerator<Entry> entryEnumerator) {
|
|
||||||
this.entryEnumerator = entryEnumerator;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Resets the enumerator to its initial state</summary>
|
|
||||||
public void Reset() {
|
|
||||||
this.entryEnumerator.Reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>The current item being enumerated</summary>
|
|
||||||
ItemType IEnumerator<ItemType>.Current {
|
|
||||||
get { return this.entryEnumerator.Current.Item; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Releases all resources used by the enumerator</summary>
|
|
||||||
public void Dispose() {
|
|
||||||
this.entryEnumerator.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Moves to the next item in the priority queue</summary>
|
|
||||||
/// <returns>True if a next item was found, false if the end has been reached</returns>
|
|
||||||
public bool MoveNext() {
|
|
||||||
return this.entryEnumerator.MoveNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>The current item being enumerated</summary>
|
|
||||||
object IEnumerator.Current {
|
|
||||||
get { return this.entryEnumerator.Current.Item; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Enumerator for entries to be unwrapped by this enumerator</summary>
|
|
||||||
private IEnumerator<Entry> entryEnumerator;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion // class Enumerator
|
|
||||||
|
|
||||||
/// <summary>Initializes a new non-intrusive priority queue</summary>
|
|
||||||
public UnintrusivePriorityQueue() {
|
|
||||||
this.intrusiveQueue = new PriorityQueue<Entry>(EntryComparer.Instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Takes the item with the highest priority off from the queue</summary>
|
|
||||||
/// <returns>The item with the highest priority in the list</returns>
|
|
||||||
public ItemType Dequeue() {
|
|
||||||
return this.intrusiveQueue.Dequeue().Item;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Puts an item into the priority queue</summary>
|
|
||||||
/// <param name="item">Item to be queued</param>
|
|
||||||
/// <param name="priority">Priority of the item to be queued</param>
|
|
||||||
public void Enqueue(ItemType item, PriorityType priority) {
|
|
||||||
this.intrusiveQueue.Enqueue(new Entry(item, priority));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Removes all items from the priority queue</summary>
|
|
||||||
public void Clear() {
|
|
||||||
this.intrusiveQueue.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Total number of items in the priority queue</summary>
|
|
||||||
public int Count {
|
|
||||||
get { return this.intrusiveQueue.Count; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Copies the contents of the priority queue into an array</summary>
|
|
||||||
/// <param name="array">Array to copy the priority queue into</param>
|
|
||||||
/// <param name="index">Starting index for the destination array</param>
|
|
||||||
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);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Obtains an object that can be used to synchronize accesses to the priority queue
|
|
||||||
/// from different threads
|
|
||||||
/// </summary>
|
|
||||||
public object SyncRoot {
|
|
||||||
get { return this.intrusiveQueue.SyncRoot; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Whether operations performed on this priority queue are thread safe</summary>
|
|
||||||
public bool IsSynchronized {
|
|
||||||
get { return this.intrusiveQueue.IsSynchronized; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Returns a typesafe enumerator for the priority queue</summary>
|
|
||||||
/// <returns>A new enumerator for the priority queue</returns>
|
|
||||||
public IEnumerator<ItemType> GetEnumerator() {
|
|
||||||
return new UnwrappingEnumerator(this.intrusiveQueue.GetEnumerator());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Returns an enumerator for the priority queue</summary>
|
|
||||||
/// <returns>A new enumerator for the priority queue</returns>
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() {
|
|
||||||
return new UnwrappingEnumerator(this.intrusiveQueue.GetEnumerator());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Intrusive priority queue being wrapped by this class</summary>
|
|
||||||
private PriorityQueue<Entry> intrusiveQueue;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Nuclex.Support.Collections
|
|
Loading…
Reference in New Issue
Block a user