Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

414 lines
12 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // $Header: $
  4. // $NoKeywords: $
  5. //
  6. // A growable array class that keeps all elements in order using binary search
  7. //===========================================================================//
  8. #ifndef UTLSORTVECTOR_H
  9. #define UTLSORTVECTOR_H
  10. #ifdef _WIN32
  11. #pragma once
  12. #endif
  13. #include "utlvector.h"
  14. //-----------------------------------------------------------------------------
  15. // class CUtlSortVector:
  16. // description:
  17. // This in an sorted order-preserving vector. Items may be inserted or removed
  18. // at any point in the vector. When an item is inserted, all elements are
  19. // moved down by one element using memmove. When an item is removed, all
  20. // elements are shifted back down. Items are searched for in the vector
  21. // using a binary search technique. Clients must pass in a Less() function
  22. // into the constructor of the vector to determine the sort order.
  23. //-----------------------------------------------------------------------------
  24. #ifndef _WIN32
  25. // 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
  26. extern void *g_pUtlSortVectorQSortContext;
  27. #endif
  28. template <class T>
  29. class CUtlSortVectorDefaultLess
  30. {
  31. public:
  32. bool Less( const T& lhs, const T& rhs, void * )
  33. {
  34. return lhs < rhs;
  35. }
  36. };
  37. template <class T, class LessFunc = CUtlSortVectorDefaultLess<T>, class BaseVector = CUtlVector<T> >
  38. class CUtlSortVector : public BaseVector
  39. {
  40. typedef BaseVector BaseClass;
  41. public:
  42. /// constructor
  43. CUtlSortVector( int nGrowSize = 0, int initSize = 0 );
  44. CUtlSortVector( T* pMemory, int numElements );
  45. /// inserts (copy constructs) an element in sorted order into the list
  46. int Insert( const T& src );
  47. /// inserts (copy constructs) an element in sorted order into the list if it isn't already in the list
  48. int InsertIfNotFound( const T& src );
  49. /// Finds an element within the list using a binary search. These are templatized based upon the key
  50. /// in which case the less function must handle the Less function for key, T and T, key
  51. template< typename TKey >
  52. int Find( const TKey& search ) const;
  53. template< typename TKey >
  54. int FindLessOrEqual( const TKey& search ) const;
  55. template< typename TKey >
  56. int FindLess( const TKey& search ) const;
  57. /// Removes a particular element
  58. void Remove( const T& search );
  59. void Remove( int i );
  60. /// Allows methods to set a context to be used with the less function..
  61. void SetLessContext( void *pCtx );
  62. /// A version of insertion that will produce an un-ordered list.
  63. /// Note that you can only use this index until sorting is redone with RedoSort!!!
  64. int InsertNoSort( const T& src );
  65. void RedoSort( bool bForceSort = false );
  66. /// Use this to insert at a specific insertion point; using FindLessOrEqual
  67. /// is required for use this this. This will test that what you've inserted
  68. /// produces a correctly ordered list.
  69. int InsertAfter( int nElemIndex, const T &src );
  70. /// finds a particular element using a linear search. Useful when used
  71. /// in between calls to InsertNoSort and RedoSort
  72. template< typename TKey >
  73. int FindUnsorted( const TKey &src ) const;
  74. protected:
  75. // No copy constructor
  76. CUtlSortVector( const CUtlSortVector<T, LessFunc> & );
  77. // never call these; illegal for this class
  78. int AddToHead();
  79. int AddToTail();
  80. int InsertBefore( int elem );
  81. int InsertAfter( int elem );
  82. int InsertBefore( int elem, const T& src );
  83. int AddToHead( const T& src );
  84. int AddToTail( const T& src );
  85. int AddMultipleToHead( int num );
  86. int AddMultipleToTail( int num, const T *pToCopy=NULL );
  87. int InsertMultipleBefore( int elem, int num, const T *pToCopy=NULL );
  88. int InsertMultipleAfter( int elem, int num );
  89. int AddVectorToTail( CUtlVector<T> const &src );
  90. struct QSortContext_t
  91. {
  92. void *m_pLessContext;
  93. LessFunc *m_pLessFunc;
  94. };
  95. #ifdef _WIN32
  96. static int CompareHelper( void *context, const T *lhs, const T *rhs )
  97. {
  98. QSortContext_t *ctx = reinterpret_cast< QSortContext_t * >( context );
  99. if ( ctx->m_pLessFunc->Less( *lhs, *rhs, ctx->m_pLessContext ) )
  100. return -1;
  101. if ( ctx->m_pLessFunc->Less( *rhs, *lhs, ctx->m_pLessContext ) )
  102. return 1;
  103. return 0;
  104. }
  105. #else
  106. static int CompareHelper( const T *lhs, const T *rhs )
  107. {
  108. QSortContext_t *ctx = reinterpret_cast< QSortContext_t * >( g_pUtlSortVectorQSortContext );
  109. if ( ctx->m_pLessFunc->Less( *lhs, *rhs, ctx->m_pLessContext ) )
  110. return -1;
  111. if ( ctx->m_pLessFunc->Less( *rhs, *lhs, ctx->m_pLessContext ) )
  112. return 1;
  113. return 0;
  114. }
  115. #endif
  116. void *m_pLessContext;
  117. bool m_bNeedsSort;
  118. private:
  119. template< typename TKey >
  120. int FindLessOrEqual( const TKey& search, bool *pFound ) const;
  121. void QuickSort( LessFunc& less, int X, int I );
  122. };
  123. //-----------------------------------------------------------------------------
  124. // constructor
  125. //-----------------------------------------------------------------------------
  126. template <class T, class LessFunc, class BaseVector>
  127. CUtlSortVector<T, LessFunc, BaseVector>::CUtlSortVector( int nGrowSize, int initSize ) :
  128. m_pLessContext(NULL), BaseVector( nGrowSize, initSize ), m_bNeedsSort( false )
  129. {
  130. }
  131. template <class T, class LessFunc, class BaseVector>
  132. CUtlSortVector<T, LessFunc, BaseVector>::CUtlSortVector( T* pMemory, int numElements ) :
  133. m_pLessContext(NULL), BaseVector( pMemory, numElements ), m_bNeedsSort( false )
  134. {
  135. }
  136. //-----------------------------------------------------------------------------
  137. // Allows methods to set a context to be used with the less function..
  138. //-----------------------------------------------------------------------------
  139. template <class T, class LessFunc, class BaseVector>
  140. void CUtlSortVector<T, LessFunc, BaseVector>::SetLessContext( void *pCtx )
  141. {
  142. m_pLessContext = pCtx;
  143. }
  144. //-----------------------------------------------------------------------------
  145. // grows the vector
  146. //-----------------------------------------------------------------------------
  147. template <class T, class LessFunc, class BaseVector>
  148. int CUtlSortVector<T, LessFunc, BaseVector>::Insert( const T& src )
  149. {
  150. AssertFatal( !m_bNeedsSort );
  151. int pos = FindLessOrEqual( src ) + 1;
  152. this->GrowVector();
  153. this->ShiftElementsRight(pos);
  154. CopyConstruct<T>( &this->Element(pos), src );
  155. return pos;
  156. }
  157. template <class T, class LessFunc, class BaseVector>
  158. int CUtlSortVector<T, LessFunc, BaseVector>::InsertNoSort( const T& src )
  159. {
  160. m_bNeedsSort = true;
  161. int lastElement = BaseVector::m_Size;
  162. // Just stick the new element at the end of the vector, but don't do a sort
  163. this->GrowVector();
  164. this->ShiftElementsRight(lastElement);
  165. CopyConstruct( &this->Element(lastElement), src );
  166. return lastElement;
  167. }
  168. /// inserts (copy constructs) an element in sorted order into the list if it isn't already in the list
  169. template <class T, class LessFunc, class BaseVector>
  170. int CUtlSortVector<T, LessFunc, BaseVector>::InsertIfNotFound( const T& src )
  171. {
  172. AssertFatal( !m_bNeedsSort );
  173. bool bFound;
  174. int pos = FindLessOrEqual( src, &bFound );
  175. if ( bFound )
  176. return pos;
  177. ++pos;
  178. this->GrowVector();
  179. this->ShiftElementsRight(pos);
  180. CopyConstruct<T>( &this->Element(pos), src );
  181. return pos;
  182. }
  183. template <class T, class LessFunc, class BaseVector>
  184. int CUtlSortVector<T, LessFunc, BaseVector>::InsertAfter( int nIndex, const T &src )
  185. {
  186. int nInsertedIndex = this->BaseClass::InsertAfter( nIndex, src );
  187. #ifdef DEBUG
  188. LessFunc less;
  189. if ( nInsertedIndex > 0 )
  190. {
  191. Assert( less.Less( this->Element(nInsertedIndex-1), src, m_pLessContext ) );
  192. }
  193. if ( nInsertedIndex < BaseClass::Count()-1 )
  194. {
  195. Assert( less.Less( src, this->Element(nInsertedIndex+1), m_pLessContext ) );
  196. }
  197. #endif
  198. return nInsertedIndex;
  199. }
  200. template <class T, class LessFunc, class BaseVector>
  201. void CUtlSortVector<T, LessFunc, BaseVector>::QuickSort( LessFunc& less, int nLower, int nUpper )
  202. {
  203. #ifdef _WIN32
  204. typedef int (__cdecl *QSortCompareFunc_t)(void *context, const void *, const void *);
  205. if ( this->Count() > 1 )
  206. {
  207. QSortContext_t ctx;
  208. ctx.m_pLessContext = m_pLessContext;
  209. ctx.m_pLessFunc = &less;
  210. qsort_s( Base(), Count(), sizeof(T), (QSortCompareFunc_t)&CUtlSortVector<T, LessFunc>::CompareHelper, &ctx );
  211. }
  212. #else
  213. typedef int (__cdecl *QSortCompareFunc_t)( const void *, const void *);
  214. if ( this->Count() > 1 )
  215. {
  216. QSortContext_t ctx;
  217. ctx.m_pLessContext = m_pLessContext;
  218. ctx.m_pLessFunc = &less;
  219. g_pUtlSortVectorQSortContext = &ctx;
  220. qsort( this->Base(), this->Count(), sizeof(T), (QSortCompareFunc_t)&CUtlSortVector<T, LessFunc>::CompareHelper );
  221. }
  222. #endif
  223. }
  224. template <class T, class LessFunc, class BaseVector>
  225. void CUtlSortVector<T, LessFunc, BaseVector>::RedoSort( bool bForceSort /*= false */ )
  226. {
  227. if ( !m_bNeedsSort && !bForceSort )
  228. return;
  229. m_bNeedsSort = false;
  230. LessFunc less;
  231. QuickSort( less, 0, this->Count() - 1 );
  232. }
  233. //-----------------------------------------------------------------------------
  234. // finds a particular element
  235. //-----------------------------------------------------------------------------
  236. template <class T, class LessFunc, class BaseVector>
  237. template < typename TKey >
  238. int CUtlSortVector<T, LessFunc, BaseVector>::Find( const TKey& src ) const
  239. {
  240. AssertFatal( !m_bNeedsSort );
  241. LessFunc less;
  242. int start = 0, end = this->Count() - 1;
  243. while (start <= end)
  244. {
  245. int mid = (start + end) >> 1;
  246. if ( less.Less( this->Element(mid), src, m_pLessContext ) )
  247. {
  248. start = mid + 1;
  249. }
  250. else if ( less.Less( src, this->Element(mid), m_pLessContext ) )
  251. {
  252. end = mid - 1;
  253. }
  254. else
  255. {
  256. return mid;
  257. }
  258. }
  259. return -1;
  260. }
  261. //-----------------------------------------------------------------------------
  262. // finds a particular element using a linear search. Useful when used
  263. // in between calls to InsertNoSort and RedoSort
  264. //-----------------------------------------------------------------------------
  265. template< class T, class LessFunc, class BaseVector >
  266. template < typename TKey >
  267. int CUtlSortVector<T, LessFunc, BaseVector>::FindUnsorted( const TKey &src ) const
  268. {
  269. LessFunc less;
  270. int nCount = this->Count();
  271. for ( int i = 0; i < nCount; ++i )
  272. {
  273. if ( less.Less( this->Element(i), src, m_pLessContext ) )
  274. continue;
  275. if ( less.Less( src, this->Element(i), m_pLessContext ) )
  276. continue;
  277. return i;
  278. }
  279. return -1;
  280. }
  281. //-----------------------------------------------------------------------------
  282. // finds a particular element
  283. //-----------------------------------------------------------------------------
  284. template <class T, class LessFunc, class BaseVector>
  285. template < typename TKey >
  286. int CUtlSortVector<T, LessFunc, BaseVector>::FindLessOrEqual( const TKey& src, bool *pFound ) const
  287. {
  288. AssertFatal( !m_bNeedsSort );
  289. LessFunc less;
  290. int start = 0, end = this->Count() - 1;
  291. while (start <= end)
  292. {
  293. int mid = (start + end) >> 1;
  294. if ( less.Less( this->Element(mid), src, m_pLessContext ) )
  295. {
  296. start = mid + 1;
  297. }
  298. else if ( less.Less( src, this->Element(mid), m_pLessContext ) )
  299. {
  300. end = mid - 1;
  301. }
  302. else
  303. {
  304. *pFound = true;
  305. return mid;
  306. }
  307. }
  308. *pFound = false;
  309. return end;
  310. }
  311. template <class T, class LessFunc, class BaseVector>
  312. template < typename TKey >
  313. int CUtlSortVector<T, LessFunc, BaseVector>::FindLessOrEqual( const TKey& src ) const
  314. {
  315. bool bFound;
  316. return FindLessOrEqual( src, &bFound );
  317. }
  318. template <class T, class LessFunc, class BaseVector>
  319. template < typename TKey >
  320. int CUtlSortVector<T, LessFunc, BaseVector>::FindLess( const TKey& src ) const
  321. {
  322. AssertFatal( !m_bNeedsSort );
  323. LessFunc less;
  324. int start = 0, end = this->Count() - 1;
  325. while (start <= end)
  326. {
  327. int mid = (start + end) >> 1;
  328. if ( less.Less( this->Element(mid), src, m_pLessContext ) )
  329. {
  330. start = mid + 1;
  331. }
  332. else
  333. {
  334. end = mid - 1;
  335. }
  336. }
  337. return end;
  338. }
  339. //-----------------------------------------------------------------------------
  340. // Removes a particular element
  341. //-----------------------------------------------------------------------------
  342. template <class T, class LessFunc, class BaseVector>
  343. void CUtlSortVector<T, LessFunc, BaseVector>::Remove( const T& search )
  344. {
  345. AssertFatal( !m_bNeedsSort );
  346. int pos = Find(search);
  347. if (pos != -1)
  348. {
  349. BaseVector::Remove(pos);
  350. }
  351. }
  352. template <class T, class LessFunc, class BaseVector>
  353. void CUtlSortVector<T, LessFunc, BaseVector>::Remove( int i )
  354. {
  355. BaseVector::Remove( i );
  356. }
  357. #endif // UTLSORTVECTOR_H