diff --git a/ICD.Common.Utils.Tests/Collections/PriorityQueueTest.cs b/ICD.Common.Utils.Tests/Collections/PriorityQueueTest.cs index 5163e0d..caa319f 100644 --- a/ICD.Common.Utils.Tests/Collections/PriorityQueueTest.cs +++ b/ICD.Common.Utils.Tests/Collections/PriorityQueueTest.cs @@ -98,6 +98,51 @@ namespace ICD.Common.Utils.Tests.Collections Assert.AreEqual(1, dequeue[2]); } + [Test] + public void EnqueueFirstTest() + { + PriorityQueue queue = new PriorityQueue(); + + queue.Enqueue(1, int.MaxValue); + queue.Enqueue(2, int.MinValue); + queue.EnqueueFirst(3); + + Assert.AreEqual(3, queue.Count); + + Assert.AreEqual(3, queue.Dequeue()); + } + + [Test] + public void EnqueueRemoveTest() + { + PriorityQueue queue = new PriorityQueue(); + + queue.Enqueue(1); + queue.Enqueue(2); + queue.Enqueue(3); + + queue.EnqueueRemove(4, i => i == 2); + + Assert.AreEqual(3, queue.Count); + + List dequeue = new List + { + queue.Dequeue(), + queue.Dequeue(), + queue.Dequeue() + }; + + Assert.AreEqual(1, dequeue[0]); + Assert.AreEqual(4, dequeue[1]); + Assert.AreEqual(3, dequeue[2]); + } + + [Test] + public void EnqueueRemovePriorityTest() + { + Assert.Inconclusive(); + } + [Test] public void DequeueTest() { diff --git a/ICD.Common.Utils/Collections/PriorityQueue.cs b/ICD.Common.Utils/Collections/PriorityQueue.cs index 2601c13..e66ddfe 100644 --- a/ICD.Common.Utils/Collections/PriorityQueue.cs +++ b/ICD.Common.Utils/Collections/PriorityQueue.cs @@ -80,6 +80,85 @@ namespace ICD.Common.Utils.Collections m_Count++; } + /// + /// Enqueues the item at the beginning of the queue. + /// + /// + [PublicAPI] + public void EnqueueFirst(T item) + { + const int priority = int.MinValue; + + if (!m_PriorityToQueue.ContainsKey(priority)) + m_PriorityToQueue.Add(priority, new List()); + + m_PriorityToQueue[priority].Insert(0, item); + m_Count++; + } + + /// + /// Removes any items in the queue matching the predicate. + /// Inserts the given item in the position of the first removed item, or at the end of the queue. + /// This is useful for reducing duplication, or replacing items with something more pertinant. + /// + /// + /// + [PublicAPI] + public void EnqueueRemove(T item, Func remove) + { + if (remove == null) + throw new ArgumentNullException("remove"); + + EnqueueRemove(item, remove, int.MaxValue); + } + + /// + /// Removes any items in the queue matching the predicate. + /// Inserts the given item in the position of the first removed item, or at the end of the queue. + /// This is useful for reducing duplication, or replacing items with something more pertinant. + /// + /// + /// + /// + [PublicAPI] + public void EnqueueRemove(T item, Func remove, int priority) + { + if (remove == null) + throw new ArgumentNullException("remove"); + + bool inserted = false; + + foreach (KeyValuePair> kvp in m_PriorityToQueue) + { + int[] removeIndices = + kvp.Value + .FindIndices(v => remove(v)) + .Reverse() + .ToArray(); + + if (removeIndices.Length == 0) + continue; + + foreach (int removeIndex in removeIndices) + { + kvp.Value.RemoveAt(removeIndex); + m_Count--; + } + + if (!inserted) + { + int insertIndex = removeIndices[0]; + kvp.Value.Insert(insertIndex, item); + m_Count++; + + inserted = true; + } + } + + if (!inserted) + Enqueue(item, priority); + } + /// /// Dequeues the first item with the lowest priority value. ///