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.

1294 lines
34 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( auto iteratorName=(listName).Head(); (listName).IsUtlLinkedList && iteratorName != (listName).InvalidIndex(); iteratorName = (listName).Next( iteratorName ) )
  23. #define FOR_EACH_LL_BACK( listName, iteratorName ) \
  24. for( auto iteratorName=(listName).Tail(); (listName).IsUtlLinkedList && iteratorName != (listName).InvalidIndex(); iteratorName = (listName).Previous( iteratorName ) )
  25. //-----------------------------------------------------------------------------
  26. // class CUtlLinkedList:
  27. // description:
  28. // A lovely index-based linked list! T is the class type, I is the index
  29. // type, which usually should be an unsigned short or smaller. However,
  30. // you must avoid using 16- or 8-bit arithmetic on PowerPC architectures;
  31. // therefore you should not use UtlLinkedListElem_t::I as the type of
  32. // a local variable... ever. PowerPC integer arithmetic must be 32- or
  33. // 64-bit only; otherwise performance plummets.
  34. //-----------------------------------------------------------------------------
  35. template <class T, class I>
  36. struct UtlLinkedListElem_t
  37. {
  38. T m_Element;
  39. I m_Previous;
  40. I m_Next;
  41. private:
  42. // No copy constructor for these...
  43. UtlLinkedListElem_t( const UtlLinkedListElem_t& );
  44. };
  45. // Class S is the storage type; the type you can use to save off indices in
  46. // persistent memory. Class I is the iterator type, which is what should be used
  47. // in local scopes. I defaults to be S, but be aware that on the 360, 16-bit
  48. // arithmetic is catastrophically slow. Therefore you should try to save shorts
  49. // in memory, but always operate on 32's or 64's in local scope.
  50. // The ideal parameter order would be TSMI (you are more likely to override M than I)
  51. // but since M depends on I we can't have the defaults in that order, alas.
  52. template <class T, class S = unsigned short, bool ML = false, class I = S, class M = CUtlMemory< UtlLinkedListElem_t<T, S>, I > >
  53. class CUtlLinkedList
  54. {
  55. public:
  56. typedef T ElemType_t;
  57. typedef S IndexType_t; // should really be called IndexStorageType_t, but that would be a huge change
  58. typedef I IndexLocalType_t;
  59. typedef M MemoryAllocator_t;
  60. enum { IsUtlLinkedList = true }; // Used to match this at compiletime
  61. // constructor, destructor
  62. CUtlLinkedList( int growSize = 0, int initSize = 0 );
  63. ~CUtlLinkedList();
  64. CUtlLinkedList( const CUtlLinkedList& ) = delete;
  65. CUtlLinkedList& operator=( const CUtlLinkedList& ) = delete;
  66. // gets particular elements
  67. T& Element( I i );
  68. T const& Element( I i ) const;
  69. T& operator[]( I i );
  70. T const& operator[]( I i ) const;
  71. // Make sure we have a particular amount of memory
  72. void EnsureCapacity( int num );
  73. void SetGrowSize( int growSize );
  74. // Memory deallocation
  75. void Purge();
  76. // Delete all the elements then call Purge.
  77. void PurgeAndDeleteElements();
  78. // Insertion methods....
  79. I InsertBefore( I before );
  80. I InsertAfter( I after );
  81. I AddToHead( );
  82. I AddToTail( );
  83. I InsertBefore( I before, T const& src );
  84. I InsertAfter( I after, T const& src );
  85. I AddToHead( T const& src );
  86. I AddToTail( T const& src );
  87. // Find an element and return its index or InvalidIndex() if it couldn't be found.
  88. I Find( const T &src ) const;
  89. // Look for the element. If it exists, remove it and return true. Otherwise, return false.
  90. bool FindAndRemove( const T &src );
  91. // Removal methods
  92. void Remove( I elem );
  93. void RemoveAll();
  94. // Allocation/deallocation methods
  95. // If multilist == true, then list list may contain many
  96. // non-connected lists, and IsInList and Head + Tail are meaningless...
  97. I Alloc( bool multilist = false );
  98. void Free( I elem );
  99. // Identify the owner of this linked list's memory:
  100. void SetAllocOwner( const char *pszAllocOwner );
  101. // list modification
  102. void LinkBefore( I before, I elem );
  103. void LinkAfter( I after, I elem );
  104. void Unlink( I elem );
  105. void LinkToHead( I elem );
  106. void LinkToTail( I elem );
  107. // invalid index (M will never allocate an element at this index)
  108. inline static S InvalidIndex() { return ( S )M::InvalidIndex(); }
  109. // Is a given index valid to use? (representible by S and not the invalid index)
  110. static bool IndexInRange( I index );
  111. inline static size_t ElementSize() { return sizeof( ListElem_t ); }
  112. // list statistics
  113. int Count() const;
  114. inline bool IsEmpty( void ) const
  115. {
  116. return ( Head() == InvalidIndex() );
  117. }
  118. I MaxElementIndex() const;
  119. I NumAllocated( void ) const { return m_NumAlloced; }
  120. // Traversing the list
  121. I Head() const;
  122. I Tail() const;
  123. I Previous( I i ) const;
  124. I Next( I i ) const;
  125. // STL compatible const_iterator class
  126. template < typename List_t >
  127. class _CUtlLinkedList_constiterator_t
  128. {
  129. public:
  130. typedef typename List_t::ElemType_t ElemType_t;
  131. typedef typename List_t::IndexType_t IndexType_t;
  132. // Default constructor -- gives a currently unusable iterator.
  133. _CUtlLinkedList_constiterator_t()
  134. : m_list( 0 )
  135. , m_index( List_t::InvalidIndex() )
  136. {
  137. }
  138. // Normal constructor.
  139. _CUtlLinkedList_constiterator_t( const List_t& list, IndexType_t index )
  140. : m_list( &list )
  141. , m_index( index )
  142. {
  143. }
  144. // Pre-increment operator++. This is the most efficient increment
  145. // operator so it should always be used.
  146. _CUtlLinkedList_constiterator_t& operator++()
  147. {
  148. m_index = m_list->Next( m_index );
  149. return *this;
  150. }
  151. // Post-increment operator++. This is less efficient than pre-increment.
  152. _CUtlLinkedList_constiterator_t operator++(int)
  153. {
  154. // Copy ourselves.
  155. _CUtlLinkedList_constiterator_t temp = *this;
  156. // Increment ourselves.
  157. ++*this;
  158. // Return the copy.
  159. return temp;
  160. }
  161. // Pre-decrement operator--. This is the most efficient decrement
  162. // operator so it should always be used.
  163. _CUtlLinkedList_constiterator_t& operator--()
  164. {
  165. Assert( m_index != m_list->Head() );
  166. if ( m_index == m_list->InvalidIndex() )
  167. {
  168. m_index = m_list->Tail();
  169. }
  170. else
  171. {
  172. m_index = m_list->Previous( m_index );
  173. }
  174. return *this;
  175. }
  176. // Post-decrement operator--. This is less efficient than post-decrement.
  177. _CUtlLinkedList_constiterator_t operator--(int)
  178. {
  179. // Copy ourselves.
  180. _CUtlLinkedList_constiterator_t temp = *this;
  181. // Decrement ourselves.
  182. --*this;
  183. // Return the copy.
  184. return temp;
  185. }
  186. bool operator==( const _CUtlLinkedList_constiterator_t& other) const
  187. {
  188. Assert( m_list == other.m_list );
  189. return m_index == other.m_index;
  190. }
  191. bool operator!=( const _CUtlLinkedList_constiterator_t& other) const
  192. {
  193. Assert( m_list == other.m_list );
  194. return m_index != other.m_index;
  195. }
  196. const ElemType_t& operator*() const
  197. {
  198. return m_list->Element( m_index );
  199. }
  200. const ElemType_t* operator->() const
  201. {
  202. return (&**this);
  203. }
  204. protected:
  205. // Use a pointer rather than a reference so that we can support
  206. // assignment of iterators.
  207. const List_t* m_list;
  208. IndexType_t m_index;
  209. };
  210. // STL compatible iterator class, using derivation so that a non-const
  211. // list can return a const_iterator.
  212. template < typename List_t >
  213. class _CUtlLinkedList_iterator_t : public _CUtlLinkedList_constiterator_t< List_t >
  214. {
  215. public:
  216. typedef typename List_t::ElemType_t ElemType_t;
  217. typedef typename List_t::IndexType_t IndexType_t;
  218. typedef _CUtlLinkedList_constiterator_t< List_t > Base;
  219. // Default constructor -- gives a currently unusable iterator.
  220. _CUtlLinkedList_iterator_t()
  221. {
  222. }
  223. // Normal constructor.
  224. _CUtlLinkedList_iterator_t( const List_t& list, IndexType_t index )
  225. : _CUtlLinkedList_constiterator_t< List_t >( list, index )
  226. {
  227. }
  228. // Pre-increment operator++. This is the most efficient increment
  229. // operator so it should always be used.
  230. _CUtlLinkedList_iterator_t& operator++()
  231. {
  232. Base::m_index = Base::m_list->Next( Base::m_index );
  233. return *this;
  234. }
  235. // Post-increment operator++. This is less efficient than pre-increment.
  236. _CUtlLinkedList_iterator_t operator++(int)
  237. {
  238. // Copy ourselves.
  239. _CUtlLinkedList_iterator_t temp = *this;
  240. // Increment ourselves.
  241. ++*this;
  242. // Return the copy.
  243. return temp;
  244. }
  245. // Pre-decrement operator--. This is the most efficient decrement
  246. // operator so it should always be used.
  247. _CUtlLinkedList_iterator_t& operator--()
  248. {
  249. Assert( Base::m_index != Base::m_list->Head() );
  250. if ( Base::m_index == Base::m_list->InvalidIndex() )
  251. {
  252. Base::m_index = Base::m_list->Tail();
  253. }
  254. else
  255. {
  256. Base::m_index = Base::m_list->Previous( Base::m_index );
  257. }
  258. return *this;
  259. }
  260. // Post-decrement operator--. This is less efficient than post-decrement.
  261. _CUtlLinkedList_iterator_t operator--(int)
  262. {
  263. // Copy ourselves.
  264. _CUtlLinkedList_iterator_t temp = *this;
  265. // Decrement ourselves.
  266. --*this;
  267. // Return the copy.
  268. return temp;
  269. }
  270. ElemType_t& operator*() const
  271. {
  272. // Const_cast to allow sharing the implementation with the
  273. // base class.
  274. List_t* pMutableList = const_cast<List_t*>( Base::m_list );
  275. return pMutableList->Element( Base::m_index );
  276. }
  277. ElemType_t* operator->() const
  278. {
  279. return (&**this);
  280. }
  281. };
  282. typedef _CUtlLinkedList_constiterator_t<CUtlLinkedList<T, S, ML, I, M> > const_iterator;
  283. typedef _CUtlLinkedList_iterator_t<CUtlLinkedList<T, S, ML, I, M> > iterator;
  284. const_iterator begin() const
  285. {
  286. return const_iterator( *this, Head() );
  287. }
  288. iterator begin()
  289. {
  290. return iterator( *this, Head() );
  291. }
  292. const_iterator end() const
  293. {
  294. return const_iterator( *this, InvalidIndex() );
  295. }
  296. iterator end()
  297. {
  298. return iterator( *this, InvalidIndex() );
  299. }
  300. // Are nodes in the list or valid?
  301. bool IsValidIndex( I i ) const;
  302. bool IsInList( I i ) const;
  303. protected:
  304. // What the linked list element looks like
  305. typedef UtlLinkedListElem_t<T, S> ListElem_t;
  306. // constructs the class
  307. I AllocInternal( bool multilist = false ) RESTRICT;
  308. void ConstructList();
  309. // Gets at the list element....
  310. ListElem_t& InternalElement( I i ) { return m_Memory[i]; }
  311. ListElem_t const& InternalElement( I i ) const { return m_Memory[i]; }
  312. M m_Memory;
  313. I m_Head;
  314. I m_Tail;
  315. I m_FirstFree;
  316. I m_ElementCount; // The number actually in the list
  317. I m_NumAlloced; // The number of allocated elements
  318. typename M::Iterator_t m_LastAlloc; // the last index allocated
  319. // For debugging purposes;
  320. // it's in release builds so this can be used in libraries correctly
  321. ListElem_t *m_pElements;
  322. FORCEINLINE M const &Memory( void ) const
  323. {
  324. return m_Memory;
  325. }
  326. void ResetDbgInfo()
  327. {
  328. m_pElements = m_Memory.Base();
  329. }
  330. };
  331. // this is kind of ugly, but until C++ gets templatized typedefs in C++0x, it's our only choice
  332. template < class T >
  333. class CUtlFixedLinkedList : public CUtlLinkedList< T, intp, true, intp, CUtlFixedMemory< UtlLinkedListElem_t< T, intp > > >
  334. {
  335. public:
  336. CUtlFixedLinkedList( int growSize = 0, int initSize = 0 )
  337. : CUtlLinkedList< T, intp, true, intp, CUtlFixedMemory< UtlLinkedListElem_t< T, intp > > >( growSize, initSize ) {}
  338. bool IsValidIndex( intp i ) const
  339. {
  340. if ( !this->Memory().IsIdxValid( i ) )
  341. return false;
  342. #ifdef _DEBUG // it's safe to skip this here, since the only way to get indices after m_LastAlloc is to use MaxElementIndex
  343. if ( this->Memory().IsIdxAfter( i, this->m_LastAlloc ) )
  344. {
  345. Assert( 0 );
  346. return false; // don't read values that have been allocated, but not constructed
  347. }
  348. #endif
  349. return ( this->Memory()[ i ].m_Previous != i ) || ( this->Memory()[ i ].m_Next == i );
  350. }
  351. private:
  352. int MaxElementIndex() const { Assert( 0 ); return this->InvalidIndex(); } // fixedmemory containers don't support iteration from 0..maxelements-1
  353. void ResetDbgInfo() {}
  354. };
  355. // this is kind of ugly, but until C++ gets templatized typedefs in C++0x, it's our only choice
  356. template < class T, class I = unsigned short >
  357. class CUtlBlockLinkedList : public CUtlLinkedList< T, I, true, I, CUtlBlockMemory< UtlLinkedListElem_t< T, I >, I > >
  358. {
  359. public:
  360. CUtlBlockLinkedList( int growSize = 0, int initSize = 0 )
  361. : CUtlLinkedList< T, I, true, I, CUtlBlockMemory< UtlLinkedListElem_t< T, I >, I > >( growSize, initSize ) {}
  362. protected:
  363. void ResetDbgInfo() {}
  364. };
  365. //-----------------------------------------------------------------------------
  366. // constructor, destructor
  367. //-----------------------------------------------------------------------------
  368. template <class T, class S, bool ML, class I, class M>
  369. CUtlLinkedList<T,S,ML,I,M>::CUtlLinkedList( int growSize, int initSize ) :
  370. m_Memory( growSize, initSize ), m_LastAlloc( m_Memory.InvalidIterator() )
  371. {
  372. #if !defined( PLATFORM_WINDOWS_PC64 ) && !defined( PLATFORM_64BITS )
  373. // Prevent signed non-int datatypes
  374. COMPILE_TIME_ASSERT( sizeof(S) == 4 || ( ( (S)-1 ) > 0 ) );
  375. #endif
  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. //-----------------------------------------------------------------------------
  458. // Are nodes in the list or valid?
  459. //-----------------------------------------------------------------------------
  460. #pragma warning(push)
  461. #pragma warning( disable: 4310 ) // Allows "(I)(S)M::INVALID_INDEX" below
  462. template <class T, class S, bool ML, class I, class M>
  463. inline bool CUtlLinkedList<T,S,ML,I,M>::IndexInRange( I index ) // Static method
  464. {
  465. // Since S is not necessarily the type returned by M, we need to check that M returns indices
  466. // which are representable by S. A common case is 'S === unsigned short', 'I == int', in which
  467. // case CUtlMemory will have 'InvalidIndex == (int)-1' (which casts to 65535 in S), and will
  468. // happily return elements at index 65535 and above.
  469. // Do some static checks here:
  470. // 'I' needs to be able to store 'S'
  471. // These COMPILE_TIME_ASSERT checks need to be in individual scopes to avoid build breaks
  472. // on MacOS and Linux due to a gcc bug.
  473. { COMPILE_TIME_ASSERT( sizeof(I) >= sizeof(S) ); }
  474. // 'S' should be unsigned (to avoid signed arithmetic errors for plausibly exhaustible ranges)
  475. { COMPILE_TIME_ASSERT( ( sizeof(S) > 2 ) || ( ( (S)-1 ) > 0 ) ); }
  476. // M::INVALID_INDEX should be storable in S to avoid ambiguities (e.g. with 65536)
  477. { COMPILE_TIME_ASSERT( ( M::INVALID_INDEX == -1 ) || ( M::INVALID_INDEX == (S)M::INVALID_INDEX ) ); }
  478. return ( ( (S)index == index ) && ( (S)index != InvalidIndex() ) );
  479. }
  480. #pragma warning(pop)
  481. template <class T, class S, bool ML, class I, class M>
  482. inline bool CUtlLinkedList<T,S,ML,I,M>::IsValidIndex( I i ) const
  483. {
  484. if ( !m_Memory.IsIdxValid( i ) )
  485. return false;
  486. if ( m_Memory.IsIdxAfter( i, m_LastAlloc ) )
  487. return false; // don't read values that have been allocated, but not constructed
  488. return ( m_Memory[ i ].m_Previous != i ) || ( m_Memory[ i ].m_Next == i );
  489. }
  490. template <class T, class S, bool ML, class I, class M>
  491. inline bool CUtlLinkedList<T,S,ML,I,M>::IsInList( I i ) const
  492. {
  493. if ( !m_Memory.IsIdxValid( i ) || m_Memory.IsIdxAfter( i, m_LastAlloc ) )
  494. return false; // don't read values that have been allocated, but not constructed
  495. return Previous( i ) != i;
  496. }
  497. /*
  498. template <class T>
  499. inline bool CUtlFixedLinkedList<T>::IsInList( int i ) const
  500. {
  501. return m_Memory.IsIdxValid( i ) && (Previous( i ) != i);
  502. }
  503. */
  504. //-----------------------------------------------------------------------------
  505. // Makes sure we have enough memory allocated to store a requested # of elements
  506. //-----------------------------------------------------------------------------
  507. template< class T, class S, bool ML, class I, class M >
  508. void CUtlLinkedList<T,S,ML,I,M>::EnsureCapacity( int num )
  509. {
  510. MEM_ALLOC_CREDIT_CLASS();
  511. m_Memory.EnsureCapacity(num);
  512. ResetDbgInfo();
  513. }
  514. template< class T, class S, bool ML, class I, class M >
  515. void CUtlLinkedList<T,S,ML,I,M>::SetGrowSize( int growSize )
  516. {
  517. RemoveAll();
  518. m_Memory.Init( growSize );
  519. ResetDbgInfo();
  520. }
  521. template< class T, class S, bool ML, class I, class M >
  522. void CUtlLinkedList<T,S,ML,I,M>::SetAllocOwner( const char *pszAllocOwner )
  523. {
  524. m_Memory.SetAllocOwner( pszAllocOwner );
  525. }
  526. //-----------------------------------------------------------------------------
  527. // Deallocate memory
  528. //-----------------------------------------------------------------------------
  529. template <class T, class S, bool ML, class I, class M>
  530. void CUtlLinkedList<T,S,ML,I,M>::Purge()
  531. {
  532. RemoveAll();
  533. m_Memory.Purge();
  534. m_FirstFree = InvalidIndex();
  535. m_NumAlloced = 0;
  536. //Routing "m_LastAlloc = m_Memory.InvalidIterator();" through a local const to sidestep an internal compiler error on 360 builds
  537. const typename M::Iterator_t scInvalidIterator = m_Memory.InvalidIterator();
  538. m_LastAlloc = scInvalidIterator;
  539. ResetDbgInfo();
  540. }
  541. template<class T, class S, bool ML, class I, class M>
  542. void CUtlLinkedList<T,S,ML,I,M>::PurgeAndDeleteElements()
  543. {
  544. I iNext;
  545. for( I i=Head(); i != InvalidIndex(); i=iNext )
  546. {
  547. iNext = Next(i);
  548. delete Element(i);
  549. }
  550. Purge();
  551. }
  552. //-----------------------------------------------------------------------------
  553. // Node allocation/deallocation
  554. //-----------------------------------------------------------------------------
  555. template <class T, class S, bool ML, class I, class M>
  556. I CUtlLinkedList<T,S,ML,I,M>::AllocInternal( bool multilist ) RESTRICT
  557. {
  558. Assert( !multilist || ML );
  559. #ifdef MULTILIST_PEDANTIC_ASSERTS
  560. Assert( multilist == ML );
  561. #endif
  562. I elem;
  563. if ( m_FirstFree == InvalidIndex() )
  564. {
  565. Assert( m_Memory.IsValidIterator( m_LastAlloc ) || m_ElementCount == 0 );
  566. typename M::Iterator_t it = m_Memory.IsValidIterator( m_LastAlloc ) ? m_Memory.Next( m_LastAlloc ) : m_Memory.First();
  567. if ( !m_Memory.IsValidIterator( it ) )
  568. {
  569. MEM_ALLOC_CREDIT_CLASS();
  570. m_Memory.Grow();
  571. ResetDbgInfo();
  572. it = m_Memory.IsValidIterator( m_LastAlloc ) ? m_Memory.Next( m_LastAlloc ) : m_Memory.First();
  573. Assert( m_Memory.IsValidIterator( it ) );
  574. if ( !m_Memory.IsValidIterator( it ) )
  575. {
  576. // We rarely if ever handle alloc failure. Continuing leads to corruption.
  577. Error( "CUtlLinkedList overflow! (exhausted memory allocator)\n" );
  578. return InvalidIndex();
  579. }
  580. }
  581. // We can overflow before the utlmemory overflows, since S != I
  582. if ( !IndexInRange( m_Memory.GetIndex( it ) ) )
  583. {
  584. // We rarely if ever handle alloc failure. Continuing leads to corruption.
  585. Error( "CUtlLinkedList overflow! (exhausted index range)\n" );
  586. return InvalidIndex();
  587. }
  588. m_LastAlloc = it;
  589. elem = m_Memory.GetIndex( m_LastAlloc );
  590. m_NumAlloced++;
  591. }
  592. else
  593. {
  594. elem = m_FirstFree;
  595. m_FirstFree = InternalElement( m_FirstFree ).m_Next;
  596. }
  597. if ( !multilist )
  598. {
  599. InternalElement( elem ).m_Next = elem;
  600. InternalElement( elem ).m_Previous = elem;
  601. }
  602. else
  603. {
  604. InternalElement( elem ).m_Next = InvalidIndex();
  605. InternalElement( elem ).m_Previous = InvalidIndex();
  606. }
  607. return elem;
  608. }
  609. template <class T, class S, bool ML, class I, class M>
  610. I CUtlLinkedList<T,S,ML,I,M>::Alloc( bool multilist )
  611. {
  612. I elem = AllocInternal( multilist );
  613. if ( elem == InvalidIndex() )
  614. return elem;
  615. Construct( &Element(elem) );
  616. return elem;
  617. }
  618. template <class T, class S, bool ML, class I, class M>
  619. void CUtlLinkedList<T,S,ML,I,M>::Free( I elem )
  620. {
  621. Assert( IsValidIndex(elem) && IndexInRange( elem ) );
  622. Unlink(elem);
  623. ListElem_t &internalElem = InternalElement(elem);
  624. Destruct( &internalElem.m_Element );
  625. internalElem.m_Next = m_FirstFree;
  626. m_FirstFree = elem;
  627. }
  628. //-----------------------------------------------------------------------------
  629. // Insertion methods; allocates and links (uses default constructor)
  630. //-----------------------------------------------------------------------------
  631. template <class T, class S, bool ML, class I, class M>
  632. I CUtlLinkedList<T,S,ML,I,M>::InsertBefore( I before )
  633. {
  634. // Make a new node
  635. I newNode = AllocInternal();
  636. if ( newNode == InvalidIndex() )
  637. return newNode;
  638. // Link it in
  639. LinkBefore( before, newNode );
  640. // Construct the data
  641. Construct( &Element(newNode) );
  642. return newNode;
  643. }
  644. template <class T, class S, bool ML, class I, class M>
  645. I CUtlLinkedList<T,S,ML,I,M>::InsertAfter( I after )
  646. {
  647. // Make a new node
  648. I newNode = AllocInternal();
  649. if ( newNode == InvalidIndex() )
  650. return newNode;
  651. // Link it in
  652. LinkAfter( after, newNode );
  653. // Construct the data
  654. Construct( &Element(newNode) );
  655. return newNode;
  656. }
  657. template <class T, class S, bool ML, class I, class M>
  658. inline I CUtlLinkedList<T,S,ML,I,M>::AddToHead( )
  659. {
  660. return InsertAfter( InvalidIndex() );
  661. }
  662. template <class T, class S, bool ML, class I, class M>
  663. inline I CUtlLinkedList<T,S,ML,I,M>::AddToTail( )
  664. {
  665. return InsertBefore( InvalidIndex() );
  666. }
  667. //-----------------------------------------------------------------------------
  668. // Insertion methods; allocates and links (uses copy constructor)
  669. //-----------------------------------------------------------------------------
  670. template <class T, class S, bool ML, class I, class M>
  671. I CUtlLinkedList<T,S,ML,I,M>::InsertBefore( I before, T const& src )
  672. {
  673. // Make a new node
  674. I newNode = AllocInternal();
  675. if ( newNode == InvalidIndex() )
  676. return newNode;
  677. // Link it in
  678. LinkBefore( before, newNode );
  679. // Construct the data
  680. CopyConstruct( &Element(newNode), src );
  681. return newNode;
  682. }
  683. template <class T, class S, bool ML, class I, class M>
  684. I CUtlLinkedList<T,S,ML,I,M>::InsertAfter( I after, T const& src )
  685. {
  686. // Make a new node
  687. I newNode = AllocInternal();
  688. if ( newNode == InvalidIndex() )
  689. return newNode;
  690. // Link it in
  691. LinkAfter( after, newNode );
  692. // Construct the data
  693. CopyConstruct( &Element(newNode), src );
  694. return newNode;
  695. }
  696. template <class T, class S, bool ML, class I, class M>
  697. inline I CUtlLinkedList<T,S,ML,I,M>::AddToHead( T const& src )
  698. {
  699. return InsertAfter( InvalidIndex(), src );
  700. }
  701. template <class T, class S, bool ML, class I, class M>
  702. inline I CUtlLinkedList<T,S,ML,I,M>::AddToTail( T const& src )
  703. {
  704. return InsertBefore( InvalidIndex(), src );
  705. }
  706. //-----------------------------------------------------------------------------
  707. // Removal methods
  708. //-----------------------------------------------------------------------------
  709. template<class T, class S, bool ML, class I, class M>
  710. I CUtlLinkedList<T,S,ML,I,M>::Find( const T &src ) const
  711. {
  712. for ( I i=Head(); i != InvalidIndex(); i = Next( 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