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.

551 lines
13 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #ifndef UTLQUEUE_H
  8. #define UTLQUEUE_H
  9. #ifdef _WIN32
  10. #pragma once
  11. #endif
  12. #include "utlmemory.h"
  13. //#define TEST_UTLQUEUE
  14. enum QueueIter_t { QUEUE_ITERATOR_INVALID = 0xffffffff };
  15. // T is the type stored in the queue
  16. template< class T, class M = CUtlMemory< T > >
  17. class CUtlQueue
  18. {
  19. public:
  20. CUtlQueue( int growSize = 0, int initSize = 0 );
  21. CUtlQueue( T *pMemory, int numElements );
  22. // return the item from the front of the queue and delete it
  23. T RemoveAtHead();
  24. bool RemoveAtHead( T &removedElement );
  25. // return the item from the end of the queue and delete it
  26. T RemoveAtTail();
  27. bool RemoveAtTail( T &removedElement );
  28. // return item at the front of the queue
  29. T const& Head() const;
  30. // return item at the end of the queue
  31. T const& Tail() const;
  32. // Add a new item to the end of the queue
  33. void Insert( T const &element );
  34. // checks if an element of this value already exists on the stack, returns true if it does
  35. bool Check( T const element ) const;
  36. // iterators may be invalidated by Insert()
  37. QueueIter_t First() const;
  38. QueueIter_t Next( QueueIter_t it ) const;
  39. QueueIter_t Last() const;
  40. QueueIter_t Previous( QueueIter_t it ) const;
  41. bool IsValid( QueueIter_t it ) const;
  42. T const& Element( QueueIter_t it ) const;
  43. // Returns the count of elements in the queue
  44. int Count() const;
  45. // Return whether the queue is empty or not, faster than Count().
  46. bool IsEmpty() const;
  47. // doesn't deallocate memory
  48. void RemoveAll();
  49. // Memory deallocation
  50. void Purge();
  51. protected:
  52. QueueIter_t Next_Unchecked( QueueIter_t it ) const;
  53. QueueIter_t Previous_Unchecked( QueueIter_t it ) const;
  54. M m_memory;
  55. // if m_head == m_tail == QUEUE_ITERATOR_INVALID, then the queue is empty
  56. QueueIter_t m_head;
  57. QueueIter_t m_tail;
  58. #ifdef TEST_UTLQUEUE
  59. friend void CUtlQueue_Test();
  60. #endif
  61. };
  62. //-----------------------------------------------------------------------------
  63. // The CUtlQueueFixed class:
  64. // A queue class with a fixed allocation scheme
  65. //-----------------------------------------------------------------------------
  66. template< class T, size_t MAX_SIZE >
  67. class CUtlQueueFixed : public CUtlQueue< T, CUtlMemoryFixed<T, MAX_SIZE > >
  68. {
  69. typedef CUtlQueue< T, CUtlMemoryFixed<T, MAX_SIZE > > BaseClass;
  70. public:
  71. // constructor, destructor
  72. CUtlQueueFixed( int growSize = 0, int initSize = 0 ) : BaseClass( growSize, initSize ) {}
  73. CUtlQueueFixed( T* pMemory, int numElements ) : BaseClass( pMemory, numElements ) {}
  74. };
  75. template< class T, class M >
  76. inline CUtlQueue<T, M>::CUtlQueue( int growSize, int initSize ) :
  77. m_memory( growSize, initSize ), m_head( QUEUE_ITERATOR_INVALID ), m_tail( QUEUE_ITERATOR_INVALID )
  78. {
  79. }
  80. template< class T, class M >
  81. inline CUtlQueue<T, M>::CUtlQueue( T *pMemory, int numElements ) :
  82. m_memory( pMemory, numElements ), m_head( QUEUE_ITERATOR_INVALID ), m_tail( QUEUE_ITERATOR_INVALID )
  83. {
  84. }
  85. template <class T, class M>
  86. inline T CUtlQueue<T, M>::RemoveAtHead()
  87. {
  88. T temp;
  89. RemoveAtHead( temp );
  90. return temp;
  91. }
  92. template <class T, class M>
  93. inline bool CUtlQueue<T, M>::RemoveAtHead( T &removedElement )
  94. {
  95. Assert( m_head != QUEUE_ITERATOR_INVALID );
  96. if ( m_head == QUEUE_ITERATOR_INVALID )
  97. {
  98. Construct( &removedElement );
  99. return false;
  100. }
  101. QueueIter_t it = m_head;
  102. removedElement = m_memory[ it ];
  103. Destruct( &m_memory[ it ] );
  104. if ( m_head == m_tail )
  105. {
  106. m_head = m_tail = QUEUE_ITERATOR_INVALID;
  107. }
  108. else
  109. {
  110. m_head = Next_Unchecked( m_head );
  111. }
  112. return true;
  113. }
  114. template <class T, class M>
  115. inline T CUtlQueue<T, M>::RemoveAtTail()
  116. {
  117. T temp;
  118. RemoveAtTail( temp );
  119. return temp;
  120. }
  121. template <class T, class M>
  122. inline bool CUtlQueue<T, M>::RemoveAtTail( T &removedElement )
  123. {
  124. Assert( m_tail != QUEUE_ITERATOR_INVALID );
  125. if ( m_tail == QUEUE_ITERATOR_INVALID )
  126. {
  127. Construct( &removedElement );
  128. return false;
  129. }
  130. removedElement = m_memory[ m_tail ];
  131. Destruct( &m_memory[ m_tail ] );
  132. if ( m_head == m_tail )
  133. {
  134. m_head = m_tail = QUEUE_ITERATOR_INVALID;
  135. }
  136. else
  137. {
  138. m_tail = Previous_Unchecked( m_tail );
  139. }
  140. return true;
  141. }
  142. template <class T, class M>
  143. inline T const& CUtlQueue<T, M>::Head() const
  144. {
  145. Assert( m_head != QUEUE_ITERATOR_INVALID );
  146. if ( m_head == QUEUE_ITERATOR_INVALID )
  147. {
  148. static T dummy;
  149. return dummy;
  150. }
  151. return m_memory[ m_head ];
  152. }
  153. template <class T, class M>
  154. inline T const& CUtlQueue<T, M>::Tail() const
  155. {
  156. Assert( m_tail != QUEUE_ITERATOR_INVALID );
  157. if ( m_tail == QUEUE_ITERATOR_INVALID )
  158. {
  159. static T dummy;
  160. return dummy;
  161. }
  162. return m_memory[ m_tail ];
  163. }
  164. template <class T, class M>
  165. void CUtlQueue<T, M>::Insert( T const &element )
  166. {
  167. if ( m_tail == QUEUE_ITERATOR_INVALID )
  168. {
  169. // empty
  170. m_memory.EnsureCapacity( 1 );
  171. m_head = m_tail = QueueIter_t( 0 );
  172. }
  173. else
  174. {
  175. // non-empty
  176. QueueIter_t nextTail = Next_Unchecked( m_tail );
  177. if ( nextTail == m_head ) // if non-empty, and growing by 1 appears to make the queue of length 1, then we were already full before the Insert
  178. {
  179. int nOldAllocCount = m_memory.NumAllocated();
  180. m_memory.Grow();
  181. int nNewAllocCount = m_memory.NumAllocated();
  182. int nGrowAmount = nNewAllocCount - nOldAllocCount;
  183. nextTail = Next_Unchecked( m_tail ); // if nextTail was 0, then it now should be nOldAllocCount
  184. if ( m_head != QueueIter_t( 0 ) )
  185. {
  186. // if the queue wraps around the end of m_memory, move the part at the end of memory to the new end of memory
  187. Q_memmove( &m_memory[ m_head + nGrowAmount ], &m_memory[ m_head ], ( nOldAllocCount - m_head ) * sizeof( T ) );
  188. #ifdef _DEBUG
  189. Q_memset( &m_memory[ m_head ], 0xdd, nGrowAmount * sizeof( T ) );
  190. #endif
  191. m_head = QueueIter_t( m_head + nGrowAmount );
  192. }
  193. }
  194. m_tail = nextTail;
  195. }
  196. CopyConstruct( &m_memory[ m_tail ], element );
  197. }
  198. template <class T, class M>
  199. bool CUtlQueue<T, M>::Check( T const element ) const
  200. {
  201. for ( QueueIter_t it = First(); it != QUEUE_ITERATOR_INVALID; it = Next( it ) )
  202. {
  203. if ( m_memory[ it ] == element )
  204. return true;
  205. }
  206. return false;
  207. }
  208. template <class T, class M>
  209. QueueIter_t CUtlQueue<T, M>::First() const
  210. {
  211. return m_head;
  212. }
  213. template <class T, class M>
  214. QueueIter_t CUtlQueue<T, M>::Next( QueueIter_t it ) const
  215. {
  216. if ( it == QUEUE_ITERATOR_INVALID )
  217. return QUEUE_ITERATOR_INVALID;
  218. if ( it == m_tail )
  219. return QUEUE_ITERATOR_INVALID;
  220. Assert( IsValid( it ) );
  221. if ( !IsValid( it ) )
  222. return QUEUE_ITERATOR_INVALID;
  223. return Next_Unchecked( it );
  224. }
  225. template <class T, class M>
  226. QueueIter_t CUtlQueue<T, M>::Last() const
  227. {
  228. return m_tail;
  229. }
  230. template <class T, class M>
  231. QueueIter_t CUtlQueue<T, M>::Previous( QueueIter_t it ) const
  232. {
  233. if ( it == QUEUE_ITERATOR_INVALID )
  234. return QUEUE_ITERATOR_INVALID;
  235. if ( it == m_head )
  236. return QUEUE_ITERATOR_INVALID;
  237. Assert( IsValid( it ) );
  238. if ( !IsValid( it ) )
  239. return QUEUE_ITERATOR_INVALID;
  240. return Previous_Unchecked( it );
  241. }
  242. template <class T, class M>
  243. QueueIter_t CUtlQueue<T, M>::Next_Unchecked( QueueIter_t it ) const
  244. {
  245. return it == m_memory.Count() - 1 ? QueueIter_t( 0 ) : QueueIter_t( it + 1 );
  246. }
  247. template <class T, class M>
  248. QueueIter_t CUtlQueue<T, M>::Previous_Unchecked( QueueIter_t it ) const
  249. {
  250. return it == 0 ? QueueIter_t( m_memory.Count() - 1 ) : QueueIter_t( it - 1 );
  251. }
  252. template <class T, class M>
  253. bool CUtlQueue<T, M>::IsValid( QueueIter_t it ) const
  254. {
  255. if ( it == QUEUE_ITERATOR_INVALID )
  256. return false;
  257. if ( m_head == QUEUE_ITERATOR_INVALID )
  258. return false;
  259. if ( m_head <= m_tail )
  260. return it >= m_head && it <= m_tail;
  261. return ( it >= m_head && it < m_memory.Count() ) || ( it >= 0 && it <= m_tail );
  262. }
  263. template <class T, class M>
  264. T const& CUtlQueue<T, M>::Element( QueueIter_t it ) const
  265. {
  266. Assert( it != QUEUE_ITERATOR_INVALID );
  267. if ( it == QUEUE_ITERATOR_INVALID )
  268. {
  269. static T dummy;
  270. return dummy;
  271. }
  272. Assert( IsValid( it ) );
  273. return m_memory[ it ];
  274. }
  275. template <class T, class M>
  276. int CUtlQueue<T, M>::Count() const
  277. {
  278. if ( m_head == QUEUE_ITERATOR_INVALID )
  279. {
  280. Assert( m_tail == QUEUE_ITERATOR_INVALID );
  281. return 0;
  282. }
  283. Assert( m_tail != QUEUE_ITERATOR_INVALID );
  284. if ( m_head <= m_tail )
  285. return m_tail + 1 - m_head;
  286. return m_tail + 1 - m_head + m_memory.Count();
  287. }
  288. template <class T, class M>
  289. bool CUtlQueue<T, M>::IsEmpty() const
  290. {
  291. Assert( ( m_head == QUEUE_ITERATOR_INVALID ) == ( m_tail == QUEUE_ITERATOR_INVALID ) );
  292. return ( m_head == QUEUE_ITERATOR_INVALID );
  293. }
  294. template <class T, class M>
  295. void CUtlQueue<T, M>::RemoveAll()
  296. {
  297. m_head = m_tail = QUEUE_ITERATOR_INVALID;
  298. }
  299. template <class T, class M>
  300. void CUtlQueue<T, M>::Purge()
  301. {
  302. m_head = m_tail = QUEUE_ITERATOR_INVALID;
  303. m_memory.Purge();
  304. }
  305. #ifdef TEST_UTLQUEUE
  306. #include <stdlib.h>
  307. struct Data_t
  308. {
  309. Data_t( int i = 0xffffffff ) : m_id( i ) {}
  310. Data_t( const Data_t &that ) : m_id( that.m_id ) {}
  311. ~Data_t() { m_id = 0xdddddddd; }
  312. Data_t &operator=( const Data_t &that ) { m_id = that.m_id; return *this; }
  313. int m_id;
  314. };
  315. inline void CUtlQueue_Test()
  316. {
  317. CUtlQueue< Data_t > queue;
  318. for ( int n = 1; n < 100; ++n )
  319. {
  320. Assert( queue.Count() == 0 );
  321. Assert( queue.m_head == QUEUE_ITERATOR_INVALID );
  322. Assert( queue.m_tail == QUEUE_ITERATOR_INVALID );
  323. int w = rand() % n;
  324. for ( int i = 0; i < w; ++i )
  325. {
  326. queue.Insert( Data_t( i ) );
  327. }
  328. if ( w > 0 )
  329. {
  330. Assert( queue.Head().m_id == queue.First() );
  331. Assert( queue.Tail().m_id == queue.Last() );
  332. Assert( queue.Head().m_id == 0 );
  333. Assert( queue.Tail().m_id == w - 1 );
  334. }
  335. Assert( queue.Count() == w );
  336. for ( int j = 0; j < n; ++j )
  337. {
  338. queue.Insert( Data_t( w + j ) );
  339. if ( j == 0 )
  340. {
  341. Assert( queue.Count() == w + j + 1 );
  342. for ( int i = 0; i < w; ++i )
  343. {
  344. queue.RemoveAtHead();
  345. }
  346. }
  347. Assert( queue.Count() == j + 1 );
  348. Assert( queue.m_head != QUEUE_ITERATOR_INVALID );
  349. Assert( queue.m_tail != QUEUE_ITERATOR_INVALID );
  350. int id = queue.Head().m_id % queue.m_memory.Count();
  351. for ( QueueIter_t it = queue.First(); it != QUEUE_ITERATOR_INVALID; it = queue.Next( it ) )
  352. {
  353. Assert( queue.Element( it ).m_id % queue.m_memory.Count() == id );
  354. id = ( id + 1 ) % queue.m_memory.Count();
  355. }
  356. id = queue.Tail().m_id % queue.m_memory.Count();
  357. for ( QueueIter_t it = queue.Last(); it != QUEUE_ITERATOR_INVALID; it = queue.Previous( it ) )
  358. {
  359. Assert( queue.Element( it ).m_id % queue.m_memory.Count() == id );
  360. id = ( id + queue.m_memory.Count() - 1 ) % queue.m_memory.Count();
  361. }
  362. for ( int i = 0; i < j; ++i )
  363. {
  364. int id = queue.m_memory[ i ].m_id;
  365. if ( queue.IsValid( QueueIter_t( i ) ) )
  366. {
  367. Assert( ( id & 0xff000000 ) == 0 );
  368. }
  369. else
  370. {
  371. Assert( id == 0xdddddddd );
  372. }
  373. }
  374. }
  375. Assert( queue.Count() == n );
  376. #if 0
  377. for ( int j = 0; j < n; ++j )
  378. {
  379. Assert( queue.m_head != QUEUE_ITERATOR_INVALID );
  380. Assert( queue.m_tail != QUEUE_ITERATOR_INVALID );
  381. Assert( queue.Count() == n - j );
  382. Data_t data = queue.RemoveAtHead();
  383. Assert( queue.Count() == n - j - 1 );
  384. if ( queue.Count() > 0 )
  385. {
  386. int id = queue.Head().m_id % queue.m_memory.Count();
  387. for ( QueueIter_t it = queue.First(); it != QUEUE_ITERATOR_INVALID; it = queue.Next( it ) )
  388. {
  389. Assert( queue.Element( it ).m_id % queue.m_memory.Count() == id );
  390. id = ( id + 1 ) % queue.m_memory.Count();
  391. }
  392. id = queue.Tail().m_id % queue.m_memory.Count();
  393. for ( QueueIter_t it = queue.Last(); it != QUEUE_ITERATOR_INVALID; it = queue.Previous( it ) )
  394. {
  395. Assert( queue.Element( it ).m_id % queue.m_memory.Count() == id );
  396. id = ( id + queue.m_memory.Count() - 1 ) % queue.m_memory.Count();
  397. }
  398. }
  399. for ( int i = 0; i < j; ++i )
  400. {
  401. int id = queue.m_memory[ i ].m_id;
  402. if ( queue.IsValid( QueueIter_t( i ) ) )
  403. {
  404. Assert( ( id & 0xff000000 ) == 0 );
  405. }
  406. else
  407. {
  408. Assert( id == 0xdddddddd );
  409. }
  410. }
  411. }
  412. #else
  413. for ( int j = n - 1; j >= 0; --j )
  414. {
  415. Assert( queue.m_head != QUEUE_ITERATOR_INVALID );
  416. Assert( queue.m_tail != QUEUE_ITERATOR_INVALID );
  417. Assert( queue.Count() == j + 1 );
  418. Data_t data = queue.RemoveAtTail();
  419. Assert( queue.Count() == j );
  420. if ( queue.Count() > 0 )
  421. {
  422. int id = queue.Head().m_id % queue.m_memory.Count();
  423. for ( QueueIter_t it = queue.First(); it != QUEUE_ITERATOR_INVALID; it = queue.Next( it ) )
  424. {
  425. Assert( queue.Element( it ).m_id % queue.m_memory.Count() == id );
  426. id = ( id + 1 ) % queue.m_memory.Count();
  427. }
  428. id = queue.Tail().m_id % queue.m_memory.Count();
  429. for ( QueueIter_t it = queue.Last(); it != QUEUE_ITERATOR_INVALID; it = queue.Previous( it ) )
  430. {
  431. Assert( queue.Element( it ).m_id % queue.m_memory.Count() == id );
  432. id = ( id + queue.m_memory.Count() - 1 ) % queue.m_memory.Count();
  433. }
  434. }
  435. for ( int i = 0; i < j; ++i )
  436. {
  437. int id = queue.m_memory[ i ].m_id;
  438. if ( queue.IsValid( QueueIter_t( i ) ) )
  439. {
  440. Assert( ( id & 0xff000000 ) == 0 );
  441. }
  442. else
  443. {
  444. Assert( id == 0xdddddddd );
  445. }
  446. }
  447. }
  448. #endif
  449. Assert( queue.Count() == 0 );
  450. Assert( queue.m_head == QUEUE_ITERATOR_INVALID );
  451. Assert( queue.m_tail == QUEUE_ITERATOR_INVALID );
  452. }
  453. }
  454. #endif // TEST_UTLQUEUE
  455. #endif // UTLQUEUE_H