diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /public/tier1/UtlSortVector.h | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'public/tier1/UtlSortVector.h')
| -rw-r--r-- | public/tier1/UtlSortVector.h | 414 |
1 files changed, 414 insertions, 0 deletions
diff --git a/public/tier1/UtlSortVector.h b/public/tier1/UtlSortVector.h new file mode 100644 index 0000000..9890c60 --- /dev/null +++ b/public/tier1/UtlSortVector.h @@ -0,0 +1,414 @@ +//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======// +// +// $Header: $ +// $NoKeywords: $ +// +// A growable array class that keeps all elements in order using binary search +//===========================================================================// + +#ifndef UTLSORTVECTOR_H +#define UTLSORTVECTOR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "utlvector.h" + + +//----------------------------------------------------------------------------- +// class CUtlSortVector: +// description: +// This in an sorted order-preserving vector. Items may be inserted or removed +// at any point in the vector. When an item is inserted, all elements are +// moved down by one element using memmove. When an item is removed, all +// elements are shifted back down. Items are searched for in the vector +// using a binary search technique. Clients must pass in a Less() function +// into the constructor of the vector to determine the sort order. +//----------------------------------------------------------------------------- + +#ifndef _WIN32 +// gcc has no qsort_s, so i need to use a static var to hold the sort context. this makes cutlsortvector _not_ thread sfae under linux +extern void *g_pUtlSortVectorQSortContext; +#endif + +template <class T> +class CUtlSortVectorDefaultLess +{ +public: + bool Less( const T& lhs, const T& rhs, void * ) + { + return lhs < rhs; + } +}; + +template <class T, class LessFunc = CUtlSortVectorDefaultLess<T>, class BaseVector = CUtlVector<T> > +class CUtlSortVector : public BaseVector +{ + typedef BaseVector BaseClass; +public: + /// constructor + CUtlSortVector( int nGrowSize = 0, int initSize = 0 ); + CUtlSortVector( T* pMemory, int numElements ); + + /// inserts (copy constructs) an element in sorted order into the list + int Insert( const T& src ); + + /// inserts (copy constructs) an element in sorted order into the list if it isn't already in the list + int InsertIfNotFound( const T& src ); + + /// Finds an element within the list using a binary search. These are templatized based upon the key + /// in which case the less function must handle the Less function for key, T and T, key + template< typename TKey > + int Find( const TKey& search ) const; + template< typename TKey > + int FindLessOrEqual( const TKey& search ) const; + template< typename TKey > + int FindLess( const TKey& search ) const; + + /// Removes a particular element + void Remove( const T& search ); + void Remove( int i ); + + /// Allows methods to set a context to be used with the less function.. + void SetLessContext( void *pCtx ); + + /// A version of insertion that will produce an un-ordered list. + /// Note that you can only use this index until sorting is redone with RedoSort!!! + int InsertNoSort( const T& src ); + void RedoSort( bool bForceSort = false ); + + /// Use this to insert at a specific insertion point; using FindLessOrEqual + /// is required for use this this. This will test that what you've inserted + /// produces a correctly ordered list. + int InsertAfter( int nElemIndex, const T &src ); + + /// finds a particular element using a linear search. Useful when used + /// in between calls to InsertNoSort and RedoSort + template< typename TKey > + int FindUnsorted( const TKey &src ) const; + +protected: + // No copy constructor + CUtlSortVector( const CUtlSortVector<T, LessFunc> & ); + + // never call these; illegal for this class + int AddToHead(); + int AddToTail(); + int InsertBefore( int elem ); + int InsertAfter( int elem ); + int InsertBefore( int elem, const T& src ); + int AddToHead( const T& src ); + int AddToTail( const T& src ); + int AddMultipleToHead( int num ); + int AddMultipleToTail( int num, const T *pToCopy=NULL ); + int InsertMultipleBefore( int elem, int num, const T *pToCopy=NULL ); + int InsertMultipleAfter( int elem, int num ); + int AddVectorToTail( CUtlVector<T> const &src ); + + struct QSortContext_t + { + void *m_pLessContext; + LessFunc *m_pLessFunc; + }; + +#ifdef _WIN32 + static int CompareHelper( void *context, const T *lhs, const T *rhs ) + { + QSortContext_t *ctx = reinterpret_cast< QSortContext_t * >( context ); + if ( ctx->m_pLessFunc->Less( *lhs, *rhs, ctx->m_pLessContext ) ) + return -1; + if ( ctx->m_pLessFunc->Less( *rhs, *lhs, ctx->m_pLessContext ) ) + return 1; + return 0; + } +#else + static int CompareHelper( const T *lhs, const T *rhs ) + { + QSortContext_t *ctx = reinterpret_cast< QSortContext_t * >( g_pUtlSortVectorQSortContext ); + if ( ctx->m_pLessFunc->Less( *lhs, *rhs, ctx->m_pLessContext ) ) + return -1; + if ( ctx->m_pLessFunc->Less( *rhs, *lhs, ctx->m_pLessContext ) ) + return 1; + return 0; + } +#endif + + void *m_pLessContext; + bool m_bNeedsSort; + +private: + template< typename TKey > + int FindLessOrEqual( const TKey& search, bool *pFound ) const; + + void QuickSort( LessFunc& less, int X, int I ); +}; + + +//----------------------------------------------------------------------------- +// constructor +//----------------------------------------------------------------------------- +template <class T, class LessFunc, class BaseVector> +CUtlSortVector<T, LessFunc, BaseVector>::CUtlSortVector( int nGrowSize, int initSize ) : + m_pLessContext(NULL), BaseVector( nGrowSize, initSize ), m_bNeedsSort( false ) +{ +} + +template <class T, class LessFunc, class BaseVector> +CUtlSortVector<T, LessFunc, BaseVector>::CUtlSortVector( T* pMemory, int numElements ) : + m_pLessContext(NULL), BaseVector( pMemory, numElements ), m_bNeedsSort( false ) +{ +} + +//----------------------------------------------------------------------------- +// Allows methods to set a context to be used with the less function.. +//----------------------------------------------------------------------------- +template <class T, class LessFunc, class BaseVector> +void CUtlSortVector<T, LessFunc, BaseVector>::SetLessContext( void *pCtx ) +{ + m_pLessContext = pCtx; +} + +//----------------------------------------------------------------------------- +// grows the vector +//----------------------------------------------------------------------------- +template <class T, class LessFunc, class BaseVector> +int CUtlSortVector<T, LessFunc, BaseVector>::Insert( const T& src ) +{ + AssertFatal( !m_bNeedsSort ); + + int pos = FindLessOrEqual( src ) + 1; + this->GrowVector(); + this->ShiftElementsRight(pos); + CopyConstruct<T>( &this->Element(pos), src ); + return pos; +} + +template <class T, class LessFunc, class BaseVector> +int CUtlSortVector<T, LessFunc, BaseVector>::InsertNoSort( const T& src ) +{ + m_bNeedsSort = true; + int lastElement = BaseVector::m_Size; + // Just stick the new element at the end of the vector, but don't do a sort + this->GrowVector(); + this->ShiftElementsRight(lastElement); + CopyConstruct( &this->Element(lastElement), src ); + return lastElement; +} + +/// inserts (copy constructs) an element in sorted order into the list if it isn't already in the list +template <class T, class LessFunc, class BaseVector> +int CUtlSortVector<T, LessFunc, BaseVector>::InsertIfNotFound( const T& src ) +{ + AssertFatal( !m_bNeedsSort ); + bool bFound; + int pos = FindLessOrEqual( src, &bFound ); + if ( bFound ) + return pos; + + ++pos; + this->GrowVector(); + this->ShiftElementsRight(pos); + CopyConstruct<T>( &this->Element(pos), src ); + return pos; +} + +template <class T, class LessFunc, class BaseVector> +int CUtlSortVector<T, LessFunc, BaseVector>::InsertAfter( int nIndex, const T &src ) +{ + int nInsertedIndex = this->BaseClass::InsertAfter( nIndex, src ); + +#ifdef DEBUG + LessFunc less; + if ( nInsertedIndex > 0 ) + { + Assert( less.Less( this->Element(nInsertedIndex-1), src, m_pLessContext ) ); + } + if ( nInsertedIndex < BaseClass::Count()-1 ) + { + Assert( less.Less( src, this->Element(nInsertedIndex+1), m_pLessContext ) ); + } +#endif + return nInsertedIndex; +} + + +template <class T, class LessFunc, class BaseVector> +void CUtlSortVector<T, LessFunc, BaseVector>::QuickSort( LessFunc& less, int nLower, int nUpper ) +{ +#ifdef _WIN32 + typedef int (__cdecl *QSortCompareFunc_t)(void *context, const void *, const void *); + if ( this->Count() > 1 ) + { + QSortContext_t ctx; + ctx.m_pLessContext = m_pLessContext; + ctx.m_pLessFunc = &less; + + qsort_s( Base(), Count(), sizeof(T), (QSortCompareFunc_t)&CUtlSortVector<T, LessFunc>::CompareHelper, &ctx ); + } +#else + typedef int (__cdecl *QSortCompareFunc_t)( const void *, const void *); + if ( this->Count() > 1 ) + { + QSortContext_t ctx; + ctx.m_pLessContext = m_pLessContext; + ctx.m_pLessFunc = &less; + g_pUtlSortVectorQSortContext = &ctx; + + qsort( this->Base(), this->Count(), sizeof(T), (QSortCompareFunc_t)&CUtlSortVector<T, LessFunc>::CompareHelper ); + } +#endif +} + +template <class T, class LessFunc, class BaseVector> +void CUtlSortVector<T, LessFunc, BaseVector>::RedoSort( bool bForceSort /*= false */ ) +{ + if ( !m_bNeedsSort && !bForceSort ) + return; + + m_bNeedsSort = false; + LessFunc less; + QuickSort( less, 0, this->Count() - 1 ); +} + +//----------------------------------------------------------------------------- +// finds a particular element +//----------------------------------------------------------------------------- +template <class T, class LessFunc, class BaseVector> +template < typename TKey > +int CUtlSortVector<T, LessFunc, BaseVector>::Find( const TKey& src ) const +{ + AssertFatal( !m_bNeedsSort ); + + LessFunc less; + + int start = 0, end = this->Count() - 1; + while (start <= end) + { + int mid = (start + end) >> 1; + if ( less.Less( this->Element(mid), src, m_pLessContext ) ) + { + start = mid + 1; + } + else if ( less.Less( src, this->Element(mid), m_pLessContext ) ) + { + end = mid - 1; + } + else + { + return mid; + } + } + return -1; +} + + +//----------------------------------------------------------------------------- +// finds a particular element using a linear search. Useful when used +// in between calls to InsertNoSort and RedoSort +//----------------------------------------------------------------------------- +template< class T, class LessFunc, class BaseVector > +template < typename TKey > +int CUtlSortVector<T, LessFunc, BaseVector>::FindUnsorted( const TKey &src ) const +{ + LessFunc less; + int nCount = this->Count(); + for ( int i = 0; i < nCount; ++i ) + { + if ( less.Less( this->Element(i), src, m_pLessContext ) ) + continue; + if ( less.Less( src, this->Element(i), m_pLessContext ) ) + continue; + return i; + } + return -1; +} + + +//----------------------------------------------------------------------------- +// finds a particular element +//----------------------------------------------------------------------------- +template <class T, class LessFunc, class BaseVector> +template < typename TKey > +int CUtlSortVector<T, LessFunc, BaseVector>::FindLessOrEqual( const TKey& src, bool *pFound ) const +{ + AssertFatal( !m_bNeedsSort ); + + LessFunc less; + int start = 0, end = this->Count() - 1; + while (start <= end) + { + int mid = (start + end) >> 1; + if ( less.Less( this->Element(mid), src, m_pLessContext ) ) + { + start = mid + 1; + } + else if ( less.Less( src, this->Element(mid), m_pLessContext ) ) + { + end = mid - 1; + } + else + { + *pFound = true; + return mid; + } + } + + *pFound = false; + return end; +} + +template <class T, class LessFunc, class BaseVector> +template < typename TKey > +int CUtlSortVector<T, LessFunc, BaseVector>::FindLessOrEqual( const TKey& src ) const +{ + bool bFound; + return FindLessOrEqual( src, &bFound ); +} + +template <class T, class LessFunc, class BaseVector> +template < typename TKey > +int CUtlSortVector<T, LessFunc, BaseVector>::FindLess( const TKey& src ) const +{ + AssertFatal( !m_bNeedsSort ); + + LessFunc less; + int start = 0, end = this->Count() - 1; + while (start <= end) + { + int mid = (start + end) >> 1; + if ( less.Less( this->Element(mid), src, m_pLessContext ) ) + { + start = mid + 1; + } + else + { + end = mid - 1; + } + } + return end; +} + + +//----------------------------------------------------------------------------- +// Removes a particular element +//----------------------------------------------------------------------------- +template <class T, class LessFunc, class BaseVector> +void CUtlSortVector<T, LessFunc, BaseVector>::Remove( const T& search ) +{ + AssertFatal( !m_bNeedsSort ); + + int pos = Find(search); + if (pos != -1) + { + BaseVector::Remove(pos); + } +} + +template <class T, class LessFunc, class BaseVector> +void CUtlSortVector<T, LessFunc, BaseVector>::Remove( int i ) +{ + BaseVector::Remove( i ); +} + +#endif // UTLSORTVECTOR_H |