Minor tweaks to CUtlPriorityQueue

To bring it in sync with the version in //Steam/main

P4:8088082
This commit is contained in:
Fletcher Dunn
2023-05-27 18:55:32 -07:00
parent 2f5f0a4425
commit def044717f
2 changed files with 71 additions and 48 deletions
+70 -47
View File
@@ -7,22 +7,22 @@
#ifndef UTLPRIORITYQUEUE_H
#define UTLPRIORITYQUEUE_H
#ifdef _WIN32
#pragma once
#endif
#include <functional>
template<typename T> using CDefLess = std::less<T>;
#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<T> >
template< class T, class L = CDefLess<T>, class SetIndexFunc = CDefUtlPriorityQueueSetIndexFunc<T> >
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<T> 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<T, LessFunc, SetIndexFunc>::CUtlPriorityQueue( T *pMemo
template <class T, class LessFunc, class SetIndexFunc>
inline void CUtlPriorityQueue<T, LessFunc, SetIndexFunc>::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 <class T, class LessFunc, class SetIndexFunc>
inline void CUtlPriorityQueue<T, LessFunc, SetIndexFunc>::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 <class T, class LessFunc, class SetIndexFunc>
inline void CUtlPriorityQueue<T, LessFunc, SetIndexFunc >::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<T, LessFunc, SetIndexFunc >::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<T, LessFunc, SetIndexFunc >::PercolateDown( int ind
template< class T, class LessFunc, class SetIndexFunc >
inline int CUtlPriorityQueue<T, LessFunc, SetIndexFunc >::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<T, LessFunc, SetIndexFunc >::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 <class T, class LessFunc, class SetIndexFunc>
void CUtlPriorityQueue<T, LessFunc, SetIndexFunc>::Swap( int index1, int index2 )
void CUtlPriorityQueue<T, LessFunc, SetIndexFunc>::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 <class T, class LessFunc, class SetIndexFunc>
void CUtlPriorityQueue<T, LessFunc, SetIndexFunc>::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<T, LessFunc, SetIndexFunc>::Validate( CValidator &validat
validator.Pop();
}
template <class T, class LessFunc, class SetIndexFunc>
void CUtlPriorityQueue<T, LessFunc, SetIndexFunc>::RecursiveValidate( CValidator &validator, const char *pchName )
{
VALIDATE_SCOPE();
ValidateRecursive( m_heap );
}
#endif // DBGFLAG_VALIDATE
#endif // UTLPRIORITYQUEUE_H
@@ -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<IThinker*,ThinkerLess,ThinkerSetIndex> s_queueThinkers;