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.

1293 lines
34 KiB

  1. //========= Copyright 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(); (listName).IsUtlLinkedList && 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. static const bool IsUtlLinkedList = true; // Used to match this at compiletime
  59. // constructor, destructor
  60. CUtlLinkedList( int growSize = 0, int initSize = 0 );
  61. ~CUtlLinkedList();
  62. // gets particular elements
  63. T& Element( I i );
  64. T const& Element( I i ) const;
  65. T& operator[]( I i );
  66. T const& operator[]( I i ) const;
  67. // Make sure we have a particular amount of memory
  68. void EnsureCapacity( int num );
  69. void SetGrowSize( int growSize );
  70. // Memory deallocation
  71. void Purge();
  72. // Delete all the elements then call Purge.
  73. void PurgeAndDeleteElements();
  74. // Insertion methods....
  75. I InsertBefore( I before );
  76. I InsertAfter( I after );
  77. I AddToHead( );
  78. I AddToTail( );
  79. I InsertBefore( I before, T const& src );
  80. I InsertAfter( I after, T const& src );
  81. I AddToHead( T const& src );
  82. I AddToTail( T const& src );
  83. // Find an element and return its index or InvalidIndex() if it couldn't be found.
  84. I Find( const T &src ) const;
  85. // Look for the element. If it exists, remove it and return true. Otherwise, return false.
  86. bool FindAndRemove( const T &src );
  87. // Removal methods
  88. void Remove( I elem );
  89. void RemoveAll();
  90. // Allocation/deallocation methods
  91. // If multilist == true, then list list may contain many
  92. // non-connected lists, and IsInList and Head + Tail are meaningless...
  93. I Alloc( bool multilist = false );
  94. void Free( I elem );
  95. // list modification
  96. void LinkBefore( I before, I elem );
  97. void LinkAfter( I after, I elem );
  98. void Unlink( I elem );
  99. void LinkToHead( I elem );
  100. void LinkToTail( I elem );
  101. // invalid index (M will never allocate an element at this index)
  102. inline static S InvalidIndex() { return ( S )M::InvalidIndex(); }
  103. // Is a given index valid to use? (representible by S and not the invalid index)
  104. static bool IndexInRange( I index );
  105. inline static size_t ElementSize() { return sizeof( ListElem_t ); }
  106. // list statistics
  107. int Count() const;
  108. inline bool IsEmpty( void ) const
  109. {
  110. return ( Head() == InvalidIndex() );
  111. }
  112. I MaxElementIndex() const;
  113. I NumAllocated( void ) const { return m_NumAlloced; }
  114. // Traversing the list
  115. I Head() const;
  116. I Tail() const;
  117. I Previous( I i ) const;
  118. I Next( I i ) const;
  119. // STL compatible const_iterator class
  120. template < typename List_t >
  121. class _CUtlLinkedList_constiterator_t
  122. {
  123. public:
  124. typedef typename List_t::ElemType_t ElemType_t;
  125. typedef typename List_t::IndexType_t IndexType_t;
  126. // Default constructor -- gives a currently unusable iterator.
  127. _CUtlLinkedList_constiterator_t()
  128. : m_list( 0 )
  129. , m_index( List_t::InvalidIndex() )
  130. {
  131. }
  132. // Normal constructor.
  133. _CUtlLinkedList_constiterator_t( const List_t& list, IndexType_t index )
  134. : m_list( &list )
  135. , m_index( index )
  136. {
  137. }
  138. // Pre-increment operator++. This is the most efficient increment
  139. // operator so it should always be used.
  140. _CUtlLinkedList_constiterator_t& operator++()
  141. {
  142. m_index = m_list->Next( m_index );
  143. return *this;
  144. }
  145. // Post-increment operator++. This is less efficient than pre-increment.
  146. _CUtlLinkedList_constiterator_t operator++(int)
  147. {
  148. // Copy ourselves.
  149. _CUtlLinkedList_constiterator_t temp = *this;
  150. // Increment ourselves.
  151. ++*this;
  152. // Return the copy.
  153. return temp;
  154. }
  155. // Pre-decrement operator--. This is the most efficient decrement
  156. // operator so it should always be used.
  157. _CUtlLinkedList_constiterator_t& operator--()
  158. {
  159. Assert( m_index != m_list->Head() );
  160. if ( m_index == m_list->InvalidIndex() )
  161. {
  162. m_index = m_list->Tail();
  163. }
  164. else
  165. {
  166. m_index = m_list->Previous( m_index );
  167. }
  168. return *this;
  169. }
  170. // Post-decrement operator--. This is less efficient than post-decrement.
  171. _CUtlLinkedList_constiterator_t operator--(int)
  172. {
  173. // Copy ourselves.
  174. _CUtlLinkedList_constiterator_t temp = *this;
  175. // Decrement ourselves.
  176. --*this;
  177. // Return the copy.
  178. return temp;
  179. }
  180. bool operator==( const _CUtlLinkedList_constiterator_t& other) const
  181. {
  182. Assert( m_list == other.m_list );
  183. return m_index == other.m_index;
  184. }
  185. bool operator!=( const _CUtlLinkedList_constiterator_t& other) const
  186. {
  187. Assert( m_list == other.m_list );
  188. return m_index != other.m_index;
  189. }
  190. const ElemType_t& operator*() const
  191. {
  192. return m_list->Element( m_index );
  193. }
  194. const ElemType_t* operator->() const
  195. {
  196. return (&**this);
  197. }
  198. protected:
  199. // Use a pointer rather than a reference so that we can support
  200. // assignment of iterators.
  201. const List_t* m_list;
  202. IndexType_t m_index;
  203. };
  204. // STL compatible iterator class, using derivation so that a non-const
  205. // list can return a const_iterator.
  206. template < typename List_t >
  207. class _CUtlLinkedList_iterator_t : public _CUtlLinkedList_constiterator_t< List_t >
  208. {
  209. public:
  210. typedef typename List_t::ElemType_t ElemType_t;
  211. typedef typename List_t::IndexType_t IndexType_t;
  212. typedef _CUtlLinkedList_constiterator_t< List_t > Base;
  213. // Default constructor -- gives a currently unusable iterator.
  214. _CUtlLinkedList_iterator_t()
  215. {
  216. }
  217. // Normal constructor.
  218. _CUtlLinkedList_iterator_t( const List_t& list, IndexType_t index )
  219. : _CUtlLinkedList_constiterator_t< List_t >( list, index )
  220. {
  221. }
  222. // Pre-increment operator++. This is the most efficient increment
  223. // operator so it should always be used.
  224. _CUtlLinkedList_iterator_t& operator++()
  225. {
  226. Base::m_index = Base::m_list->Next( Base::m_index );
  227. return *this;
  228. }
  229. // Post-increment operator++. This is less efficient than pre-increment.
  230. _CUtlLinkedList_iterator_t operator++(int)
  231. {
  232. // Copy ourselves.
  233. _CUtlLinkedList_iterator_t temp = *this;
  234. // Increment ourselves.
  235. ++*this;
  236. // Return the copy.
  237. return temp;
  238. }
  239. // Pre-decrement operator--. This is the most efficient decrement
  240. // operator so it should always be used.
  241. _CUtlLinkedList_iterator_t& operator--()
  242. {
  243. Assert( Base::m_index != Base::m_list->Head() );
  244. if ( Base::m_index == Base::m_list->InvalidIndex() )
  245. {
  246. Base::m_index = Base::m_list->Tail();
  247. }
  248. else
  249. {
  250. Base::m_index = Base::m_list->Previous( Base::m_index );
  251. }
  252. return *this;
  253. }
  254. // Post-decrement operator--. This is less efficient than post-decrement.
  255. _CUtlLinkedList_iterator_t operator--(int)
  256. {
  257. // Copy ourselves.
  258. _CUtlLinkedList_iterator_t temp = *this;
  259. // Decrement ourselves.
  260. --*this;
  261. // Return the copy.
  262. return temp;
  263. }
  264. ElemType_t& operator*() const
  265. {
  266. // Const_cast to allow sharing the implementation with the
  267. // base class.
  268. List_t* pMutableList = const_cast<List_t*>( Base::m_list );
  269. return pMutableList->Element( Base::m_index );
  270. }
  271. ElemType_t* operator->() const
  272. {
  273. return (&**this);
  274. }
  275. };
  276. typedef _CUtlLinkedList_constiterator_t<CUtlLinkedList<T, S, ML, I, M> > const_iterator;
  277. typedef _CUtlLinkedList_iterator_t<CUtlLinkedList<T, S, ML, I, M> > iterator;
  278. const_iterator begin() const
  279. {
  280. return const_iterator( *this, Head() );
  281. }
  282. iterator begin()
  283. {
  284. return iterator( *this, Head() );
  285. }
  286. const_iterator end() const
  287. {
  288. return const_iterator( *this, InvalidIndex() );
  289. }
  290. iterator end()
  291. {
  292. return iterator( *this, InvalidIndex() );
  293. }
  294. // Are nodes in the list or valid?
  295. bool IsValidIndex( I i ) const;
  296. bool IsInList( I i ) const;
  297. protected:
  298. // What the linked list element looks like
  299. typedef UtlLinkedListElem_t<T, S> ListElem_t;
  300. // constructs the class
  301. I AllocInternal( bool multilist = false );
  302. void ConstructList();
  303. // Gets at the list element....
  304. ListElem_t& InternalElement( I i ) { return m_Memory[i]; }
  305. ListElem_t const& InternalElement( I i ) const { return m_Memory[i]; }
  306. // copy constructors not allowed
  307. CUtlLinkedList( CUtlLinkedList<T, S, ML, I, M> const& list ) { Assert(0); }
  308. M m_Memory;
  309. I m_Head;
  310. I m_Tail;
  311. I m_FirstFree;
  312. I m_ElementCount; // The number actually in the list
  313. I m_NumAlloced; // The number of allocated elements
  314. typename M::Iterator_t m_LastAlloc; // the last index allocated
  315. // For debugging purposes;
  316. // it's in release builds so this can be used in libraries correctly
  317. ListElem_t *m_pElements;
  318. FORCEINLINE M const &Memory( void ) const
  319. {
  320. return m_Memory;
  321. }
  322. void ResetDbgInfo()
  323. {
  324. m_pElements = m_Memory.Base();
  325. }
  326. private:
  327. // Faster version of Next that can only be used from tested code internal
  328. // to this class, such as Find(). It avoids the cost of checking the index
  329. // validity, which is a big win on debug builds.
  330. I PrivateNext( I i ) const;
  331. };
  332. // this is kind of ugly, but until C++ gets templatized typedefs in C++0x, it's our only choice
  333. template < class T >
  334. class CUtlFixedLinkedList : public CUtlLinkedList< T, int, true, int, CUtlFixedMemory< UtlLinkedListElem_t< T, int > > >
  335. {
  336. public:
  337. CUtlFixedLinkedList( int growSize = 0, int initSize = 0 )
  338. : CUtlLinkedList< T, int, true, int, CUtlFixedMemory< UtlLinkedListElem_t< T, int > > >( growSize, initSize ) {}
  339. typedef CUtlLinkedList< T, int, true, int, CUtlFixedMemory< UtlLinkedListElem_t< T, int > > > BaseClass;
  340. bool IsValidIndex( int i ) const
  341. {
  342. if ( !BaseClass::Memory().IsIdxValid( i ) )
  343. return false;
  344. #ifdef _DEBUG // it's safe to skip this here, since the only way to get indices after m_LastAlloc is to use MaxElementIndex
  345. if ( BaseClass::Memory().IsIdxAfter( i, this->m_LastAlloc ) )
  346. {
  347. Assert( 0 );
  348. return false; // don't read values that have been allocated, but not constructed
  349. }
  350. #endif
  351. return ( BaseClass::Memory()[ i ].m_Previous != i ) || ( BaseClass::Memory()[ i ].m_Next == i );
  352. }
  353. private:
  354. int MaxElementIndex() const { Assert( 0 ); return BaseClass::InvalidIndex(); } // fixedmemory containers don't support iteration from 0..maxelements-1
  355. void ResetDbgInfo() {}
  356. };
  357. // this is kind of ugly, but until C++ gets templatized typedefs in C++0x, it's our only choice
  358. template < class T, class I = unsigned short >
  359. class CUtlBlockLinkedList : public CUtlLinkedList< T, I, true, I, CUtlBlockMemory< UtlLinkedListElem_t< T, I >, I > >
  360. {
  361. public:
  362. CUtlBlockLinkedList( int growSize = 0, int initSize = 0 )
  363. : CUtlLinkedList< T, I, true, I, CUtlBlockMemory< UtlLinkedListElem_t< T, I >, I > >( growSize, initSize ) {}
  364. protected:
  365. void ResetDbgInfo() {}
  366. };
  367. //-----------------------------------------------------------------------------
  368. // constructor, destructor
  369. //-----------------------------------------------------------------------------
  370. template <class T, class S, bool ML, class I, class M>
  371. CUtlLinkedList<T,S,ML,I,M>::CUtlLinkedList( int growSize, int initSize ) :
  372. m_Memory( growSize, initSize ), m_LastAlloc( m_Memory.InvalidIterator() )
  373. {
  374. // Prevent signed non-int datatypes
  375. COMPILE_TIME_ASSERT( sizeof(S) == 4 || ( ( (S)-1 ) > 0 ) );
  376. ConstructList();
  377. ResetDbgInfo();
  378. }
  379. template <class T, class S, bool ML, class I, class M>
  380. CUtlLinkedList<T,S,ML,I,M>::~CUtlLinkedList( )
  381. {
  382. RemoveAll();
  383. }
  384. template <class T, class S, bool ML, class I, class M>
  385. void CUtlLinkedList<T,S,ML,I,M>::ConstructList()
  386. {
  387. m_Head = InvalidIndex();
  388. m_Tail = InvalidIndex();
  389. m_FirstFree = InvalidIndex();
  390. m_ElementCount = 0;
  391. m_NumAlloced = 0;
  392. }
  393. //-----------------------------------------------------------------------------
  394. // gets particular elements
  395. //-----------------------------------------------------------------------------
  396. template <class T, class S, bool ML, class I, class M>
  397. inline T& CUtlLinkedList<T,S,ML,I,M>::Element( I i )
  398. {
  399. return m_Memory[i].m_Element;
  400. }
  401. template <class T, class S, bool ML, class I, class M>
  402. inline T const& CUtlLinkedList<T,S,ML,I,M>::Element( I i ) const
  403. {
  404. return m_Memory[i].m_Element;
  405. }
  406. template <class T, class S, bool ML, class I, class M>
  407. inline T& CUtlLinkedList<T,S,ML,I,M>::operator[]( I i )
  408. {
  409. return m_Memory[i].m_Element;
  410. }
  411. template <class T, class S, bool ML, class I, class M>
  412. inline T const& CUtlLinkedList<T,S,ML,I,M>::operator[]( I i ) const
  413. {
  414. return m_Memory[i].m_Element;
  415. }
  416. //-----------------------------------------------------------------------------
  417. // list statistics
  418. //-----------------------------------------------------------------------------
  419. template <class T, class S, bool ML, class I, class M>
  420. inline int CUtlLinkedList<T,S,ML,I,M>::Count() const
  421. {
  422. #ifdef MULTILIST_PEDANTIC_ASSERTS
  423. AssertMsg( !ML, "CUtlLinkedList::Count() is meaningless for linked lists." );
  424. #endif
  425. return m_ElementCount;
  426. }
  427. template <class T, class S, bool ML, class I, class M>
  428. inline I CUtlLinkedList<T,S,ML,I,M>::MaxElementIndex() const
  429. {
  430. return m_Memory.NumAllocated();
  431. }
  432. //-----------------------------------------------------------------------------
  433. // Traversing the list
  434. //-----------------------------------------------------------------------------
  435. template <class T, class S, bool ML, class I, class M>
  436. inline I CUtlLinkedList<T,S,ML,I,M>::Head() const
  437. {
  438. return m_Head;
  439. }
  440. template <class T, class S, bool ML, class I, class M>
  441. inline I CUtlLinkedList<T,S,ML,I,M>::Tail() const
  442. {
  443. return m_Tail;
  444. }
  445. template <class T, class S, bool ML, class I, class M>
  446. inline I CUtlLinkedList<T,S,ML,I,M>::Previous( I i ) const
  447. {
  448. Assert( IsValidIndex(i) );
  449. return InternalElement(i).m_Previous;
  450. }
  451. template <class T, class S, bool ML, class I, class M>
  452. inline I CUtlLinkedList<T,S,ML,I,M>::Next( I i ) const
  453. {
  454. Assert( IsValidIndex(i) );
  455. return InternalElement(i).m_Next;
  456. }
  457. template <class T, class S, bool ML, class I, class M>
  458. inline I CUtlLinkedList<T,S,ML,I,M>::PrivateNext( I i ) const
  459. {
  460. return InternalElement(i).m_Next;
  461. }
  462. //-----------------------------------------------------------------------------
  463. // Are nodes in the list or valid?
  464. //-----------------------------------------------------------------------------
  465. #pragma warning(push)
  466. #pragma warning( disable: 4310 ) // Allows "(I)(S)M::INVALID_INDEX" below
  467. template <class T, class S, bool ML, class I, class M>
  468. inline bool CUtlLinkedList<T,S,ML,I,M>::IndexInRange( I index ) // Static method
  469. {
  470. // Since S is not necessarily the type returned by M, we need to check that M returns indices
  471. // which are representable by S. A common case is 'S === unsigned short', 'I == int', in which
  472. // case CUtlMemory will have 'InvalidIndex == (int)-1' (which casts to 65535 in S), and will
  473. // happily return elements at index 65535 and above.
  474. // Do some static checks here:
  475. // 'I' needs to be able to store 'S'
  476. COMPILE_TIME_ASSERT( sizeof(I) >= sizeof(S) );
  477. // 'S' should be unsigned (to avoid signed arithmetic errors for plausibly exhaustible ranges)
  478. COMPILE_TIME_ASSERT( ( sizeof(S) > 2 ) || ( ( (S)-1 ) > 0 ) );
  479. // M::INVALID_INDEX should be storable in S to avoid ambiguities (e.g. with 65536)
  480. COMPILE_TIME_ASSERT( ( M::INVALID_INDEX == -1 ) || ( M::INVALID_INDEX == (S)M::INVALID_INDEX ) );
  481. return ( ( (S)index == index ) && ( (S)index != InvalidIndex() ) );
  482. }
  483. #pragma warning(pop)
  484. template <class T, class S, bool ML, class I, class M>
  485. inline bool CUtlLinkedList<T,S,ML,I,M>::IsValidIndex( I i ) const
  486. {
  487. if ( !m_Memory.IsIdxValid( i ) )
  488. return false;
  489. if ( m_Memory.IsIdxAfter( i, m_LastAlloc ) )
  490. return false; // don't read values that have been allocated, but not constructed
  491. return ( m_Memory[ i ].m_Previous != i ) || ( m_Memory[ i ].m_Next == i );
  492. }
  493. template <class T, class S, bool ML, class I, class M>
  494. inline bool CUtlLinkedList<T,S,ML,I,M>::IsInList( I i ) const
  495. {
  496. if ( !m_Memory.IsIdxValid( i ) || m_Memory.IsIdxAfter( i, m_LastAlloc ) )
  497. return false; // don't read values that have been allocated, but not constructed
  498. return Previous( i ) != i;
  499. }
  500. /*
  501. template <class T>
  502. inline bool CUtlFixedLinkedList<T>::IsInList( int i ) const
  503. {
  504. return m_Memory.IsIdxValid( i ) && (Previous( i ) != i);
  505. }
  506. */
  507. //-----------------------------------------------------------------------------
  508. // Makes sure we have enough memory allocated to store a requested # of elements
  509. //-----------------------------------------------------------------------------
  510. template< class T, class S, bool ML, class I, class M >
  511. void CUtlLinkedList<T,S,ML,I,M>::EnsureCapacity( int num )
  512. {
  513. MEM_ALLOC_CREDIT_CLASS();
  514. m_Memory.EnsureCapacity(num);
  515. ResetDbgInfo();
  516. }
  517. template< class T, class S, bool ML, class I, class M >
  518. void CUtlLinkedList<T,S,ML,I,M>::SetGrowSize( int growSize )
  519. {
  520. RemoveAll();
  521. m_Memory.Init( growSize );
  522. ResetDbgInfo();
  523. }
  524. //-----------------------------------------------------------------------------
  525. // Deallocate memory
  526. //-----------------------------------------------------------------------------
  527. template <class T, class S, bool ML, class I, class M>
  528. void CUtlLinkedList<T,S,ML,I,M>::Purge()
  529. {
  530. RemoveAll();
  531. m_Memory.Purge();
  532. m_FirstFree = InvalidIndex();
  533. m_NumAlloced = 0;
  534. //Routing "m_LastAlloc = m_Memory.InvalidIterator();" through a local const to sidestep an internal compiler error on 360 builds
  535. const typename M::Iterator_t scInvalidIterator = m_Memory.InvalidIterator();
  536. m_LastAlloc = scInvalidIterator;
  537. ResetDbgInfo();
  538. }
  539. template<class T, class S, bool ML, class I, class M>
  540. void CUtlLinkedList<T,S,ML,I,M>::PurgeAndDeleteElements()
  541. {
  542. I iNext;
  543. for( I i=Head(); i != InvalidIndex(); i=iNext )
  544. {
  545. iNext = Next(i);
  546. delete Element(i);
  547. }
  548. Purge();
  549. }
  550. //-----------------------------------------------------------------------------
  551. // Node allocation/deallocation
  552. //-----------------------------------------------------------------------------
  553. template <class T, class S, bool ML, class I, class M>
  554. I CUtlLinkedList<T,S,ML,I,M>::AllocInternal( bool multilist )
  555. {
  556. Assert( !multilist || ML );
  557. #ifdef MULTILIST_PEDANTIC_ASSERTS
  558. Assert( multilist == ML );
  559. #endif
  560. I elem;
  561. if ( m_FirstFree == InvalidIndex() )
  562. {
  563. Assert( m_Memory.IsValidIterator( m_LastAlloc ) || m_ElementCount == 0 );
  564. typename M::Iterator_t it = m_Memory.IsValidIterator( m_LastAlloc ) ? m_Memory.Next( m_LastAlloc ) : m_Memory.First();
  565. if ( !m_Memory.IsValidIterator( it ) )
  566. {
  567. MEM_ALLOC_CREDIT_CLASS();
  568. m_Memory.Grow();
  569. ResetDbgInfo();
  570. it = m_Memory.IsValidIterator( m_LastAlloc ) ? m_Memory.Next( m_LastAlloc ) : m_Memory.First();
  571. Assert( m_Memory.IsValidIterator( it ) );
  572. if ( !m_Memory.IsValidIterator( it ) )
  573. {
  574. // We rarely if ever handle alloc failure. Continuing leads to corruption.
  575. Error( "CUtlLinkedList overflow! (exhausted memory allocator)\n" );
  576. return InvalidIndex();
  577. }
  578. }
  579. // We can overflow before the utlmemory overflows, since S != I
  580. if ( !IndexInRange( m_Memory.GetIndex( it ) ) )
  581. {
  582. // We rarely if ever handle alloc failure. Continuing leads to corruption.
  583. Error( "CUtlLinkedList overflow! (exhausted index range)\n" );
  584. return InvalidIndex();
  585. }
  586. m_LastAlloc = it;
  587. elem = m_Memory.GetIndex( m_LastAlloc );
  588. m_NumAlloced++;
  589. }
  590. else
  591. {
  592. elem = m_FirstFree;
  593. m_FirstFree = InternalElement( m_FirstFree ).m_Next;
  594. }
  595. if ( !multilist )
  596. {
  597. InternalElement( elem ).m_Next = elem;
  598. InternalElement( elem ).m_Previous = elem;
  599. }
  600. else
  601. {
  602. InternalElement( elem ).m_Next = InvalidIndex();
  603. InternalElement( elem ).m_Previous = InvalidIndex();
  604. }
  605. return elem;
  606. }
  607. template <class T, class S, bool ML, class I, class M>
  608. I CUtlLinkedList<T,S,ML,I,M>::Alloc( bool multilist )
  609. {
  610. I elem = AllocInternal( multilist );
  611. if ( elem == InvalidIndex() )
  612. return elem;
  613. Construct( &Element(elem) );
  614. return elem;
  615. }
  616. template <class T, class S, bool ML, class I, class M>
  617. void CUtlLinkedList<T,S,ML,I,M>::Free( I elem )
  618. {
  619. Assert( IsValidIndex(elem) && IndexInRange( elem ) );
  620. Unlink(elem);
  621. ListElem_t &internalElem = InternalElement(elem);
  622. Destruct( &internalElem.m_Element );
  623. internalElem.m_Next = m_FirstFree;
  624. m_FirstFree = elem;
  625. }
  626. //-----------------------------------------------------------------------------
  627. // Insertion methods; allocates and links (uses default constructor)
  628. //-----------------------------------------------------------------------------
  629. template <class T, class S, bool ML, class I, class M>
  630. I CUtlLinkedList<T,S,ML,I,M>::InsertBefore( I before )
  631. {
  632. // Make a new node
  633. I newNode = AllocInternal();
  634. if ( newNode == InvalidIndex() )
  635. return newNode;
  636. // Link it in
  637. LinkBefore( before, newNode );
  638. // Construct the data
  639. Construct( &Element(newNode) );
  640. return newNode;
  641. }
  642. template <class T, class S, bool ML, class I, class M>
  643. I CUtlLinkedList<T,S,ML,I,M>::InsertAfter( I after )
  644. {
  645. // Make a new node
  646. I newNode = AllocInternal();
  647. if ( newNode == InvalidIndex() )
  648. return newNode;
  649. // Link it in
  650. LinkAfter( after, newNode );
  651. // Construct the data
  652. Construct( &Element(newNode) );
  653. return newNode;
  654. }
  655. template <class T, class S, bool ML, class I, class M>
  656. inline I CUtlLinkedList<T,S,ML,I,M>::AddToHead( )
  657. {
  658. return InsertAfter( InvalidIndex() );
  659. }
  660. template <class T, class S, bool ML, class I, class M>
  661. inline I CUtlLinkedList<T,S,ML,I,M>::AddToTail( )
  662. {
  663. return InsertBefore( InvalidIndex() );
  664. }
  665. //-----------------------------------------------------------------------------
  666. // Insertion methods; allocates and links (uses copy constructor)
  667. //-----------------------------------------------------------------------------
  668. template <class T, class S, bool ML, class I, class M>
  669. I CUtlLinkedList<T,S,ML,I,M>::InsertBefore( I before, T const& src )
  670. {
  671. // Make a new node
  672. I newNode = AllocInternal();
  673. if ( newNode == InvalidIndex() )
  674. return newNode;
  675. // Link it in
  676. LinkBefore( before, newNode );
  677. // Construct the data
  678. CopyConstruct( &Element(newNode), src );
  679. return newNode;
  680. }
  681. template <class T, class S, bool ML, class I, class M>
  682. I CUtlLinkedList<T,S,ML,I,M>::InsertAfter( I after, T const& src )
  683. {
  684. // Make a new node
  685. I newNode = AllocInternal();
  686. if ( newNode == InvalidIndex() )
  687. return newNode;
  688. // Link it in
  689. LinkAfter( after, newNode );
  690. // Construct the data
  691. CopyConstruct( &Element(newNode), src );
  692. return newNode;
  693. }
  694. template <class T, class S, bool ML, class I, class M>
  695. inline I CUtlLinkedList<T,S,ML,I,M>::AddToHead( T const& src )
  696. {
  697. return InsertAfter( InvalidIndex(), src );
  698. }
  699. template <class T, class S, bool ML, class I, class M>
  700. inline I CUtlLinkedList<T,S,ML,I,M>::AddToTail( T const& src )
  701. {
  702. return InsertBefore( InvalidIndex(), src );
  703. }
  704. //-----------------------------------------------------------------------------
  705. // Removal methods
  706. //-----------------------------------------------------------------------------
  707. template<class T, class S, bool ML, class I, class M>
  708. I CUtlLinkedList<T,S,ML,I,M>::Find( const T &src ) const
  709. {
  710. // Cache the invalidIndex to avoid two levels of function calls on each iteration.
  711. I invalidIndex = InvalidIndex();
  712. for ( I i=Head(); i != invalidIndex; i = PrivateNext( i ) )
  713. {
  714. if ( Element( i ) == src )
  715. return i;
  716. }
  717. return InvalidIndex();
  718. }
  719. template<class T, class S, bool ML, class I, class M>
  720. bool CUtlLinkedList<T,S,ML,I,M>::FindAndRemove( const T &src )
  721. {
  722. I i = Find( src );
  723. if ( i == InvalidIndex() )
  724. {
  725. return false;
  726. }
  727. else
  728. {
  729. Remove( i );
  730. return true;
  731. }
  732. }
  733. template <class T, class S, bool ML, class I, class M>
  734. void CUtlLinkedList<T,S,ML,I,M>::Remove( I elem )
  735. {
  736. Free( elem );
  737. }
  738. template <class T, class S, bool ML, class I, class M>
  739. void CUtlLinkedList<T,S,ML,I,M>::RemoveAll()
  740. {
  741. // Have to do some convoluted stuff to invoke the destructor on all
  742. // valid elements for the multilist case (since we don't have all elements
  743. // connected to each other in a list).
  744. if ( m_LastAlloc == m_Memory.InvalidIterator() )
  745. {
  746. Assert( m_Head == InvalidIndex() );
  747. Assert( m_Tail == InvalidIndex() );
  748. Assert( m_FirstFree == InvalidIndex() );
  749. Assert( m_ElementCount == 0 );
  750. return;
  751. }
  752. if ( ML )
  753. {
  754. for ( typename M::Iterator_t it = m_Memory.First(); it != m_Memory.InvalidIterator(); it = m_Memory.Next( it ) )
  755. {
  756. I i = m_Memory.GetIndex( it );
  757. if ( IsValidIndex( i ) ) // skip elements already in the free list
  758. {
  759. ListElem_t &internalElem = InternalElement( i );
  760. Destruct( &internalElem.m_Element );
  761. internalElem.m_Previous = i;
  762. internalElem.m_Next = m_FirstFree;
  763. m_FirstFree = i;
  764. }
  765. if ( it == m_LastAlloc )
  766. break; // don't destruct elements that haven't ever been constructed
  767. }
  768. }
  769. else
  770. {
  771. I i = Head();
  772. I next;
  773. while ( i != InvalidIndex() )
  774. {
  775. next = Next( i );
  776. ListElem_t &internalElem = InternalElement( i );
  777. Destruct( &internalElem.m_Element );
  778. internalElem.m_Previous = i;
  779. internalElem.m_Next = next == InvalidIndex() ? m_FirstFree : next;
  780. i = next;
  781. }
  782. if ( Head() != InvalidIndex() )
  783. {
  784. m_FirstFree = Head();
  785. }
  786. }
  787. // Clear everything else out
  788. m_Head = InvalidIndex();
  789. m_Tail = InvalidIndex();
  790. m_ElementCount = 0;
  791. }
  792. //-----------------------------------------------------------------------------
  793. // list modification
  794. //-----------------------------------------------------------------------------
  795. template <class T, class S, bool ML, class I, class M>
  796. void CUtlLinkedList<T,S,ML,I,M>::LinkBefore( I before, I elem )
  797. {
  798. Assert( IsValidIndex(elem) );
  799. // Unlink it if it's in the list at the moment
  800. Unlink(elem);
  801. ListElem_t * RESTRICT pNewElem = &InternalElement(elem);
  802. // The element *after* our newly linked one is the one we linked before.
  803. pNewElem->m_Next = before;
  804. S newElem_mPrevious; // we need to hang on to this for the compairson against InvalidIndex()
  805. // below; otherwise we get a a load-hit-store on pNewElem->m_Previous, even
  806. // with RESTRICT
  807. if (before == InvalidIndex())
  808. {
  809. // In this case, we're linking to the end of the list, so reset the tail
  810. newElem_mPrevious = m_Tail;
  811. pNewElem->m_Previous = m_Tail;
  812. m_Tail = elem;
  813. }
  814. else
  815. {
  816. // Here, we're not linking to the end. Set the prev pointer to point to
  817. // the element we're linking.
  818. Assert( IsInList(before) );
  819. ListElem_t * RESTRICT beforeElem = &InternalElement(before);
  820. pNewElem->m_Previous = newElem_mPrevious = beforeElem->m_Previous;
  821. beforeElem->m_Previous = elem;
  822. }
  823. // Reset the head if we linked to the head of the list
  824. if (newElem_mPrevious == InvalidIndex())
  825. m_Head = elem;
  826. else
  827. InternalElement(newElem_mPrevious).m_Next = elem;
  828. // one more element baby
  829. ++m_ElementCount;
  830. }
  831. template <class T, class S, bool ML, class I, class M>
  832. void CUtlLinkedList<T,S,ML,I,M>::LinkAfter( I after, I elem )
  833. {
  834. Assert( IsValidIndex(elem) );
  835. // Unlink it if it's in the list at the moment
  836. if ( IsInList(elem) )
  837. Unlink(elem);
  838. ListElem_t& newElem = InternalElement(elem);
  839. // The element *before* our newly linked one is the one we linked after
  840. newElem.m_Previous = after;
  841. if (after == InvalidIndex())
  842. {
  843. // In this case, we're linking to the head of the list, reset the head
  844. newElem.m_Next = m_Head;
  845. m_Head = elem;
  846. }
  847. else
  848. {
  849. // Here, we're not linking to the end. Set the next pointer to point to
  850. // the element we're linking.
  851. Assert( IsInList(after) );
  852. ListElem_t& afterElem = InternalElement(after);
  853. newElem.m_Next = afterElem.m_Next;
  854. afterElem.m_Next = elem;
  855. }
  856. // Reset the tail if we linked to the tail of the list
  857. if (newElem.m_Next == InvalidIndex())
  858. m_Tail = elem;
  859. else
  860. InternalElement(newElem.m_Next).m_Previous = elem;
  861. // one more element baby
  862. ++m_ElementCount;
  863. }
  864. template <class T, class S, bool ML, class I, class M>
  865. void CUtlLinkedList<T,S,ML,I,M>::Unlink( I elem )
  866. {
  867. Assert( IsValidIndex(elem) );
  868. if (IsInList(elem))
  869. {
  870. ListElem_t * RESTRICT pOldElem = &m_Memory[ elem ];
  871. // If we're the first guy, reset the head
  872. // otherwise, make our previous node's next pointer = our next
  873. if ( pOldElem->m_Previous != InvalidIndex() )
  874. {
  875. m_Memory[ pOldElem->m_Previous ].m_Next = pOldElem->m_Next;
  876. }
  877. else
  878. {
  879. m_Head = pOldElem->m_Next;
  880. }
  881. // If we're the last guy, reset the tail
  882. // otherwise, make our next node's prev pointer = our prev
  883. if ( pOldElem->m_Next != InvalidIndex() )
  884. {
  885. m_Memory[ pOldElem->m_Next ].m_Previous = pOldElem->m_Previous;
  886. }
  887. else
  888. {
  889. m_Tail = pOldElem->m_Previous;
  890. }
  891. // This marks this node as not in the list,
  892. // but not in the free list either
  893. pOldElem->m_Previous = pOldElem->m_Next = elem;
  894. // One less puppy
  895. --m_ElementCount;
  896. }
  897. }
  898. template <class T, class S, bool ML, class I, class M>
  899. inline void CUtlLinkedList<T,S,ML,I,M>::LinkToHead( I elem )
  900. {
  901. LinkAfter( InvalidIndex(), elem );
  902. }
  903. template <class T, class S, bool ML, class I, class M>
  904. inline void CUtlLinkedList<T,S,ML,I,M>::LinkToTail( I elem )
  905. {
  906. LinkBefore( InvalidIndex(), elem );
  907. }
  908. //-----------------------------------------------------------------------------
  909. // Class to drop in to replace a CUtlLinkedList that needs to be more memory agressive
  910. //-----------------------------------------------------------------------------
  911. DECLARE_POINTER_HANDLE( UtlPtrLinkedListIndex_t ); // to enforce correct usage
  912. template < typename T >
  913. class CUtlPtrLinkedList
  914. {
  915. public:
  916. CUtlPtrLinkedList()
  917. : m_pFirst( NULL ),
  918. m_nElems( 0 )
  919. {
  920. COMPILE_TIME_ASSERT( sizeof(IndexType_t) == sizeof(Node_t *) );
  921. }
  922. ~CUtlPtrLinkedList()
  923. {
  924. RemoveAll();
  925. }
  926. typedef UtlPtrLinkedListIndex_t IndexType_t;
  927. T &operator[]( IndexType_t i )
  928. {
  929. return (( Node_t * )i)->elem;
  930. }
  931. const T &operator[]( IndexType_t i ) const
  932. {
  933. return (( Node_t * )i)->elem;
  934. }
  935. IndexType_t AddToTail()
  936. {
  937. return DoInsertBefore( (IndexType_t)m_pFirst, NULL );
  938. }
  939. IndexType_t AddToTail( T const& src )
  940. {
  941. return DoInsertBefore( (IndexType_t)m_pFirst, &src );
  942. }
  943. IndexType_t AddToHead()
  944. {
  945. IndexType_t result = DoInsertBefore( (IndexType_t)m_pFirst, NULL );
  946. m_pFirst = ((Node_t *)result);
  947. return result;
  948. }
  949. IndexType_t AddToHead( T const& src )
  950. {
  951. IndexType_t result = DoInsertBefore( (IndexType_t)m_pFirst, &src );
  952. m_pFirst = ((Node_t *)result);
  953. return result;
  954. }
  955. IndexType_t InsertBefore( IndexType_t before )
  956. {
  957. return DoInsertBefore( before, NULL );
  958. }
  959. IndexType_t InsertAfter( IndexType_t after )
  960. {
  961. Node_t *pBefore = ((Node_t *)after)->next;
  962. return DoInsertBefore( pBefore, NULL );
  963. }
  964. IndexType_t InsertBefore( IndexType_t before, T const& src )
  965. {
  966. return DoInsertBefore( before, &src );
  967. }
  968. IndexType_t InsertAfter( IndexType_t after, T const& src )
  969. {
  970. Node_t *pBefore = ((Node_t *)after)->next;
  971. return DoInsertBefore( pBefore, &src );
  972. }
  973. void Remove( IndexType_t elem )
  974. {
  975. Node_t *p = (Node_t *)elem;
  976. if ( p->pNext == p )
  977. {
  978. m_pFirst = NULL;
  979. }
  980. else
  981. {
  982. if ( m_pFirst == p )
  983. {
  984. m_pFirst = p->pNext;
  985. }
  986. p->pNext->pPrev = p->pPrev;
  987. p->pPrev->pNext = p->pNext;
  988. }
  989. delete p;
  990. m_nElems--;
  991. }
  992. void RemoveAll()
  993. {
  994. Node_t *p = m_pFirst;
  995. if ( p )
  996. {
  997. do
  998. {
  999. Node_t *pNext = p->pNext;
  1000. delete p;
  1001. p = pNext;
  1002. } while( p != m_pFirst );
  1003. }
  1004. m_pFirst = NULL;
  1005. m_nElems = 0;
  1006. }
  1007. int Count() const
  1008. {
  1009. return m_nElems;
  1010. }
  1011. IndexType_t Head() const
  1012. {
  1013. return (IndexType_t)m_pFirst;
  1014. }
  1015. IndexType_t Next( IndexType_t i ) const
  1016. {
  1017. Node_t *p = ((Node_t *)i)->pNext;
  1018. if ( p != m_pFirst )
  1019. {
  1020. return (IndexType_t)p;
  1021. }
  1022. return NULL;
  1023. }
  1024. bool IsValidIndex( IndexType_t i ) const
  1025. {
  1026. Node_t *p = ((Node_t *)i);
  1027. return ( p && p->pNext && p->pPrev );
  1028. }
  1029. inline static IndexType_t InvalidIndex()
  1030. {
  1031. return NULL;
  1032. }
  1033. private:
  1034. struct Node_t
  1035. {
  1036. Node_t() {}
  1037. Node_t( const T &_elem ) : elem( _elem ) {}
  1038. T elem;
  1039. Node_t *pPrev, *pNext;
  1040. };
  1041. Node_t *AllocNode( const T *pCopyFrom )
  1042. {
  1043. MEM_ALLOC_CREDIT_CLASS();
  1044. Node_t *p;
  1045. if ( !pCopyFrom )
  1046. {
  1047. p = new Node_t;
  1048. }
  1049. else
  1050. {
  1051. p = new Node_t( *pCopyFrom );
  1052. }
  1053. return p;
  1054. }
  1055. IndexType_t DoInsertBefore( IndexType_t before, const T *pCopyFrom )
  1056. {
  1057. Node_t *p = AllocNode( pCopyFrom );
  1058. Node_t *pBefore = (Node_t *)before;
  1059. if ( pBefore )
  1060. {
  1061. p->pNext = pBefore;
  1062. p->pPrev = pBefore->pPrev;
  1063. pBefore->pPrev = p;
  1064. p->pPrev->pNext = p;
  1065. }
  1066. else
  1067. {
  1068. Assert( !m_pFirst );
  1069. m_pFirst = p->pNext = p->pPrev = p;
  1070. }
  1071. m_nElems++;
  1072. return (IndexType_t)p;
  1073. }
  1074. Node_t *m_pFirst;
  1075. unsigned m_nElems;
  1076. };
  1077. //-----------------------------------------------------------------------------
  1078. #endif // UTLLINKEDLIST_H