/// /// Copyright © 2003-2008 JetBrains s.r.o. /// You may distribute under the terms of the GNU General Public License, as published by the Free Software Foundation, version 2 (see License.txt in the repository root folder). /// using System; using System.Collections; using JetBrains.Omea.Base; namespace JetBrains.Omea.Containers { /** * default priority queue works with int priority values * the more priority, the faster an object is popped * NOTE: specific feature of the PriorityQueue is that objects pushed with * the same priority are popped in the sequence of pushing * The feature is guaranteed by properties of encapsulated RedBlackTree */ public class PriorityQueue: IEnumerable { public PriorityQueue() { _tree = new RedBlackTree( new QueueEntryComparer() ); } public void Push( int priority, object obj ) { QueueEntry entry = AllocEntry(); entry.SetEntry( priority, obj, _tree._null ); _tree.RB_InsertNode( entry ); } public object Pop() { QueueEntry node = (QueueEntry) _tree.GetMinimumNode(); if( node == null ) { return null; } object result = node.Value; _tree.RB_Delete( node ); _freeNode = node; return result; } public void Remove( QueueEntry entry ) { _tree.RB_Delete( entry ); } public int Count { get { return _tree.Count; } } public QueueEntry PopEntry() { QueueEntry node = (QueueEntry) _tree.GetMinimumNode(); if( node == null ) { return null; } _tree.RB_Delete( node ); return node; } #region IEnumerable Members private class PriorityQueueEnumerator: IEnumerator { private RedBlackTree _tree; private QueueEntry _queueEntry; internal PriorityQueueEnumerator( RedBlackTree tree ) { _tree = tree; Reset(); } #region IEnumerator Members public void Reset() { _queueEntry = null; } public object Current { get { return _queueEntry; } } public bool MoveNext() { if( _queueEntry == null ) { _queueEntry = _tree.GetMinimumNode() as QueueEntry; } else { _queueEntry = _tree.GetSuccessor( _queueEntry ) as QueueEntry; } return _queueEntry != null; } #endregion } public IEnumerator GetEnumerator() { return new PriorityQueueEnumerator( _tree ); } #endregion /// /// Priority queue entry inherits RBNodeBase /// public class QueueEntry : RBNodeBase { private int _priority; private object _object; public void SetEntry( int priority, object obj, RBNodeBase nullNode ) { _priority = priority; _object = obj; _right = _left = _parent = nullNode; } public int CompareTo( object obj ) { QueueEntry entry = (QueueEntry) obj; return entry._priority - _priority; } public override object Key { get { return IntInternalizer.Intern( _priority ); } set { _priority = (int) value; } } public int Priority { get { return _priority; } } public object Value { get { return _object; } } } protected class QueueEntryComparer : IComparer { #region IComparer Members public int Compare( object x, object y ) { return (int) y - (int) x; } #endregion } private QueueEntry AllocEntry() { QueueEntry result = _freeNode; if( result == null ) { result = new QueueEntry(); } else { _freeNode = null; } return result; } protected RedBlackTree _tree; protected QueueEntry _freeNode; } /** * priority queue with DateTime priority values * the less priority (date & time), the faster an object is popped * uses partially ordered tree instead of red-black tree (less memory), * so it doesn't guarantee any order for objects with the same date & time */ public class DateTimePriorityQueue { public DateTimePriorityQueue() { _poTree = new ArrayList(); } public void Push( DateTime priority, object obj ) { int i = _poTree.Count; QueueEntry newEntry = new QueueEntry( priority, obj ); _poTree.Add( newEntry ); while( i > 0 ) { int parent = ( i - 1 ) >> 1; QueueEntry E = (QueueEntry) _poTree[ parent ]; if( E.Priority <= priority ) { break; } _poTree[ parent ] = newEntry; _poTree[ i ] = E; i = parent; } } public object Pop() { QueueEntry minEntry = PopEntry(); return ( minEntry == null ) ? null : minEntry.Value; } public int Count { get { return _poTree.Count; } } public QueueEntry PopEntry() { QueueEntry result = GetMinimumEntry(); if( result != null ) { int lastIndex = _poTree.Count - 1; QueueEntry E = (QueueEntry) _poTree[ lastIndex ]; _poTree.RemoveAt( lastIndex ); if( _poTree.Count == 0 ) { _poTree.TrimToSize(); } else { _poTree[ 0 ] = E; int i = 0; int left; while( ( left = ( i << 1 ) + 1 ) < _poTree.Count ) { QueueEntry leftEntry = (QueueEntry) _poTree[ left ]; if( left + 1 < _poTree.Count ) { QueueEntry rightEntry = (QueueEntry) _poTree[ left + 1 ]; if( rightEntry.Priority < leftEntry.Priority ) { leftEntry = rightEntry; ++left; } } if( E.Priority <= leftEntry.Priority ) { break; } _poTree[ left ] = E; _poTree[ i ] = leftEntry; i = left; } } } return result; } public QueueEntry GetMinimumEntry() { return ( _poTree.Count == 0 ) ? null : ( (QueueEntry) _poTree[ 0 ] ); } public class QueueEntry { private DateTime _priority; private object _object; public QueueEntry( DateTime priority, object obj ) { _priority = priority; _object = obj; } public DateTime Priority { get { return _priority; } } public object Value { get { return _object; } } } /** * plain table representation of partially ordered tree */ protected internal ArrayList _poTree; } }