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.

773 lines
20 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Multiple linked list container class
  4. //
  5. // $Revision: $
  6. // $NoKeywords: $
  7. //=============================================================================//
  8. #ifndef UTLMULTILIST_H
  9. #define UTLMULTILIST_H
  10. #ifdef _WIN32
  11. #pragma once
  12. #endif
  13. #include "utllinkedlist.h"
  14. // memdbgon must be the last include file in a .h file!!!
  15. #include "tier0/memdbgon.h"
  16. //-----------------------------------------------------------------------------
  17. // class CUtlMultiList:
  18. // description:
  19. // A lovely index-based linked list! T is the class type, I is the index
  20. // type, which usually should be an unsigned short or smaller.
  21. // This list can contain multiple lists
  22. //-----------------------------------------------------------------------------
  23. template <class T, class I>
  24. class CUtlMultiList
  25. {
  26. protected:
  27. // What the linked list element looks like
  28. struct ListElem_t
  29. {
  30. T m_Element;
  31. I m_Previous;
  32. I m_Next;
  33. };
  34. struct List_t
  35. {
  36. I m_Head;
  37. I m_Tail;
  38. I m_Count;
  39. };
  40. typedef CUtlMemory<ListElem_t> M; // Keep naming similar to CUtlLinkedList
  41. public:
  42. typedef I ListHandle_t;
  43. // constructor, destructor
  44. CUtlMultiList( int growSize = 0, int initSize = 0 );
  45. CUtlMultiList( void *pMemory, int memsize );
  46. ~CUtlMultiList( );
  47. // gets particular elements
  48. T& Element( I i );
  49. T const& Element( I i ) const;
  50. T& operator[]( I i );
  51. T const& operator[]( I i ) const;
  52. // Make sure we have a particular amount of memory
  53. void EnsureCapacity( int num );
  54. // Memory deallocation
  55. void Purge();
  56. // List Creation/deletion
  57. ListHandle_t CreateList();
  58. void DestroyList( ListHandle_t list );
  59. bool IsValidList( ListHandle_t list ) const;
  60. // Insertion methods (call default constructor)....
  61. I InsertBefore( ListHandle_t list, I before );
  62. I InsertAfter( ListHandle_t list, I after );
  63. I AddToHead( ListHandle_t list );
  64. I AddToTail( ListHandle_t list );
  65. // Insertion methods (call copy constructor)....
  66. I InsertBefore( ListHandle_t list, I before, T const& src );
  67. I InsertAfter( ListHandle_t list, I after, T const& src );
  68. I AddToHead( ListHandle_t list, T const& src );
  69. I AddToTail( ListHandle_t list, T const& src );
  70. // Removal methods
  71. void Remove( ListHandle_t list, I elem );
  72. // Removes all items in a single list
  73. void RemoveAll( ListHandle_t list );
  74. // Removes all items in all lists
  75. void RemoveAll();
  76. // Allocation/deallocation methods
  77. // NOTE: To free, it must *not* be in a list!
  78. I Alloc( );
  79. void Free( I elem );
  80. // list modification
  81. void LinkBefore( ListHandle_t list, I before, I elem );
  82. void LinkAfter( ListHandle_t list, I after, I elem );
  83. void Unlink( ListHandle_t list, I elem );
  84. void LinkToHead( ListHandle_t list, I elem );
  85. void LinkToTail( ListHandle_t list, I elem );
  86. // invalid index
  87. static I InvalidIndex() { return (I)~0; }
  88. static bool IndexInRange( int index );
  89. static size_t ElementSize() { return sizeof(ListElem_t); }
  90. // list statistics
  91. int Count( ListHandle_t list ) const;
  92. int TotalCount( ) const;
  93. I MaxElementIndex() const;
  94. // Traversing the list
  95. I Head( ListHandle_t list ) const;
  96. I Tail( ListHandle_t list ) const;
  97. I Previous( I element ) const;
  98. I Next( I element ) const;
  99. // Are nodes in a list or valid?
  100. bool IsValidIndex( I i ) const;
  101. bool IsInList( I i ) const;
  102. protected:
  103. // constructs the class
  104. void ConstructList( );
  105. // Gets at the list element....
  106. ListElem_t& InternalElement( I i ) { return m_Memory[i]; }
  107. ListElem_t const& InternalElement( I i ) const { return m_Memory[i]; }
  108. // A test for debug mode only...
  109. bool IsElementInList( ListHandle_t list, I elem ) const;
  110. // copy constructors not allowed
  111. CUtlMultiList( CUtlMultiList<T, I> const& list ) { Assert(0); }
  112. M m_Memory;
  113. CUtlLinkedList<List_t, I> m_List;
  114. I* m_pElementList;
  115. I m_FirstFree;
  116. I m_TotalElements;
  117. int m_MaxElementIndex; // The number allocated (use int so we can catch overflow)
  118. void ResetDbgInfo()
  119. {
  120. m_pElements = m_Memory.Base();
  121. #ifdef _DEBUG
  122. // Allocate space for the element list (which list is each element in)
  123. if (m_Memory.NumAllocated() > 0)
  124. {
  125. if (!m_pElementList)
  126. {
  127. m_pElementList = (I*)malloc( m_Memory.NumAllocated() * sizeof(I) );
  128. }
  129. else
  130. {
  131. m_pElementList = (I*)realloc( m_pElementList, m_Memory.NumAllocated() * sizeof(I) );
  132. }
  133. }
  134. #endif
  135. }
  136. // For debugging purposes;
  137. // it's in release builds so this can be used in libraries correctly
  138. ListElem_t *m_pElements;
  139. };
  140. //-----------------------------------------------------------------------------
  141. // constructor, destructor
  142. //-----------------------------------------------------------------------------
  143. template <class T, class I>
  144. CUtlMultiList<T,I>::CUtlMultiList( int growSize, int initSize ) :
  145. m_Memory(growSize, initSize), m_pElementList(0)
  146. {
  147. ConstructList();
  148. }
  149. template <class T, class I>
  150. CUtlMultiList<T,I>::CUtlMultiList( void* pMemory, int memsize ) :
  151. m_Memory((ListElem_t *)pMemory, memsize/sizeof(ListElem_t)), m_pElementList(0)
  152. {
  153. ConstructList();
  154. }
  155. template <class T, class I>
  156. CUtlMultiList<T,I>::~CUtlMultiList( )
  157. {
  158. RemoveAll();
  159. if (m_pElementList)
  160. free(m_pElementList);
  161. }
  162. template <class T, class I>
  163. void CUtlMultiList<T,I>::ConstructList( )
  164. {
  165. m_FirstFree = InvalidIndex();
  166. m_TotalElements = 0;
  167. m_MaxElementIndex = 0;
  168. ResetDbgInfo();
  169. }
  170. //-----------------------------------------------------------------------------
  171. // gets particular elements
  172. //-----------------------------------------------------------------------------
  173. template <class T, class I>
  174. inline T& CUtlMultiList<T,I>::Element( I i )
  175. {
  176. return m_Memory[i].m_Element;
  177. }
  178. template <class T, class I>
  179. inline T const& CUtlMultiList<T,I>::Element( I i ) const
  180. {
  181. return m_Memory[i].m_Element;
  182. }
  183. template <class T, class I>
  184. inline T& CUtlMultiList<T,I>::operator[]( I i )
  185. {
  186. return m_Memory[i].m_Element;
  187. }
  188. template <class T, class I>
  189. inline T const& CUtlMultiList<T,I>::operator[]( I i ) const
  190. {
  191. return m_Memory[i].m_Element;
  192. }
  193. //-----------------------------------------------------------------------------
  194. // list creation/destruction
  195. //-----------------------------------------------------------------------------
  196. template <class T, class I>
  197. typename CUtlMultiList<T,I>::ListHandle_t CUtlMultiList<T,I>::CreateList()
  198. {
  199. ListHandle_t l = m_List.AddToTail();
  200. m_List[l].m_Head = m_List[l].m_Tail = InvalidIndex();
  201. m_List[l].m_Count = 0;
  202. return l;
  203. }
  204. template <class T, class I>
  205. void CUtlMultiList<T,I>::DestroyList( ListHandle_t list )
  206. {
  207. Assert( IsValidList(list) );
  208. RemoveAll( list );
  209. m_List.Remove(list);
  210. }
  211. template <class T, class I>
  212. bool CUtlMultiList<T,I>::IsValidList( ListHandle_t list ) const
  213. {
  214. return m_List.IsValidIndex(list);
  215. }
  216. //-----------------------------------------------------------------------------
  217. // list statistics
  218. //-----------------------------------------------------------------------------
  219. template <class T, class I>
  220. inline int CUtlMultiList<T,I>::TotalCount() const
  221. {
  222. return m_TotalElements;
  223. }
  224. template <class T, class I>
  225. inline int CUtlMultiList<T,I>::Count( ListHandle_t list ) const
  226. {
  227. Assert( IsValidList(list) );
  228. return m_List[list].m_Count;
  229. }
  230. template <class T, class I>
  231. inline I CUtlMultiList<T,I>::MaxElementIndex() const
  232. {
  233. return m_MaxElementIndex;
  234. }
  235. //-----------------------------------------------------------------------------
  236. // Traversing the list
  237. //-----------------------------------------------------------------------------
  238. template <class T, class I>
  239. inline I CUtlMultiList<T,I>::Head(ListHandle_t list) const
  240. {
  241. Assert( IsValidList(list) );
  242. return m_List[list].m_Head;
  243. }
  244. template <class T, class I>
  245. inline I CUtlMultiList<T,I>::Tail(ListHandle_t list) const
  246. {
  247. Assert( IsValidList(list) );
  248. return m_List[list].m_Tail;
  249. }
  250. template <class T, class I>
  251. inline I CUtlMultiList<T,I>::Previous( I i ) const
  252. {
  253. Assert( IsValidIndex(i) );
  254. return InternalElement(i).m_Previous;
  255. }
  256. template <class T, class I>
  257. inline I CUtlMultiList<T,I>::Next( I i ) const
  258. {
  259. Assert( IsValidIndex(i) );
  260. return InternalElement(i).m_Next;
  261. }
  262. //-----------------------------------------------------------------------------
  263. // Are nodes in the list or valid?
  264. //-----------------------------------------------------------------------------
  265. template <class T, class I>
  266. inline bool CUtlMultiList<T,I>::IndexInRange( int index ) // Static method
  267. {
  268. // Since I is not necessarily the type returned by M (int), we need to check that M returns
  269. // indices which are representable by I. A common case is 'I === unsigned short', in which case
  270. // case CUtlMemory will have 'InvalidIndex == (int)-1' (which casts to 65535 in I), and will
  271. // happily return elements at index 65535 and above.
  272. // Do a couple of static checks here: the invalid index should be (I)~0 given how we use m_MaxElementIndex,
  273. // and 'I' should be unsigned (to avoid signed arithmetic errors for plausibly exhaustible ranges).
  274. // These COMPILE_TIME_ASSERT checks need to be in individual scopes to avoid build breaks
  275. // on MacOS and Linux due to a gcc bug.
  276. { COMPILE_TIME_ASSERT( (I)M::INVALID_INDEX == (I)~0 ); }
  277. { COMPILE_TIME_ASSERT( ( sizeof(I) > 2 ) || ( ( (I)-1 ) > 0 ) ); }
  278. return ( ( (I)index == index ) && ( (I)index != InvalidIndex() ) );
  279. }
  280. template <class T, class I>
  281. inline bool CUtlMultiList<T,I>::IsValidIndex( I i ) const
  282. {
  283. // GCC warns if I is an unsigned type and we do a ">= 0" against it (since the comparison is always 0).
  284. // We get the warning even if we cast inside the expression. It only goes away if we assign to another variable.
  285. long x = i;
  286. return (i < m_MaxElementIndex) && (x >= 0) &&
  287. ((m_Memory[i].m_Previous != i) || (m_Memory[i].m_Next == i));
  288. }
  289. template <class T, class I>
  290. inline bool CUtlMultiList<T,I>::IsInList( I i ) const
  291. {
  292. // GCC warns if I is an unsigned type and we do a ">= 0" against it (since the comparison is always 0).
  293. // We get the warning even if we cast inside the expression. It only goes away if we assign to another variable.
  294. long x = i;
  295. return (i < m_MaxElementIndex) && (x >= 0) && (Previous(i) != i);
  296. }
  297. //-----------------------------------------------------------------------------
  298. // Makes sure we have enough memory allocated to store a requested # of elements
  299. //-----------------------------------------------------------------------------
  300. template< class T, class I >
  301. void CUtlMultiList<T, I>::EnsureCapacity( int num )
  302. {
  303. m_Memory.EnsureCapacity(num);
  304. ResetDbgInfo();
  305. }
  306. //-----------------------------------------------------------------------------
  307. // Deallocate memory
  308. //-----------------------------------------------------------------------------
  309. template <class T, class I>
  310. void CUtlMultiList<T,I>::Purge()
  311. {
  312. RemoveAll();
  313. m_List.Purge();
  314. m_Memory.Purge( );
  315. m_List.Purge();
  316. m_FirstFree = InvalidIndex();
  317. m_TotalElements = 0;
  318. m_MaxElementIndex = 0;
  319. ResetDbgInfo();
  320. }
  321. //-----------------------------------------------------------------------------
  322. // Node allocation/deallocation
  323. //-----------------------------------------------------------------------------
  324. template <class T, class I>
  325. I CUtlMultiList<T,I>::Alloc( )
  326. {
  327. I elem;
  328. if (m_FirstFree == InvalidIndex())
  329. {
  330. // We can overflow before the utlmemory overflows, since we have have I != int
  331. if ( !IndexInRange( m_MaxElementIndex ) )
  332. {
  333. // We rarely if ever handle alloc failure. Continuing leads to corruption.
  334. Error( "CUtlMultiList overflow! (exhausted index range)\n" );
  335. return InvalidIndex();
  336. }
  337. // Nothing in the free list; add.
  338. // Since nothing is in the free list, m_TotalElements == total # of elements
  339. // the list knows about.
  340. if (m_MaxElementIndex == m_Memory.NumAllocated())
  341. {
  342. m_Memory.Grow();
  343. ResetDbgInfo();
  344. if ( m_MaxElementIndex >= m_Memory.NumAllocated() )
  345. {
  346. // We rarely if ever handle alloc failure. Continuing leads to corruption.
  347. Error( "CUtlMultiList overflow! (exhausted memory allocator)\n" );
  348. return InvalidIndex();
  349. }
  350. }
  351. elem = (I)m_MaxElementIndex;
  352. ++m_MaxElementIndex;
  353. }
  354. else
  355. {
  356. elem = m_FirstFree;
  357. m_FirstFree = InternalElement(m_FirstFree).m_Next;
  358. }
  359. // Mark the element as not being in a list
  360. InternalElement(elem).m_Next = InternalElement(elem).m_Previous = elem;
  361. ++m_TotalElements;
  362. Construct( &Element(elem) );
  363. return elem;
  364. }
  365. template <class T, class I>
  366. void CUtlMultiList<T,I>::Free( I elem )
  367. {
  368. Assert( IsValidIndex(elem) && !IsInList(elem) );
  369. Destruct( &Element(elem) );
  370. InternalElement(elem).m_Next = m_FirstFree;
  371. m_FirstFree = elem;
  372. --m_TotalElements;
  373. }
  374. //-----------------------------------------------------------------------------
  375. // A test for debug mode only...
  376. //-----------------------------------------------------------------------------
  377. template <class T, class I>
  378. inline bool CUtlMultiList<T,I>::IsElementInList( ListHandle_t list, I elem ) const
  379. {
  380. if (!m_pElementList)
  381. return true;
  382. return m_pElementList[elem] == list;
  383. }
  384. //-----------------------------------------------------------------------------
  385. // list modification
  386. //-----------------------------------------------------------------------------
  387. template <class T, class I>
  388. void CUtlMultiList<T,I>::LinkBefore( ListHandle_t list, I before, I elem )
  389. {
  390. Assert( IsValidIndex(elem) && IsValidList(list) );
  391. // Unlink it if it's in the list at the moment
  392. Unlink(list, elem);
  393. ListElem_t& newElem = InternalElement(elem);
  394. // The element *after* our newly linked one is the one we linked before.
  395. newElem.m_Next = before;
  396. if (before == InvalidIndex())
  397. {
  398. // In this case, we're linking to the end of the list, so reset the tail
  399. newElem.m_Previous = m_List[list].m_Tail;
  400. m_List[list].m_Tail = elem;
  401. }
  402. else
  403. {
  404. // Here, we're not linking to the end. Set the prev pointer to point to
  405. // the element we're linking.
  406. Assert( IsInList(before) );
  407. ListElem_t& beforeElem = InternalElement(before);
  408. newElem.m_Previous = beforeElem.m_Previous;
  409. beforeElem.m_Previous = elem;
  410. }
  411. // Reset the head if we linked to the head of the list
  412. if (newElem.m_Previous == InvalidIndex())
  413. m_List[list].m_Head = elem;
  414. else
  415. InternalElement(newElem.m_Previous).m_Next = elem;
  416. // one more element baby
  417. ++m_List[list].m_Count;
  418. // Store the element into the list
  419. if (m_pElementList)
  420. m_pElementList[elem] = list;
  421. }
  422. template <class T, class I>
  423. void CUtlMultiList<T,I>::LinkAfter( ListHandle_t list, I after, I elem )
  424. {
  425. Assert( IsValidIndex(elem) );
  426. // Unlink it if it's in the list at the moment
  427. Unlink(list, elem);
  428. ListElem_t& newElem = InternalElement(elem);
  429. // The element *before* our newly linked one is the one we linked after
  430. newElem.m_Previous = after;
  431. if (after == InvalidIndex())
  432. {
  433. // In this case, we're linking to the head of the list, reset the head
  434. newElem.m_Next = m_List[list].m_Head;
  435. m_List[list].m_Head = elem;
  436. }
  437. else
  438. {
  439. // Here, we're not linking to the end. Set the next pointer to point to
  440. // the element we're linking.
  441. Assert( IsInList(after) );
  442. ListElem_t& afterElem = InternalElement(after);
  443. newElem.m_Next = afterElem.m_Next;
  444. afterElem.m_Next = elem;
  445. }
  446. // Reset the tail if we linked to the tail of the list
  447. if (newElem.m_Next == InvalidIndex())
  448. m_List[list].m_Tail = elem;
  449. else
  450. InternalElement(newElem.m_Next).m_Previous = elem;
  451. // one more element baby
  452. ++m_List[list].m_Count;
  453. // Store the element into the list
  454. if (m_pElementList)
  455. m_pElementList[elem] = list;
  456. }
  457. template <class T, class I>
  458. void CUtlMultiList<T,I>::Unlink( ListHandle_t list, I elem )
  459. {
  460. Assert( IsValidIndex(elem) && IsValidList(list) );
  461. if (IsInList(elem))
  462. {
  463. // Make sure the element is in the right list
  464. Assert( IsElementInList( list, elem ) );
  465. ListElem_t& oldElem = InternalElement(elem);
  466. // If we're the first guy, reset the head
  467. // otherwise, make our previous node's next pointer = our next
  468. if (oldElem.m_Previous != InvalidIndex())
  469. InternalElement(oldElem.m_Previous).m_Next = oldElem.m_Next;
  470. else
  471. m_List[list].m_Head = oldElem.m_Next;
  472. // If we're the last guy, reset the tail
  473. // otherwise, make our next node's prev pointer = our prev
  474. if (oldElem.m_Next != InvalidIndex())
  475. InternalElement(oldElem.m_Next).m_Previous = oldElem.m_Previous;
  476. else
  477. m_List[list].m_Tail = oldElem.m_Previous;
  478. // This marks this node as not in the list,
  479. // but not in the free list either
  480. oldElem.m_Previous = oldElem.m_Next = elem;
  481. // One less puppy
  482. --m_List[list].m_Count;
  483. // Store the element into the list
  484. if (m_pElementList)
  485. m_pElementList[elem] = m_List.InvalidIndex();
  486. }
  487. }
  488. template <class T, class I>
  489. inline void CUtlMultiList<T,I>::LinkToHead( ListHandle_t list, I elem )
  490. {
  491. LinkAfter( list, InvalidIndex(), elem );
  492. }
  493. template <class T, class I>
  494. inline void CUtlMultiList<T,I>::LinkToTail( ListHandle_t list, I elem )
  495. {
  496. LinkBefore( list, InvalidIndex(), elem );
  497. }
  498. //-----------------------------------------------------------------------------
  499. // Insertion methods; allocates and links (uses default constructor)
  500. //-----------------------------------------------------------------------------
  501. template <class T, class I>
  502. I CUtlMultiList<T,I>::InsertBefore( ListHandle_t list, I before )
  503. {
  504. // Make a new node
  505. I newNode = Alloc();
  506. if ( newNode == InvalidIndex() )
  507. return newNode;
  508. // Link it in
  509. LinkBefore( list, before, newNode );
  510. // Construct the data
  511. Construct( &Element(newNode) );
  512. return newNode;
  513. }
  514. template <class T, class I>
  515. I CUtlMultiList<T,I>::InsertAfter( ListHandle_t list, I after )
  516. {
  517. // Make a new node
  518. I newNode = Alloc();
  519. if ( newNode == InvalidIndex() )
  520. return newNode;
  521. // Link it in
  522. LinkAfter( list, after, newNode );
  523. // Construct the data
  524. Construct( &Element(newNode) );
  525. return newNode;
  526. }
  527. template <class T, class I>
  528. inline I CUtlMultiList<T,I>::AddToHead( ListHandle_t list )
  529. {
  530. return InsertAfter( list, InvalidIndex() );
  531. }
  532. template <class T, class I>
  533. inline I CUtlMultiList<T,I>::AddToTail( ListHandle_t list )
  534. {
  535. return InsertBefore( list, InvalidIndex() );
  536. }
  537. //-----------------------------------------------------------------------------
  538. // Insertion methods; allocates and links (uses copy constructor)
  539. //-----------------------------------------------------------------------------
  540. template <class T, class I>
  541. I CUtlMultiList<T,I>::InsertBefore( ListHandle_t list, I before, T const& src )
  542. {
  543. // Make a new node
  544. I newNode = Alloc();
  545. if ( newNode == InvalidIndex() )
  546. return newNode;
  547. // Link it in
  548. LinkBefore( list, before, newNode );
  549. // Construct the data
  550. CopyConstruct( &Element(newNode), src );
  551. return newNode;
  552. }
  553. template <class T, class I>
  554. I CUtlMultiList<T,I>::InsertAfter( ListHandle_t list, I after, T const& src )
  555. {
  556. // Make a new node
  557. I newNode = Alloc();
  558. if ( newNode == InvalidIndex() )
  559. return newNode;
  560. // Link it in
  561. LinkAfter( list, after, newNode );
  562. // Construct the data
  563. CopyConstruct( &Element(newNode), src );
  564. return newNode;
  565. }
  566. template <class T, class I>
  567. inline I CUtlMultiList<T,I>::AddToHead( ListHandle_t list, T const& src )
  568. {
  569. return InsertAfter( list, InvalidIndex(), src );
  570. }
  571. template <class T, class I>
  572. inline I CUtlMultiList<T,I>::AddToTail( ListHandle_t list, T const& src )
  573. {
  574. return InsertBefore( list, InvalidIndex(), src );
  575. }
  576. //-----------------------------------------------------------------------------
  577. // Removal methods
  578. //-----------------------------------------------------------------------------
  579. template <class T, class I>
  580. void CUtlMultiList<T,I>::Remove( ListHandle_t list, I elem )
  581. {
  582. if (IsInList(elem))
  583. Unlink(list, elem);
  584. Free( elem );
  585. }
  586. // Removes all items in a single list
  587. template <class T, class I>
  588. void CUtlMultiList<T,I>::RemoveAll( ListHandle_t list )
  589. {
  590. Assert( IsValidList(list) );
  591. I i = Head(list);
  592. I next;
  593. while( i != InvalidIndex() )
  594. {
  595. next = Next(i);
  596. Remove(list, i);
  597. i = next;
  598. }
  599. }
  600. template <class T, class I>
  601. void CUtlMultiList<T,I>::RemoveAll()
  602. {
  603. if (m_MaxElementIndex == 0)
  604. return;
  605. // Put everything into the free list
  606. I prev = InvalidIndex();
  607. for (int i = (int)m_MaxElementIndex; --i >= 0; )
  608. {
  609. // Invoke the destructor
  610. if (IsValidIndex((I)i))
  611. Destruct( &Element((I)i) );
  612. // next points to the next free list item
  613. InternalElement((I)i).m_Next = prev;
  614. // Indicates it's in the free list
  615. InternalElement((I)i).m_Previous = (I)i;
  616. prev = (I)i;
  617. }
  618. // First free points to the first element
  619. m_FirstFree = 0;
  620. // Clear everything else out
  621. for (I list = m_List.Head(); list != m_List.InvalidIndex(); list = m_List.Next(list) )
  622. {
  623. m_List[list].m_Head = InvalidIndex();
  624. m_List[list].m_Tail = InvalidIndex();
  625. m_List[list].m_Count = 0;
  626. }
  627. m_TotalElements = 0;
  628. }
  629. #include "tier0/memdbgoff.h"
  630. #endif // UTLMULTILIST_H