diff --git a/src/public/tier1/utlpriorityqueue.h b/src/public/tier1/utlpriorityqueue.h index 2dc00a3..2852b45 100644 --- a/src/public/tier1/utlpriorityqueue.h +++ b/src/public/tier1/utlpriorityqueue.h @@ -7,22 +7,22 @@ #ifndef UTLPRIORITYQUEUE_H #define UTLPRIORITYQUEUE_H -#ifdef _WIN32 -#pragma once -#endif + +#include +template using CDefLess = std::less; #include "utlvector.h" template < typename T > class CDefUtlPriorityQueueSetIndexFunc { public: - inline static void SetIndex( T &heapElement, int nNewIndex ) { } + inline static void SetIndex( T &heapElement, int nNewIndex, void *pContext ) { } }; // T is the type stored in the queue, it must include the priority // The head of the list contains the element with GREATEST priority // configure the LessFunc_t to get the desired queue order -template< class T, class L = bool (*)( T const&, T const& ), class SetIndexFunc = CDefUtlPriorityQueueSetIndexFunc > +template< class T, class L = CDefLess, class SetIndexFunc = CDefUtlPriorityQueueSetIndexFunc > class CUtlPriorityQueue { public: @@ -33,10 +33,9 @@ public: typedef T ElemType_t; - // constructor: lessfunc is required, but may be set after the constructor with - // SetLessFunc - CUtlPriorityQueue( int growSize = 0, int initSize = 0, LessFunc_t lessfunc = LessFunc_t() ); - CUtlPriorityQueue( T *pMemory, int numElements, LessFunc_t lessfunc = LessFunc_t() ); + // constructor: lessfunc is required + CUtlPriorityQueue( int growSize = 0, int initSize = 0, LessFunc_t lessfunc = {} ); + CUtlPriorityQueue( T *pMemory, int numElements, LessFunc_t lessfunc = {} ); // gets particular elements inline T const& ElementAtHead() const { return m_heap.Element(0); } @@ -52,9 +51,7 @@ public: // O(lgn) to rebalance heap void Insert( T const &element ); - // Sets the less func - void SetLessFunc( LessFunc_t func ); - + // Returns the count of elements in the queue inline int Count() const { return m_heap.Count(); } @@ -64,19 +61,28 @@ public: // Memory deallocation void Purge() { m_heap.Purge(); } + int InvalidIndex() const { return m_heap.InvalidIndex(); } + inline const T & Element( int index ) const { return m_heap.Element(index); } + inline T &ElementMutable( int index ) { return m_heap.Element( index ); } + + void SetSetIndexContext( void *pContext ) { m_pSetIndexContext = pContext; } + #ifdef DBGFLAG_VALIDATE void Validate( CValidator &validator, const char *pchName ); + void RecursiveValidate( CValidator &validator, const char *pchName ); #endif // DBGFLAG_VALIDATE protected: CUtlVector m_heap; - void Swap( int index1, int index2 ); + void Swap( int parent, int child ); int PercolateDown( int nIndex ); int PercolateUp( int nIndex ); + void *m_pSetIndexContext = NULL; + // Used for sorting. LessFunc_t m_LessFunc; }; @@ -96,15 +102,15 @@ inline CUtlPriorityQueue::CUtlPriorityQueue( T *pMemo template inline void CUtlPriorityQueue::RemoveAtHead() { - SetIndexFunc::SetIndex( m_heap[ 0 ], m_heap.InvalidIndex() ); + SetIndexFunc::SetIndex( m_heap[ 0 ], m_heap.InvalidIndex(), m_pSetIndexContext ); m_heap.FastRemove( 0 ); if ( Count() > 0 ) { - SetIndexFunc::SetIndex( m_heap[ 0 ], 0 ); + SetIndexFunc::SetIndex( m_heap[ 0 ], 0, m_pSetIndexContext ); + PercolateDown( 0 ); } - - PercolateDown( 0 ); + } @@ -112,20 +118,25 @@ template inline void CUtlPriorityQueue::RemoveAt( int index ) { Assert(m_heap.IsValidIndex(index)); - SetIndexFunc::SetIndex( m_heap[ index ], m_heap.InvalidIndex() ); + SetIndexFunc::SetIndex( m_heap[ index ], m_heap.InvalidIndex(), m_pSetIndexContext ); m_heap.FastRemove( index ); if ( index < Count() ) { - SetIndexFunc::SetIndex( m_heap[ index ], index ); + SetIndexFunc::SetIndex( m_heap[ index ], index, m_pSetIndexContext ); + RevaluateElement( index ); } - - RevaluateElement( index ); } template inline void CUtlPriorityQueue::RevaluateElement( int nStartingIndex ) { + if ( (unsigned)nStartingIndex >= (unsigned)Count() ) + { + Assert( false ); + return; + } + int index = PercolateDown( nStartingIndex ); // If index is still the same as the starting index, then the specified element was larger than @@ -141,21 +152,22 @@ template< class T, class LessFunc, class SetIndexFunc > inline int CUtlPriorityQueue::PercolateDown( int index ) { int count = Count(); - - int half = count/2; + DbgAssert( (unsigned)index < (unsigned)count ); + int larger = index; - while ( index < half ) + for (;;) { int child = ((index+1) * 2) - 1; // if we wasted an element, this math would be more compact (1 based array) - if ( child < count ) + if ( child >= count ) + break; + + // Item has been filtered down to its proper place, terminate. + if ( m_LessFunc( m_heap[index], m_heap[child] ) ) { - // Item has been filtered down to its proper place, terminate. - if ( m_LessFunc( m_heap[index], m_heap[child] ) ) - { - // mark the potential swap and check the other child - larger = child; - } + // mark the potential swap and check the other child + larger = child; } + // go to sibling child++; if ( child < count ) @@ -179,13 +191,14 @@ inline int CUtlPriorityQueue::PercolateDown( int ind template< class T, class LessFunc, class SetIndexFunc > inline int CUtlPriorityQueue::PercolateUp( int index ) { - if ( index >= Count() ) - return index; + DbgAssert( (unsigned)index < (unsigned)Count() ); - while ( index != 0 ) + while ( index > 0 ) { int parent = ((index+1) / 2) - 1; - if ( m_LessFunc( m_heap[index], m_heap[parent] ) ) + + // Heap condition satisfied? Then we're done + if ( !m_LessFunc( m_heap[parent], m_heap[index] ) ) break; // swap with parent and repeat @@ -201,25 +214,26 @@ inline void CUtlPriorityQueue::Insert( T const &elem { int index = m_heap.AddToTail(); m_heap[index] = element; - SetIndexFunc::SetIndex( m_heap[ index ], index ); + SetIndexFunc::SetIndex( m_heap[ index ], index, m_pSetIndexContext ); PercolateUp( index ); } template -void CUtlPriorityQueue::Swap( int index1, int index2 ) +void CUtlPriorityQueue::Swap( int parent, int child ) { - T tmp = m_heap[index1]; - m_heap[index1] = m_heap[index2]; - m_heap[index2] = tmp; - SetIndexFunc::SetIndex( m_heap[ index1 ], index1 ); - SetIndexFunc::SetIndex( m_heap[ index2 ], index2 ); -} + // Our current code should never call this unless there is a heap violation, + // otherwise we are wasting work. Also we assume that + // this internal function will only be called with the parent + // in the first operand + DbgAssert( parent < child ); + DbgAssert( m_LessFunc( m_heap[parent], m_heap[child] ) ); -template -void CUtlPriorityQueue::SetLessFunc( LessFunc_t lessfunc ) -{ - m_LessFunc = lessfunc; + T tmp = m_heap[parent]; + m_heap[parent] = m_heap[child]; + m_heap[child] = tmp; + SetIndexFunc::SetIndex( m_heap[ parent ], parent, m_pSetIndexContext ); + SetIndexFunc::SetIndex( m_heap[ child ], child, m_pSetIndexContext ); } //----------------------------------------------------------------------------- @@ -239,6 +253,15 @@ void CUtlPriorityQueue::Validate( CValidator &validat validator.Pop(); } + +template +void CUtlPriorityQueue::RecursiveValidate( CValidator &validator, const char *pchName ) +{ + VALIDATE_SCOPE(); + + ValidateRecursive( m_heap ); + +} #endif // DBGFLAG_VALIDATE #endif // UTLPRIORITYQUEUE_H diff --git a/src/steamnetworkingsockets/steamnetworkingsockets_thinker.cpp b/src/steamnetworkingsockets/steamnetworkingsockets_thinker.cpp index 5a4bd81..5e073cf 100644 --- a/src/steamnetworkingsockets/steamnetworkingsockets_thinker.cpp +++ b/src/steamnetworkingsockets/steamnetworkingsockets_thinker.cpp @@ -37,7 +37,7 @@ struct ThinkerLess class ThinkerSetIndex { public: - static void SetIndex( IThinker *p, int idx ) { p->m_queueIndex = idx; } + static void SetIndex( IThinker *p, int idx, void *pContext ) { p->m_queueIndex = idx; } }; static CUtlPriorityQueue s_queueThinkers;