//+--------------------------------------------------------------------------- // // Copyright (C) 1996, Microsoft Corporation // // File: tpriq.hxx // // Contents: priority queue template // // Classes: TPriorityQueue // // History: 12-Jan-96 dlee Created // //---------------------------------------------------------------------------- #pragma once //+--------------------------------------------------------------------------- // // Class: TPriorityQueue // // Purpose: Priority queue class implemented using a sorted array. // // History: 12-Jan-96 dlee Created // // Notes: Class T must implement two methods: // // BOOL IsGreaterThan( T & rItem ) // // returns TRUE if "this" is greater than rItem // // unsigned GetSize() // // returns size of the item, generally 1 // //---------------------------------------------------------------------------- template class TPriorityQueue { public: TPriorityQueue( BOOL fSizeIsOne, unsigned maxTotalSize ) : _maxTotalSize( maxTotalSize ), _curSize( 0 ), _aItems( fSizeIsOne ? maxTotalSize : 16 ) { } ~TPriorityQueue() {} BOOL DeQueue( T & rItem ); void EnQueue( T & rItem ); BOOL ShouldEnQueue( T & rItem, unsigned & cDeQueue ); void Remove( unsigned iItem ); T & PeekTop() { Win4Assert( 0 != Count() ); return _aItems[ 0 ]; } T & Peek( unsigned iItem ) { // Peek() is not guaranteed to return the items in any given order Win4Assert( iItem < Count() ); return _aItems[ iItem ]; } unsigned CurrentSize() { return _curSize; } unsigned Count() { return _aItems.Count(); } unsigned MaxTotalSize() { return _maxTotalSize; } private: unsigned _maxTotalSize; unsigned _curSize; CDynArrayInPlace _aItems; }; //+------------------------------------------------------------------------- // // Member: CPriorityQueue::DeQueue, public // // Synopsis: Removes the highest-most priority item. // // History: 12-Jan-96 dlee Created // //-------------------------------------------------------------------------- template BOOL TPriorityQueue::DeQueue( T & rItem ) { if ( 0 != _aItems.Count() ) { // Return the item at the top of the queue rItem = _aItems[0]; _curSize -= rItem.GetSize(); _aItems.Remove( 0 ); vqDebugOut( ( DEB_TRACE, "TPriorityQueue::DeQueue, %d items remain\n", Count() ) ); return TRUE; } return FALSE; } //DeQueue template void TPriorityQueue::EnQueue( T & rItem ) { // Find the insertion point for ( unsigned i = 0; i < _aItems.Count(); i++ ) { if ( !_aItems[ i ].IsGreaterThan( rItem ) ) break; } _aItems.Insert( rItem, i ); _curSize += rItem.GetSize(); vqDebugOut(( DEB_TRACE, "CPriorityQueue::EnQueue %d items\n", Count() ) ); } //EnQueue //+--------------------------------------------------------------------------- // // Member: TPriorityQueue::ShouldEnQueue, public // // Synopsis: Determines if new item should be added to queue // // Arguments: [rItem] -- Item to add // [cDequeue] -- Count of items which must be dequeued before // adding [rItem]. // // Returns: TRUE if item should be added to queue // // History: 7-Aug-97 Created // //---------------------------------------------------------------------------- template BOOL TPriorityQueue::ShouldEnQueue( T & rItem, unsigned & cDeQueue ) { cDeQueue = 0; // Determine if we have to dequeue an item to get this item in the queue if ( 0 == Count() ) return ( rItem.GetSize() <= _maxTotalSize ); if ( ( rItem.GetSize() + _curSize ) > _maxTotalSize ) { // // Is new item lower-priority than top item on queue? // If so, we can immediately reject this item. // if ( rItem.IsGreaterThan( _aItems[ 0 ] ) ) { vqDebugOut(( DEB_TRACE, "CPriorityQueue::EnQueue item rejected (low priority)\n" ) ); return FALSE; } // // Can we remove enough lower priority items to fit this on? // int SizeRemaining = rItem.GetSize(); int FreeSpace = _maxTotalSize - _curSize; Win4Assert( SizeRemaining > FreeSpace ); SizeRemaining -= FreeSpace; while ( cDeQueue < Count() && SizeRemaining > 0 && !rItem.IsGreaterThan( _aItems[ cDeQueue ] ) ) { SizeRemaining -= _aItems[ cDeQueue ].GetSize(); cDeQueue++; } // // We might have removed everything and still not have enough space. // if ( cDeQueue == Count() ) { return ( rItem.GetSize() <= _maxTotalSize ); } // // Or we may have failed to remove everything and not have enough space. // else if ( SizeRemaining > 0 ) { vqDebugOut(( DEB_TRACE, "CPriorityQueue::EnQueue item rejected (can't fit)\n" ) ); cDeQueue = 0; return FALSE; } } return TRUE; } //ShouldEnQueue template void TPriorityQueue::Remove( unsigned iItem ) { Win4Assert( iItem < Count() ); _curSize -= _aItems[ iItem ].GetSize(); _aItems.Remove( iItem ); } //Remove