Counter Strike : Global Offensive Source Code
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.

447 lines
13 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. template <typename K>
  58. int FindAs( const K& key ) const;
  59. /// Removes a particular element
  60. void Remove( const T& search );
  61. void Remove( int i );
  62. /// Allows methods to set a context to be used with the less function..
  63. void SetLessContext( void *pCtx );
  64. /// A version of insertion that will produce an un-ordered list.
  65. /// Note that you can only use this index until sorting is redone with RedoSort!!!
  66. int InsertNoSort( const T& src );
  67. void RedoSort( bool bForceSort = false );
  68. /// Use this to insert at a specific insertion point; using FindLessOrEqual
  69. /// is required for use this this. This will test that what you've inserted
  70. /// produces a correctly ordered list.
  71. int InsertAfter( int nElemIndex, const T &src );
  72. /// finds a particular element using a linear search. Useful when used
  73. /// in between calls to InsertNoSort and RedoSort
  74. template< typename TKey >
  75. int FindUnsorted( const TKey &src ) const;
  76. protected:
  77. // No copy constructor
  78. CUtlSortVector( const CUtlSortVector<T, LessFunc> & );
  79. // never call these; illegal for this class
  80. int AddToHead();
  81. int AddToTail();
  82. int InsertBefore( int elem );
  83. int InsertAfter( int elem );
  84. int AddToHead( const T& src );
  85. int AddToTail( const T& src );
  86. int InsertBefore( int elem, const T& src );
  87. int AddMultipleToHead( int num );
  88. int AddMultipleToTail( int num, const T *pToCopy=NULL );
  89. int InsertMultipleBefore( int elem, int num, const T *pToCopy=NULL );
  90. int InsertMultipleAfter( int elem, int num );
  91. int AddVectorToTail( CUtlVector<T> const &src );
  92. struct QSortContext_t
  93. {
  94. void *m_pLessContext;
  95. LessFunc *m_pLessFunc;
  96. };
  97. #ifdef _WIN32
  98. static int CompareHelper( void *context, const T *lhs, const T *rhs )
  99. {
  100. QSortContext_t *ctx = reinterpret_cast< QSortContext_t * >( context );
  101. if ( ctx->m_pLessFunc->Less( *lhs, *rhs, ctx->m_pLessContext ) )
  102. return -1;
  103. if ( ctx->m_pLessFunc->Less( *rhs, *lhs, ctx->m_pLessContext ) )
  104. return 1;
  105. return 0;
  106. }
  107. #else
  108. static int CompareHelper( const T *lhs, const T *rhs )
  109. {
  110. QSortContext_t *ctx = reinterpret_cast< QSortContext_t * >( g_pUtlSortVectorQSortContext );
  111. if ( ctx->m_pLessFunc->Less( *lhs, *rhs, ctx->m_pLessContext ) )
  112. return -1;
  113. if ( ctx->m_pLessFunc->Less( *rhs, *lhs, ctx->m_pLessContext ) )
  114. return 1;
  115. return 0;
  116. }
  117. #endif
  118. void *m_pLessContext;
  119. bool m_bNeedsSort;
  120. private:
  121. template< typename TKey >
  122. int FindLessOrEqual( const TKey& search, bool *pFound ) const;
  123. void QuickSort( LessFunc& less, int X, int I );
  124. };
  125. //-----------------------------------------------------------------------------
  126. // constructor
  127. //-----------------------------------------------------------------------------
  128. template <class T, class LessFunc, class BaseVector>
  129. CUtlSortVector<T, LessFunc, BaseVector>::CUtlSortVector( int nGrowSize, int initSize ) :
  130. m_pLessContext(NULL), BaseVector( nGrowSize, initSize ), m_bNeedsSort( false )
  131. {
  132. }
  133. template <class T, class LessFunc, class BaseVector>
  134. CUtlSortVector<T, LessFunc, BaseVector>::CUtlSortVector( T* pMemory, int numElements ) :
  135. m_pLessContext(NULL), BaseVector( pMemory, numElements ), m_bNeedsSort( false )
  136. {
  137. }
  138. //-----------------------------------------------------------------------------
  139. // Allows methods to set a context to be used with the less function..
  140. //-----------------------------------------------------------------------------
  141. template <class T, class LessFunc, class BaseVector>
  142. void CUtlSortVector<T, LessFunc, BaseVector>::SetLessContext( void *pCtx )
  143. {
  144. m_pLessContext = pCtx;
  145. }
  146. //-----------------------------------------------------------------------------
  147. // grows the vector
  148. //-----------------------------------------------------------------------------
  149. template <class T, class LessFunc, class BaseVector>
  150. int CUtlSortVector<T, LessFunc, BaseVector>::Insert( const T& src )
  151. {
  152. AssertFatal( !m_bNeedsSort );
  153. int pos = FindLessOrEqual( src ) + 1;
  154. this->GrowVector();
  155. this->ShiftElementsRight(pos);
  156. CopyConstruct<T>( &this->Element(pos), src );
  157. return pos;
  158. }
  159. template <class T, class LessFunc, class BaseVector>
  160. int CUtlSortVector<T, LessFunc, BaseVector>::InsertNoSort( const T& src )
  161. {
  162. m_bNeedsSort = true;
  163. int lastElement = BaseVector::m_Size;
  164. // Just stick the new element at the end of the vector, but don't do a sort
  165. this->GrowVector();
  166. this->ShiftElementsRight(lastElement);
  167. CopyConstruct( &this->Element(lastElement), src );
  168. return lastElement;
  169. }
  170. /// inserts (copy constructs) an element in sorted order into the list if it isn't already in the list
  171. template <class T, class LessFunc, class BaseVector>
  172. int CUtlSortVector<T, LessFunc, BaseVector>::InsertIfNotFound( const T& src )
  173. {
  174. AssertFatal( !m_bNeedsSort );
  175. bool bFound;
  176. int pos = FindLessOrEqual( src, &bFound );
  177. if ( bFound )
  178. return pos;
  179. ++pos;
  180. BaseVector::InsertBefore( 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 = 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 K>
  286. int CUtlSortVector<T, LessFunc, BaseVector>::FindAs( const K& key ) 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. int nResult = less.Compare( this->Element(mid), key, m_pLessContext );
  295. if ( nResult < 0 )
  296. {
  297. start = mid + 1;
  298. }
  299. else if ( nResult > 0 )
  300. {
  301. end = mid - 1;
  302. }
  303. else
  304. {
  305. return mid;
  306. }
  307. }
  308. return -1;
  309. }
  310. //-----------------------------------------------------------------------------
  311. // finds a particular element
  312. //-----------------------------------------------------------------------------
  313. template <class T, class LessFunc, class BaseVector>
  314. template < typename TKey >
  315. int CUtlSortVector<T, LessFunc, BaseVector>::FindLessOrEqual( const TKey& src, bool *pFound ) const
  316. {
  317. AssertFatal( !m_bNeedsSort );
  318. LessFunc less;
  319. int start = 0, end = this->Count() - 1;
  320. while (start <= end)
  321. {
  322. int mid = (start + end) >> 1;
  323. if ( less.Less( this->Element(mid), src, m_pLessContext ) )
  324. {
  325. start = mid + 1;
  326. }
  327. else if ( less.Less( src, this->Element(mid), m_pLessContext ) )
  328. {
  329. end = mid - 1;
  330. }
  331. else
  332. {
  333. *pFound = true;
  334. return mid;
  335. }
  336. }
  337. *pFound = false;
  338. return end;
  339. }
  340. template <class T, class LessFunc, class BaseVector>
  341. template < typename TKey >
  342. int CUtlSortVector<T, LessFunc, BaseVector>::FindLessOrEqual( const TKey& src ) const
  343. {
  344. bool bFound;
  345. return FindLessOrEqual( src, &bFound );
  346. }
  347. template <class T, class LessFunc, class BaseVector>
  348. template < typename TKey >
  349. int CUtlSortVector<T, LessFunc, BaseVector>::FindLess( const TKey& src ) const
  350. {
  351. AssertFatal( !m_bNeedsSort );
  352. LessFunc less;
  353. int start = 0, end = this->Count() - 1;
  354. while (start <= end)
  355. {
  356. int mid = (start + end) >> 1;
  357. if ( less.Less( this->Element(mid), src, m_pLessContext ) )
  358. {
  359. start = mid + 1;
  360. }
  361. else
  362. {
  363. end = mid - 1;
  364. }
  365. }
  366. return end;
  367. }
  368. //-----------------------------------------------------------------------------
  369. // Removes a particular element
  370. //-----------------------------------------------------------------------------
  371. template <class T, class LessFunc, class BaseVector>
  372. void CUtlSortVector<T, LessFunc, BaseVector>::Remove( const T& search )
  373. {
  374. AssertFatal( !m_bNeedsSort );
  375. int pos = Find(search);
  376. if (pos != -1)
  377. {
  378. BaseVector::Remove(pos);
  379. }
  380. }
  381. template <class T, class LessFunc, class BaseVector>
  382. void CUtlSortVector<T, LessFunc, BaseVector>::Remove( int i )
  383. {
  384. BaseVector::Remove( i );
  385. }
  386. #endif // UTLSORTVECTOR_H