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.

1087 lines
28 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Linked list container class
  4. //
  5. // $Revision: $
  6. // $NoKeywords: $
  7. //=============================================================================//
  8. #ifndef UTLLINKEDLIST_H
  9. #define UTLLINKEDLIST_H
  10. #ifdef _WIN32
  11. #pragma once
  12. #endif
  13. #include "tier0/basetypes.h"
  14. #include "utlmemory.h"
  15. #include "utlfixedmemory.h"
  16. #include "utlblockmemory.h"
  17. #include "tier0/dbg.h"
  18. // define to enable asserts griping about things you shouldn't be doing with multilists
  19. // #define MULTILIST_PEDANTIC_ASSERTS 1
  20. // This is a useful macro to iterate from head to tail in a linked list.
  21. #define FOR_EACH_LL( listName, iteratorName ) \
  22. for( int iteratorName=listName.Head(); iteratorName != listName.InvalidIndex(); iteratorName = listName.Next( iteratorName ) )
  23. //-----------------------------------------------------------------------------
  24. // class CUtlLinkedList:
  25. // description:
  26. // A lovely index-based linked list! T is the class type, I is the index
  27. // type, which usually should be an unsigned short or smaller. However,
  28. // you must avoid using 16- or 8-bit arithmetic on PowerPC architectures;
  29. // therefore you should not use UtlLinkedListElem_t::I as the type of
  30. // a local variable... ever. PowerPC integer arithmetic must be 32- or
  31. // 64-bit only; otherwise performance plummets.
  32. //-----------------------------------------------------------------------------
  33. template <class T, class I>
  34. struct UtlLinkedListElem_t
  35. {
  36. T m_Element;
  37. I m_Previous;
  38. I m_Next;
  39. private:
  40. // No copy constructor for these...
  41. UtlLinkedListElem_t( const UtlLinkedListElem_t& );
  42. };
  43. // Class S is the storage type; the type you can use to save off indices in
  44. // persistent memory. Class I is the iterator type, which is what should be used
  45. // in local scopes. I defaults to be S, but be aware that on the 360, 16-bit
  46. // arithmetic is catastrophically slow. Therefore you should try to save shorts
  47. // in memory, but always operate on 32's or 64's in local scope.
  48. // The ideal parameter order would be TSMI (you are more likely to override M than I)
  49. // but since M depends on I we can't have the defaults in that order, alas.
  50. template <class T, class S = unsigned short, bool ML = false, class I = S, class M = CUtlMemory< UtlLinkedListElem_t<T, S>, I > >
  51. class CUtlLinkedList
  52. {
  53. public:
  54. typedef T ElemType_t;
  55. typedef S IndexType_t; // should really be called IndexStorageType_t, but that would be a huge change
  56. typedef I IndexLocalType_t;
  57. typedef M MemoryAllocator_t;
  58. // constructor, destructor
  59. CUtlLinkedList( int growSize = 0, int initSize = 0 );
  60. ~CUtlLinkedList();
  61. // gets particular elements
  62. T& Element( I i );
  63. T const& Element( I i ) const;
  64. T& operator[]( I i );
  65. T const& operator[]( I i ) const;
  66. // Make sure we have a particular amount of memory
  67. void EnsureCapacity( int num );
  68. void SetGrowSize( int growSize );
  69. // Memory deallocation
  70. void Purge();
  71. // Delete all the elements then call Purge.
  72. void PurgeAndDeleteElements();
  73. // Insertion methods....
  74. I InsertBefore( I before );
  75. I InsertAfter( I after );
  76. I AddToHead( );
  77. I AddToTail( );
  78. I InsertBefore( I before, T const& src );
  79. I InsertAfter( I after, T const& src );
  80. I AddToHead( T const& src );
  81. I AddToTail( T const& src );
  82. // Find an element and return its index or InvalidIndex() if it couldn't be found.
  83. I Find( const T &src ) const;
  84. // Look for the element. If it exists, remove it and return true. Otherwise, return false.
  85. bool FindAndRemove( const T &src );
  86. // Removal methods
  87. void Remove( I elem );
  88. void RemoveAll();
  89. // Allocation/deallocation methods
  90. // If multilist == true, then list list may contain many
  91. // non-connected lists, and IsInList and Head + Tail are meaningless...
  92. I Alloc( bool multilist = false );
  93. void Free( I elem );
  94. // Identify the owner of this linked list's memory:
  95. void SetAllocOwner( const char *pszAllocOwner );
  96. // list modification
  97. void LinkBefore( I before, I elem );
  98. void LinkAfter( I after, I elem );
  99. void Unlink( I elem );
  100. void LinkToHead( I elem );
  101. void LinkToTail( I elem );
  102. // invalid index (M will never allocate an element at this index)
  103. inline static S InvalidIndex() { return ( S )M::InvalidIndex(); }
  104. // Is a given index valid to use? (representible by S and not the invalid index)
  105. static bool IndexInRange( I index );
  106. inline static size_t ElementSize() { return sizeof( ListElem_t ); }
  107. // list statistics
  108. int Count() const;
  109. I MaxElementIndex() const;
  110. I NumAllocated( void ) const { return m_NumAlloced; }
  111. // Traversing the list
  112. I Head() const;
  113. I Tail() const;
  114. I Previous( I i ) const;
  115. I Next( I i ) const;
  116. // Are nodes in the list or valid?
  117. bool IsValidIndex( I i ) const;
  118. bool IsInList( I i ) const;
  119. protected:
  120. // What the linked list element looks like
  121. typedef UtlLinkedListElem_t<T, S> ListElem_t;
  122. // constructs the class
  123. I AllocInternal( bool multilist = false );
  124. void ConstructList();
  125. // Gets at the list element....
  126. ListElem_t& InternalElement( I i ) { return m_Memory[i]; }
  127. ListElem_t const& InternalElement( I i ) const { return m_Memory[i]; }
  128. // copy constructors not allowed
  129. CUtlLinkedList( CUtlLinkedList<T, S, ML, I, M> const& list ) { Assert(0); }
  130. M m_Memory;
  131. I m_Head;
  132. I m_Tail;
  133. I m_FirstFree;
  134. I m_ElementCount; // The number actually in the list
  135. I m_NumAlloced; // The number of allocated elements
  136. typename M::Iterator_t m_LastAlloc; // the last index allocated
  137. // For debugging purposes;
  138. // it's in release builds so this can be used in libraries correctly
  139. ListElem_t *m_pElements;
  140. FORCEINLINE M const &Memory( void ) const
  141. {
  142. return m_Memory;
  143. }
  144. void ResetDbgInfo()
  145. {
  146. m_pElements = m_Memory.Base();
  147. }
  148. };
  149. // this is kind of ugly, but until C++ gets templatized typedefs in C++0x, it's our only choice
  150. template < class T >
  151. class CUtlFixedLinkedList : public CUtlLinkedList< T, intp, true, intp, CUtlFixedMemory< UtlLinkedListElem_t< T, intp > > >
  152. {
  153. public:
  154. CUtlFixedLinkedList( int growSize = 0, int initSize = 0 )
  155. : CUtlLinkedList< T, intp, true, intp, CUtlFixedMemory< UtlLinkedListElem_t< T, intp > > >( growSize, initSize ) {}
  156. bool IsValidIndex( intp i ) const
  157. {
  158. if ( !this->Memory().IsIdxValid( i ) )
  159. return false;
  160. #ifdef _DEBUG // it's safe to skip this here, since the only way to get indices after m_LastAlloc is to use MaxElementIndex
  161. if ( this->Memory().IsIdxAfter( i, this->m_LastAlloc ) )
  162. {
  163. Assert( 0 );
  164. return false; // don't read values that have been allocated, but not constructed
  165. }
  166. #endif
  167. return ( this->Memory()[ i ].m_Previous != i ) || ( this->Memory()[ i ].m_Next == i );
  168. }
  169. private:
  170. int MaxElementIndex() const { Assert( 0 ); return this->InvalidIndex(); } // fixedmemory containers don't support iteration from 0..maxelements-1
  171. void ResetDbgInfo() {}
  172. };
  173. // this is kind of ugly, but until C++ gets templatized typedefs in C++0x, it's our only choice
  174. template < class T, class I = unsigned short >
  175. class CUtlBlockLinkedList : public CUtlLinkedList< T, I, true, I, CUtlBlockMemory< UtlLinkedListElem_t< T, I >, I > >
  176. {
  177. public:
  178. CUtlBlockLinkedList( int growSize = 0, int initSize = 0 )
  179. : CUtlLinkedList< T, I, true, I, CUtlBlockMemory< UtlLinkedListElem_t< T, I >, I > >( growSize, initSize ) {}
  180. protected:
  181. void ResetDbgInfo() {}
  182. };
  183. //-----------------------------------------------------------------------------
  184. // constructor, destructor
  185. //-----------------------------------------------------------------------------
  186. template <class T, class S, bool ML, class I, class M>
  187. CUtlLinkedList<T,S,ML,I,M>::CUtlLinkedList( int growSize, int initSize ) :
  188. m_Memory( growSize, initSize ), m_LastAlloc( m_Memory.InvalidIterator() )
  189. {
  190. // Prevent signed non-int datatypes
  191. COMPILE_TIME_ASSERT( sizeof(S) == 4 || ( ( (S)-1 ) > 0 ) );
  192. ConstructList();
  193. ResetDbgInfo();
  194. }
  195. template <class T, class S, bool ML, class I, class M>
  196. CUtlLinkedList<T,S,ML,I,M>::~CUtlLinkedList( )
  197. {
  198. RemoveAll();
  199. }
  200. template <class T, class S, bool ML, class I, class M>
  201. void CUtlLinkedList<T,S,ML,I,M>::ConstructList()
  202. {
  203. m_Head = InvalidIndex();
  204. m_Tail = InvalidIndex();
  205. m_FirstFree = InvalidIndex();
  206. m_ElementCount = 0;
  207. m_NumAlloced = 0;
  208. }
  209. //-----------------------------------------------------------------------------
  210. // gets particular elements
  211. //-----------------------------------------------------------------------------
  212. template <class T, class S, bool ML, class I, class M>
  213. inline T& CUtlLinkedList<T,S,ML,I,M>::Element( I i )
  214. {
  215. return m_Memory[i].m_Element;
  216. }
  217. template <class T, class S, bool ML, class I, class M>
  218. inline T const& CUtlLinkedList<T,S,ML,I,M>::Element( I i ) const
  219. {
  220. return m_Memory[i].m_Element;
  221. }
  222. template <class T, class S, bool ML, class I, class M>
  223. inline T& CUtlLinkedList<T,S,ML,I,M>::operator[]( I i )
  224. {
  225. return m_Memory[i].m_Element;
  226. }
  227. template <class T, class S, bool ML, class I, class M>
  228. inline T const& CUtlLinkedList<T,S,ML,I,M>::operator[]( I i ) const
  229. {
  230. return m_Memory[i].m_Element;
  231. }
  232. //-----------------------------------------------------------------------------
  233. // list statistics
  234. //-----------------------------------------------------------------------------
  235. template <class T, class S, bool ML, class I, class M>
  236. inline int CUtlLinkedList<T,S,ML,I,M>::Count() const
  237. {
  238. #ifdef MULTILIST_PEDANTIC_ASSERTS
  239. AssertMsg( !ML, "CUtlLinkedList::Count() is meaningless for linked lists." );
  240. #endif
  241. return m_ElementCount;
  242. }
  243. template <class T, class S, bool ML, class I, class M>
  244. inline I CUtlLinkedList<T,S,ML,I,M>::MaxElementIndex() const
  245. {
  246. return m_Memory.NumAllocated();
  247. }
  248. //-----------------------------------------------------------------------------
  249. // Traversing the list
  250. //-----------------------------------------------------------------------------
  251. template <class T, class S, bool ML, class I, class M>
  252. inline I CUtlLinkedList<T,S,ML,I,M>::Head() const
  253. {
  254. return m_Head;
  255. }
  256. template <class T, class S, bool ML, class I, class M>
  257. inline I CUtlLinkedList<T,S,ML,I,M>::Tail() const
  258. {
  259. return m_Tail;
  260. }
  261. template <class T, class S, bool ML, class I, class M>
  262. inline I CUtlLinkedList<T,S,ML,I,M>::Previous( I i ) const
  263. {
  264. Assert( IsValidIndex(i) );
  265. return InternalElement(i).m_Previous;
  266. }
  267. template <class T, class S, bool ML, class I, class M>
  268. inline I CUtlLinkedList<T,S,ML,I,M>::Next( I i ) const
  269. {
  270. Assert( IsValidIndex(i) );
  271. return InternalElement(i).m_Next;
  272. }
  273. //-----------------------------------------------------------------------------
  274. // Are nodes in the list or valid?
  275. //-----------------------------------------------------------------------------
  276. #pragma warning(push)
  277. #pragma warning( disable: 4310 ) // Allows "(I)(S)M::INVALID_INDEX" below
  278. template <class T, class S, bool ML, class I, class M>
  279. inline bool CUtlLinkedList<T,S,ML,I,M>::IndexInRange( I index ) // Static method
  280. {
  281. // Since S is not necessarily the type returned by M, we need to check that M returns indices
  282. // which are representable by S. A common case is 'S === unsigned short', 'I == int', in which
  283. // case CUtlMemory will have 'InvalidIndex == (int)-1' (which casts to 65535 in S), and will
  284. // happily return elements at index 65535 and above.
  285. // Do some static checks here:
  286. // 'I' needs to be able to store 'S'
  287. COMPILE_TIME_ASSERT( sizeof(I) >= sizeof(S) );
  288. // 'S' should be unsigned (to avoid signed arithmetic errors for plausibly exhaustible ranges)
  289. COMPILE_TIME_ASSERT( ( sizeof(S) > 2 ) || ( ( (S)-1 ) > 0 ) );
  290. // M::INVALID_INDEX should be storable in S to avoid ambiguities (e.g. with 65536)
  291. COMPILE_TIME_ASSERT( ( M::INVALID_INDEX == -1 ) || ( M::INVALID_INDEX == (S)M::INVALID_INDEX ) );
  292. return ( ( (S)index == index ) && ( (S)index != InvalidIndex() ) );
  293. }
  294. #pragma warning(pop)
  295. template <class T, class S, bool ML, class I, class M>
  296. inline bool CUtlLinkedList<T,S,ML,I,M>::IsValidIndex( I i ) const
  297. {
  298. if ( !m_Memory.IsIdxValid( i ) )
  299. return false;
  300. if ( m_Memory.IsIdxAfter( i, m_LastAlloc ) )
  301. return false; // don't read values that have been allocated, but not constructed
  302. return ( m_Memory[ i ].m_Previous != i ) || ( m_Memory[ i ].m_Next == i );
  303. }
  304. template <class T, class S, bool ML, class I, class M>
  305. inline bool CUtlLinkedList<T,S,ML,I,M>::IsInList( I i ) const
  306. {
  307. if ( !m_Memory.IsIdxValid( i ) || m_Memory.IsIdxAfter( i, m_LastAlloc ) )
  308. return false; // don't read values that have been allocated, but not constructed
  309. return Previous( i ) != i;
  310. }
  311. /*
  312. template <class T>
  313. inline bool CUtlFixedLinkedList<T>::IsInList( int i ) const
  314. {
  315. return m_Memory.IsIdxValid( i ) && (Previous( i ) != i);
  316. }
  317. */
  318. //-----------------------------------------------------------------------------
  319. // Makes sure we have enough memory allocated to store a requested # of elements
  320. //-----------------------------------------------------------------------------
  321. template< class T, class S, bool ML, class I, class M >
  322. void CUtlLinkedList<T,S,ML,I,M>::EnsureCapacity( int num )
  323. {
  324. MEM_ALLOC_CREDIT_CLASS();
  325. m_Memory.EnsureCapacity(num);
  326. ResetDbgInfo();
  327. }
  328. template< class T, class S, bool ML, class I, class M >
  329. void CUtlLinkedList<T,S,ML,I,M>::SetGrowSize( int growSize )
  330. {
  331. RemoveAll();
  332. m_Memory.Init( growSize );
  333. ResetDbgInfo();
  334. }
  335. template< class T, class S, bool ML, class I, class M >
  336. void CUtlLinkedList<T,S,ML,I,M>::SetAllocOwner( const char *pszAllocOwner )
  337. {
  338. m_Memory.SetAllocOwner( pszAllocOwner );
  339. }
  340. //-----------------------------------------------------------------------------
  341. // Deallocate memory
  342. //-----------------------------------------------------------------------------
  343. template <class T, class S, bool ML, class I, class M>
  344. void CUtlLinkedList<T,S,ML,I,M>::Purge()
  345. {
  346. RemoveAll();
  347. m_Memory.Purge();
  348. m_FirstFree = InvalidIndex();
  349. m_NumAlloced = 0;
  350. //Routing "m_LastAlloc = m_Memory.InvalidIterator();" through a local const to sidestep an internal compiler error on 360 builds
  351. const typename M::Iterator_t scInvalidIterator = m_Memory.InvalidIterator();
  352. m_LastAlloc = scInvalidIterator;
  353. ResetDbgInfo();
  354. }
  355. template<class T, class S, bool ML, class I, class M>
  356. void CUtlLinkedList<T,S,ML,I,M>::PurgeAndDeleteElements()
  357. {
  358. I iNext;
  359. for( I i=Head(); i != InvalidIndex(); i=iNext )
  360. {
  361. iNext = Next(i);
  362. delete Element(i);
  363. }
  364. Purge();
  365. }
  366. //-----------------------------------------------------------------------------
  367. // Node allocation/deallocation
  368. //-----------------------------------------------------------------------------
  369. template <class T, class S, bool ML, class I, class M>
  370. I CUtlLinkedList<T,S,ML,I,M>::AllocInternal( bool multilist )
  371. {
  372. Assert( !multilist || ML );
  373. #ifdef MULTILIST_PEDANTIC_ASSERTS
  374. Assert( multilist == ML );
  375. #endif
  376. I elem;
  377. if ( m_FirstFree == InvalidIndex() )
  378. {
  379. Assert( m_Memory.IsValidIterator( m_LastAlloc ) || m_ElementCount == 0 );
  380. typename M::Iterator_t it = m_Memory.IsValidIterator( m_LastAlloc ) ? m_Memory.Next( m_LastAlloc ) : m_Memory.First();
  381. if ( !m_Memory.IsValidIterator( it ) )
  382. {
  383. MEM_ALLOC_CREDIT_CLASS();
  384. m_Memory.Grow();
  385. ResetDbgInfo();
  386. it = m_Memory.IsValidIterator( m_LastAlloc ) ? m_Memory.Next( m_LastAlloc ) : m_Memory.First();
  387. Assert( m_Memory.IsValidIterator( it ) );
  388. if ( !m_Memory.IsValidIterator( it ) )
  389. {
  390. ExecuteNTimes( 10, Warning( "CUtlLinkedList overflow! (exhausted memory allocator)\n" ) );
  391. return InvalidIndex();
  392. }
  393. }
  394. // We can overflow before the utlmemory overflows, since S != I
  395. if ( !IndexInRange( m_Memory.GetIndex( it ) ) )
  396. {
  397. ExecuteNTimes( 10, Warning( "CUtlLinkedList overflow! (exhausted index range)\n" ) );
  398. return InvalidIndex();
  399. }
  400. m_LastAlloc = it;
  401. elem = m_Memory.GetIndex( m_LastAlloc );
  402. m_NumAlloced++;
  403. }
  404. else
  405. {
  406. elem = m_FirstFree;
  407. m_FirstFree = InternalElement( m_FirstFree ).m_Next;
  408. }
  409. if ( !multilist )
  410. {
  411. InternalElement( elem ).m_Next = elem;
  412. InternalElement( elem ).m_Previous = elem;
  413. }
  414. else
  415. {
  416. InternalElement( elem ).m_Next = InvalidIndex();
  417. InternalElement( elem ).m_Previous = InvalidIndex();
  418. }
  419. return elem;
  420. }
  421. template <class T, class S, bool ML, class I, class M>
  422. I CUtlLinkedList<T,S,ML,I,M>::Alloc( bool multilist )
  423. {
  424. I elem = AllocInternal( multilist );
  425. if ( elem == InvalidIndex() )
  426. return elem;
  427. Construct( &Element(elem) );
  428. return elem;
  429. }
  430. template <class T, class S, bool ML, class I, class M>
  431. void CUtlLinkedList<T,S,ML,I,M>::Free( I elem )
  432. {
  433. Assert( IsValidIndex(elem) && IndexInRange( elem ) );
  434. Unlink(elem);
  435. ListElem_t &internalElem = InternalElement(elem);
  436. Destruct( &internalElem.m_Element );
  437. internalElem.m_Next = m_FirstFree;
  438. m_FirstFree = elem;
  439. }
  440. //-----------------------------------------------------------------------------
  441. // Insertion methods; allocates and links (uses default constructor)
  442. //-----------------------------------------------------------------------------
  443. template <class T, class S, bool ML, class I, class M>
  444. I CUtlLinkedList<T,S,ML,I,M>::InsertBefore( I before )
  445. {
  446. // Make a new node
  447. I newNode = AllocInternal();
  448. if ( newNode == InvalidIndex() )
  449. return newNode;
  450. // Link it in
  451. LinkBefore( before, newNode );
  452. // Construct the data
  453. Construct( &Element(newNode) );
  454. return newNode;
  455. }
  456. template <class T, class S, bool ML, class I, class M>
  457. I CUtlLinkedList<T,S,ML,I,M>::InsertAfter( I after )
  458. {
  459. // Make a new node
  460. I newNode = AllocInternal();
  461. if ( newNode == InvalidIndex() )
  462. return newNode;
  463. // Link it in
  464. LinkAfter( after, newNode );
  465. // Construct the data
  466. Construct( &Element(newNode) );
  467. return newNode;
  468. }
  469. template <class T, class S, bool ML, class I, class M>
  470. inline I CUtlLinkedList<T,S,ML,I,M>::AddToHead( )
  471. {
  472. return InsertAfter( InvalidIndex() );
  473. }
  474. template <class T, class S, bool ML, class I, class M>
  475. inline I CUtlLinkedList<T,S,ML,I,M>::AddToTail( )
  476. {
  477. return InsertBefore( InvalidIndex() );
  478. }
  479. //-----------------------------------------------------------------------------
  480. // Insertion methods; allocates and links (uses copy constructor)
  481. //-----------------------------------------------------------------------------
  482. template <class T, class S, bool ML, class I, class M>
  483. I CUtlLinkedList<T,S,ML,I,M>::InsertBefore( I before, T const& src )
  484. {
  485. // Make a new node
  486. I newNode = AllocInternal();
  487. if ( newNode == InvalidIndex() )
  488. return newNode;
  489. // Link it in
  490. LinkBefore( before, newNode );
  491. // Construct the data
  492. CopyConstruct( &Element(newNode), src );
  493. return newNode;
  494. }
  495. template <class T, class S, bool ML, class I, class M>
  496. I CUtlLinkedList<T,S,ML,I,M>::InsertAfter( I after, T const& src )
  497. {
  498. // Make a new node
  499. I newNode = AllocInternal();
  500. if ( newNode == InvalidIndex() )
  501. return newNode;
  502. // Link it in
  503. LinkAfter( after, newNode );
  504. // Construct the data
  505. CopyConstruct( &Element(newNode), src );
  506. return newNode;
  507. }
  508. template <class T, class S, bool ML, class I, class M>
  509. inline I CUtlLinkedList<T,S,ML,I,M>::AddToHead( T const& src )
  510. {
  511. return InsertAfter( InvalidIndex(), src );
  512. }
  513. template <class T, class S, bool ML, class I, class M>
  514. inline I CUtlLinkedList<T,S,ML,I,M>::AddToTail( T const& src )
  515. {
  516. return InsertBefore( InvalidIndex(), src );
  517. }
  518. //-----------------------------------------------------------------------------
  519. // Removal methods
  520. //-----------------------------------------------------------------------------
  521. template<class T, class S, bool ML, class I, class M>
  522. I CUtlLinkedList<T,S,ML,I,M>::Find( const T &src ) const
  523. {
  524. for ( I i=Head(); i != InvalidIndex(); i = Next( i ) )
  525. {
  526. if ( Element( i ) == src )
  527. return i;
  528. }
  529. return InvalidIndex();
  530. }
  531. template<class T, class S, bool ML, class I, class M>
  532. bool CUtlLinkedList<T,S,ML,I,M>::FindAndRemove( const T &src )
  533. {
  534. I i = Find( src );
  535. if ( i == InvalidIndex() )
  536. {
  537. return false;
  538. }
  539. else
  540. {
  541. Remove( i );
  542. return true;
  543. }
  544. }
  545. template <class T, class S, bool ML, class I, class M>
  546. void CUtlLinkedList<T,S,ML,I,M>::Remove( I elem )
  547. {
  548. Free( elem );
  549. }
  550. template <class T, class S, bool ML, class I, class M>
  551. void CUtlLinkedList<T,S,ML,I,M>::RemoveAll()
  552. {
  553. // Have to do some convoluted stuff to invoke the destructor on all
  554. // valid elements for the multilist case (since we don't have all elements
  555. // connected to each other in a list).
  556. if ( m_LastAlloc == m_Memory.InvalidIterator() )
  557. {
  558. Assert( m_Head == InvalidIndex() );
  559. Assert( m_Tail == InvalidIndex() );
  560. Assert( m_FirstFree == InvalidIndex() );
  561. Assert( m_ElementCount == 0 );
  562. return;
  563. }
  564. if ( ML )
  565. {
  566. for ( typename M::Iterator_t it = m_Memory.First(); it != m_Memory.InvalidIterator(); it = m_Memory.Next( it ) )
  567. {
  568. I i = m_Memory.GetIndex( it );
  569. if ( IsValidIndex( i ) ) // skip elements already in the free list
  570. {
  571. ListElem_t &internalElem = InternalElement( i );
  572. Destruct( &internalElem.m_Element );
  573. internalElem.m_Previous = i;
  574. internalElem.m_Next = m_FirstFree;
  575. m_FirstFree = i;
  576. }
  577. if ( it == m_LastAlloc )
  578. break; // don't destruct elements that haven't ever been constructed
  579. }
  580. }
  581. else
  582. {
  583. I i = Head();
  584. I next;
  585. while ( i != InvalidIndex() )
  586. {
  587. next = Next( i );
  588. ListElem_t &internalElem = InternalElement( i );
  589. Destruct( &internalElem.m_Element );
  590. internalElem.m_Previous = i;
  591. internalElem.m_Next = next == InvalidIndex() ? m_FirstFree : next;
  592. i = next;
  593. }
  594. if ( Head() != InvalidIndex() )
  595. {
  596. m_FirstFree = Head();
  597. }
  598. }
  599. // Clear everything else out
  600. m_Head = InvalidIndex();
  601. m_Tail = InvalidIndex();
  602. m_ElementCount = 0;
  603. }
  604. //-----------------------------------------------------------------------------
  605. // list modification
  606. //-----------------------------------------------------------------------------
  607. template <class T, class S, bool ML, class I, class M>
  608. void CUtlLinkedList<T,S,ML,I,M>::LinkBefore( I before, I elem )
  609. {
  610. Assert( IsValidIndex(elem) );
  611. // Unlink it if it's in the list at the moment
  612. Unlink(elem);
  613. ListElem_t * pNewElem = &InternalElement(elem);
  614. // The element *after* our newly linked one is the one we linked before.
  615. pNewElem->m_Next = before;
  616. S newElem_mPrevious; // we need to hang on to this for the compairson against InvalidIndex()
  617. // below; otherwise we get a a load-hit-store on pNewElem->m_Previous, even
  618. // with
  619. if (before == InvalidIndex())
  620. {
  621. // In this case, we're linking to the end of the list, so reset the tail
  622. newElem_mPrevious = m_Tail;
  623. pNewElem->m_Previous = m_Tail;
  624. m_Tail = elem;
  625. }
  626. else
  627. {
  628. // Here, we're not linking to the end. Set the prev pointer to point to
  629. // the element we're linking.
  630. Assert( IsInList(before) );
  631. ListElem_t * beforeElem = &InternalElement(before);
  632. pNewElem->m_Previous = newElem_mPrevious = beforeElem->m_Previous;
  633. beforeElem->m_Previous = elem;
  634. }
  635. // Reset the head if we linked to the head of the list
  636. if (newElem_mPrevious == InvalidIndex())
  637. m_Head = elem;
  638. else
  639. InternalElement(newElem_mPrevious).m_Next = elem;
  640. // one more element baby
  641. ++m_ElementCount;
  642. }
  643. template <class T, class S, bool ML, class I, class M>
  644. void CUtlLinkedList<T,S,ML,I,M>::LinkAfter( I after, I elem )
  645. {
  646. Assert( IsValidIndex(elem) );
  647. // Unlink it if it's in the list at the moment
  648. if ( IsInList(elem) )
  649. Unlink(elem);
  650. ListElem_t& newElem = InternalElement(elem);
  651. // The element *before* our newly linked one is the one we linked after
  652. newElem.m_Previous = after;
  653. if (after == InvalidIndex())
  654. {
  655. // In this case, we're linking to the head of the list, reset the head
  656. newElem.m_Next = m_Head;
  657. m_Head = elem;
  658. }
  659. else
  660. {
  661. // Here, we're not linking to the end. Set the next pointer to point to
  662. // the element we're linking.
  663. Assert( IsInList(after) );
  664. ListElem_t& afterElem = InternalElement(after);
  665. newElem.m_Next = afterElem.m_Next;
  666. afterElem.m_Next = elem;
  667. }
  668. // Reset the tail if we linked to the tail of the list
  669. if (newElem.m_Next == InvalidIndex())
  670. m_Tail = elem;
  671. else
  672. InternalElement(newElem.m_Next).m_Previous = elem;
  673. // one more element baby
  674. ++m_ElementCount;
  675. }
  676. template <class T, class S, bool ML, class I, class M>
  677. void CUtlLinkedList<T,S,ML,I,M>::Unlink( I elem )
  678. {
  679. Assert( IsValidIndex(elem) );
  680. if (IsInList(elem))
  681. {
  682. ListElem_t * pOldElem = &m_Memory[ elem ];
  683. // If we're the first guy, reset the head
  684. // otherwise, make our previous node's next pointer = our next
  685. if ( pOldElem->m_Previous != InvalidIndex() )
  686. {
  687. m_Memory[ pOldElem->m_Previous ].m_Next = pOldElem->m_Next;
  688. }
  689. else
  690. {
  691. m_Head = pOldElem->m_Next;
  692. }
  693. // If we're the last guy, reset the tail
  694. // otherwise, make our next node's prev pointer = our prev
  695. if ( pOldElem->m_Next != InvalidIndex() )
  696. {
  697. m_Memory[ pOldElem->m_Next ].m_Previous = pOldElem->m_Previous;
  698. }
  699. else
  700. {
  701. m_Tail = pOldElem->m_Previous;
  702. }
  703. // This marks this node as not in the list,
  704. // but not in the free list either
  705. pOldElem->m_Previous = pOldElem->m_Next = elem;
  706. // One less puppy
  707. --m_ElementCount;
  708. }
  709. }
  710. template <class T, class S, bool ML, class I, class M>
  711. inline void CUtlLinkedList<T,S,ML,I,M>::LinkToHead( I elem )
  712. {
  713. LinkAfter( InvalidIndex(), elem );
  714. }
  715. template <class T, class S, bool ML, class I, class M>
  716. inline void CUtlLinkedList<T,S,ML,I,M>::LinkToTail( I elem )
  717. {
  718. LinkBefore( InvalidIndex(), elem );
  719. }
  720. //-----------------------------------------------------------------------------
  721. // Class to drop in to replace a CUtlLinkedList that needs to be more memory agressive
  722. //-----------------------------------------------------------------------------
  723. DECLARE_POINTER_HANDLE( UtlPtrLinkedListIndex_t ); // to enforce correct usage
  724. template < typename T >
  725. class CUtlPtrLinkedList
  726. {
  727. public:
  728. CUtlPtrLinkedList()
  729. : m_pFirst( NULL ),
  730. m_nElems( 0 )
  731. {
  732. COMPILE_TIME_ASSERT( sizeof(IndexType_t) == sizeof(Node_t *) );
  733. }
  734. ~CUtlPtrLinkedList()
  735. {
  736. RemoveAll();
  737. }
  738. typedef UtlPtrLinkedListIndex_t IndexType_t;
  739. T &operator[]( IndexType_t i )
  740. {
  741. return (( Node_t * )i)->elem;
  742. }
  743. const T &operator[]( IndexType_t i ) const
  744. {
  745. return (( Node_t * )i)->elem;
  746. }
  747. IndexType_t AddToTail()
  748. {
  749. return DoInsertBefore( (IndexType_t)m_pFirst, NULL );
  750. }
  751. IndexType_t AddToTail( T const& src )
  752. {
  753. return DoInsertBefore( (IndexType_t)m_pFirst, &src );
  754. }
  755. IndexType_t AddToHead()
  756. {
  757. IndexType_t result = DoInsertBefore( (IndexType_t)m_pFirst, NULL );
  758. m_pFirst = ((Node_t *)result);
  759. return result;
  760. }
  761. IndexType_t AddToHead( T const& src )
  762. {
  763. IndexType_t result = DoInsertBefore( (IndexType_t)m_pFirst, &src );
  764. m_pFirst = ((Node_t *)result);
  765. return result;
  766. }
  767. IndexType_t InsertBefore( IndexType_t before )
  768. {
  769. return DoInsertBefore( before, NULL );
  770. }
  771. IndexType_t InsertAfter( IndexType_t after )
  772. {
  773. Node_t *pBefore = ((Node_t *)after)->next;
  774. return DoInsertBefore( pBefore, NULL );
  775. }
  776. IndexType_t InsertBefore( IndexType_t before, T const& src )
  777. {
  778. return DoInsertBefore( before, &src );
  779. }
  780. IndexType_t InsertAfter( IndexType_t after, T const& src )
  781. {
  782. Node_t *pBefore = ((Node_t *)after)->next;
  783. return DoInsertBefore( pBefore, &src );
  784. }
  785. void Remove( IndexType_t elem )
  786. {
  787. Node_t *p = (Node_t *)elem;
  788. if ( p->pNext == p )
  789. {
  790. m_pFirst = NULL;
  791. }
  792. else
  793. {
  794. if ( m_pFirst == p )
  795. {
  796. m_pFirst = p->pNext;
  797. }
  798. p->pNext->pPrev = p->pPrev;
  799. p->pPrev->pNext = p->pNext;
  800. }
  801. delete p;
  802. m_nElems--;
  803. }
  804. void RemoveAll()
  805. {
  806. Node_t *p = m_pFirst;
  807. if ( p )
  808. {
  809. do
  810. {
  811. Node_t *pNext = p->pNext;
  812. delete p;
  813. p = pNext;
  814. } while( p != m_pFirst );
  815. }
  816. m_pFirst = NULL;
  817. m_nElems = 0;
  818. }
  819. int Count() const
  820. {
  821. return m_nElems;
  822. }
  823. IndexType_t Head() const
  824. {
  825. return (IndexType_t)m_pFirst;
  826. }
  827. IndexType_t Next( IndexType_t i ) const
  828. {
  829. Node_t *p = ((Node_t *)i)->pNext;
  830. if ( p != m_pFirst )
  831. {
  832. return (IndexType_t)p;
  833. }
  834. return NULL;
  835. }
  836. bool IsValidIndex( IndexType_t i ) const
  837. {
  838. Node_t *p = ((Node_t *)i);
  839. return ( p && p->pNext && p->pPrev );
  840. }
  841. inline static IndexType_t InvalidIndex()
  842. {
  843. return NULL;
  844. }
  845. private:
  846. struct Node_t
  847. {
  848. Node_t() {}
  849. Node_t( const T &_elem ) : elem( _elem ) {}
  850. T elem;
  851. Node_t *pPrev, *pNext;
  852. };
  853. Node_t *AllocNode( const T *pCopyFrom )
  854. {
  855. MEM_ALLOC_CREDIT_CLASS();
  856. Node_t *p;
  857. if ( !pCopyFrom )
  858. {
  859. p = new Node_t;
  860. }
  861. else
  862. {
  863. p = new Node_t( *pCopyFrom );
  864. }
  865. return p;
  866. }
  867. IndexType_t DoInsertBefore( IndexType_t before, const T *pCopyFrom )
  868. {
  869. Node_t *p = AllocNode( pCopyFrom );
  870. Node_t *pBefore = (Node_t *)before;
  871. if ( pBefore )
  872. {
  873. p->pNext = pBefore;
  874. p->pPrev = pBefore->pPrev;
  875. pBefore->pPrev = p;
  876. p->pPrev->pNext = p;
  877. }
  878. else
  879. {
  880. Assert( !m_pFirst );
  881. m_pFirst = p->pNext = p->pPrev = p;
  882. }
  883. m_nElems++;
  884. return (IndexType_t)p;
  885. }
  886. Node_t *m_pFirst;
  887. unsigned m_nElems;
  888. };
  889. //-----------------------------------------------------------------------------
  890. #endif // UTLLINKEDLIST_H