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.

625 lines
15 KiB

  1. //========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: N-way tree container class
  4. //
  5. // $Revision: $
  6. // $NoKeywords: $
  7. //=============================================================================//
  8. #ifndef UTLNTREE_H
  9. #define UTLNTREE_H
  10. #ifdef _WIN32
  11. #pragma once
  12. #endif
  13. #include "basetypes.h"
  14. #include "utlmemory.h"
  15. #include "tier0/dbg.h"
  16. #define INVALID_NTREE_IDX ((I)~0)
  17. //-----------------------------------------------------------------------------
  18. // class CUtlNTree:
  19. // description:
  20. // A lovely index-based linked list! T is the class type, I is the index
  21. // type, which usually should be an unsigned short or smaller.
  22. //-----------------------------------------------------------------------------
  23. template <class T, class I = unsigned short>
  24. class CUtlNTree
  25. {
  26. public:
  27. typedef T ElemType_t;
  28. typedef I IndexType_t;
  29. // constructor, destructor
  30. CUtlNTree( int growSize = 0, int initSize = 0 );
  31. CUtlNTree( void *pMemory, int memsize );
  32. ~CUtlNTree( );
  33. // gets particular elements
  34. T& Element( I i );
  35. const T& Element( I i ) const;
  36. T& operator[]( I i );
  37. const T& operator[]( I i ) const;
  38. // Make sure we have a particular amount of memory
  39. void EnsureCapacity( int num );
  40. // Clears the tree, doesn't deallocate memory
  41. void RemoveAll();
  42. // Memory deallocation
  43. void Purge();
  44. // Allocation/deallocation methods
  45. I Alloc( );
  46. void Free( I elem );
  47. void FreeSubTree( I elem );
  48. // list modification
  49. void SetRoot( I root );
  50. void LinkChildBefore( I parent, I before, I elem );
  51. void LinkChildAfter( I parent, I after, I elem );
  52. void Unlink( I elem );
  53. // Alloc + link combined
  54. I InsertChildBefore( I parent, I before );
  55. I InsertChildAfter( I parent, I after );
  56. I InsertChildBefore( I parent, I before, const T &elem );
  57. I InsertChildAfter( I parent, I after, const T &elem );
  58. // Unlink + free combined
  59. void Remove( I elem );
  60. void RemoveSubTree( I elem );
  61. // invalid index
  62. inline static I InvalidIndex() { return INVALID_NTREE_IDX; }
  63. inline static size_t ElementSize() { return sizeof(Node_t); }
  64. // list statistics
  65. int Count() const;
  66. I MaxElementIndex() const;
  67. // Traversing the list
  68. I Root() const;
  69. I FirstChild( I i ) const;
  70. I PrevSibling( I i ) const;
  71. I NextSibling( I i ) const;
  72. I Parent( I i ) const;
  73. // Are nodes in the list or valid?
  74. bool IsValidIndex( I i ) const;
  75. bool IsInTree( I i ) const;
  76. protected:
  77. // What the linked list element looks like
  78. struct Node_t
  79. {
  80. T m_Element;
  81. I m_Parent;
  82. I m_FirstChild;
  83. I m_PrevSibling;
  84. I m_NextSibling;
  85. private:
  86. // No copy constructor for these...
  87. Node_t( const Node_t& );
  88. };
  89. // constructs the class
  90. void ConstructList();
  91. // Allocates the element, doesn't call the constructor
  92. I AllocInternal();
  93. // Gets at the node element....
  94. Node_t& InternalNode( I i ) { return m_Memory[i]; }
  95. const Node_t& InternalNode( I i ) const { return m_Memory[i]; }
  96. void ResetDbgInfo()
  97. {
  98. m_pElements = m_Memory.Base();
  99. }
  100. // copy constructors not allowed
  101. CUtlNTree( CUtlNTree<T, I> const& tree ) { Assert(0); }
  102. CUtlMemory<Node_t> m_Memory;
  103. I m_Root;
  104. I m_FirstFree;
  105. I m_ElementCount; // The number actually in the tree
  106. I m_MaxElementIndex; // The max index we've ever assigned
  107. // For debugging purposes;
  108. // it's in release builds so this can be used in libraries correctly
  109. Node_t *m_pElements;
  110. };
  111. //-----------------------------------------------------------------------------
  112. // constructor, destructor
  113. //-----------------------------------------------------------------------------
  114. template <class T, class I>
  115. CUtlNTree<T,I>::CUtlNTree( int growSize, int initSize ) :
  116. m_Memory(growSize, initSize)
  117. {
  118. ConstructList();
  119. ResetDbgInfo();
  120. }
  121. template <class T, class I>
  122. CUtlNTree<T,I>::CUtlNTree( void* pMemory, int memsize ) :
  123. m_Memory(pMemory, memsize/sizeof(T))
  124. {
  125. ConstructList();
  126. ResetDbgInfo();
  127. }
  128. template <class T, class I>
  129. CUtlNTree<T,I>::~CUtlNTree( )
  130. {
  131. RemoveAll();
  132. }
  133. template <class T, class I>
  134. void CUtlNTree<T,I>::ConstructList()
  135. {
  136. m_Root = InvalidIndex();
  137. m_FirstFree = InvalidIndex();
  138. m_ElementCount = m_MaxElementIndex = 0;
  139. }
  140. //-----------------------------------------------------------------------------
  141. // gets particular elements
  142. //-----------------------------------------------------------------------------
  143. template <class T, class I>
  144. inline T& CUtlNTree<T,I>::Element( I i )
  145. {
  146. return m_Memory[i].m_Element;
  147. }
  148. template <class T, class I>
  149. inline const T& CUtlNTree<T,I>::Element( I i ) const
  150. {
  151. return m_Memory[i].m_Element;
  152. }
  153. template <class T, class I>
  154. inline T& CUtlNTree<T,I>::operator[]( I i )
  155. {
  156. return m_Memory[i].m_Element;
  157. }
  158. template <class T, class I>
  159. inline const T& CUtlNTree<T,I>::operator[]( I i ) const
  160. {
  161. return m_Memory[i].m_Element;
  162. }
  163. //-----------------------------------------------------------------------------
  164. // list statistics
  165. //-----------------------------------------------------------------------------
  166. template <class T, class I>
  167. inline int CUtlNTree<T,I>::Count() const
  168. {
  169. return m_ElementCount;
  170. }
  171. template <class T, class I>
  172. inline I CUtlNTree<T,I>::MaxElementIndex() const
  173. {
  174. return m_MaxElementIndex;
  175. }
  176. //-----------------------------------------------------------------------------
  177. // Traversing the list
  178. //-----------------------------------------------------------------------------
  179. template <class T, class I>
  180. inline I CUtlNTree<T,I>::Root() const
  181. {
  182. return m_Root;
  183. }
  184. template <class T, class I>
  185. inline I CUtlNTree<T,I>::FirstChild( I i ) const
  186. {
  187. Assert( IsInTree(i) );
  188. return InternalNode(i).m_FirstChild;
  189. }
  190. template <class T, class I>
  191. inline I CUtlNTree<T,I>::PrevSibling( I i ) const
  192. {
  193. Assert( IsInTree(i) );
  194. return InternalNode(i).m_PrevSibling;
  195. }
  196. template <class T, class I>
  197. inline I CUtlNTree<T,I>::NextSibling( I i ) const
  198. {
  199. Assert( IsInTree(i) );
  200. return InternalNode(i).m_NextSibling;
  201. }
  202. template <class T, class I>
  203. inline I CUtlNTree<T,I>::Parent( I i ) const
  204. {
  205. Assert( IsInTree(i) );
  206. return InternalNode(i).m_Parent;
  207. }
  208. //-----------------------------------------------------------------------------
  209. // Are nodes in the list or valid?
  210. //-----------------------------------------------------------------------------
  211. template <class T, class I>
  212. inline bool CUtlNTree<T,I>::IsValidIndex( I i ) const
  213. {
  214. return (i < m_MaxElementIndex) && (i >= 0);
  215. }
  216. template <class T, class I>
  217. inline bool CUtlNTree<T,I>::IsInTree( I i ) const
  218. {
  219. bool bIndexPositive = ( 0 > (I)(-1) ) ? (i >= 0) : true;
  220. return (i < m_MaxElementIndex) && bIndexPositive && (InternalNode(i).m_PrevSibling != i);
  221. }
  222. //-----------------------------------------------------------------------------
  223. // Makes sure we have enough memory allocated to store a requested # of elements
  224. //-----------------------------------------------------------------------------
  225. template< class T, class I >
  226. void CUtlNTree<T, I>::EnsureCapacity( int num )
  227. {
  228. MEM_ALLOC_CREDIT_CLASS();
  229. m_Memory.EnsureCapacity(num);
  230. ResetDbgInfo();
  231. }
  232. //-----------------------------------------------------------------------------
  233. // Deallocate memory
  234. //-----------------------------------------------------------------------------
  235. template <class T, class I>
  236. void CUtlNTree<T,I>::Purge()
  237. {
  238. RemoveAll();
  239. m_Memory.Purge( );
  240. m_FirstFree = InvalidIndex();
  241. m_MaxElementIndex = 0;
  242. ResetDbgInfo();
  243. }
  244. //-----------------------------------------------------------------------------
  245. // Node allocation/deallocation
  246. //-----------------------------------------------------------------------------
  247. template <class T, class I>
  248. I CUtlNTree<T,I>::AllocInternal( )
  249. {
  250. I elem;
  251. if ( m_FirstFree == INVALID_NTREE_IDX )
  252. {
  253. // Nothing in the free list; add.
  254. // Since nothing is in the free list, m_MaxElementIndex == total # of elements
  255. // the list knows about.
  256. if ((int)m_MaxElementIndex == m_Memory.NumAllocated())
  257. {
  258. MEM_ALLOC_CREDIT_CLASS();
  259. m_Memory.Grow();
  260. }
  261. Assert( m_MaxElementIndex != INVALID_NTREE_IDX );
  262. elem = (I)m_MaxElementIndex;
  263. ++m_MaxElementIndex;
  264. if ( elem == InvalidIndex() )
  265. {
  266. Error("CUtlNTree overflow!\n");
  267. }
  268. }
  269. else
  270. {
  271. elem = m_FirstFree;
  272. m_FirstFree = InternalNode( m_FirstFree ).m_NextSibling;
  273. }
  274. Node_t &node = InternalNode( elem );
  275. node.m_NextSibling = node.m_PrevSibling = node.m_Parent = node.m_FirstChild = INVALID_NTREE_IDX;
  276. ResetDbgInfo();
  277. // one more element baby
  278. ++m_ElementCount;
  279. return elem;
  280. }
  281. template <class T, class I>
  282. I CUtlNTree<T,I>::Alloc( )
  283. {
  284. I elem = AllocInternal();
  285. Construct( &Element(elem) );
  286. return elem;
  287. }
  288. template <class T, class I>
  289. void CUtlNTree<T,I>::Free( I elem )
  290. {
  291. Assert( IsInTree( elem ) );
  292. Unlink( elem );
  293. // If there's children, this will result in leaks. Use FreeSubTree instead.
  294. Assert( FirstChild( elem ) == INVALID_NTREE_IDX );
  295. Node_t &node = InternalNode( elem );
  296. Destruct( &node.m_Element );
  297. node.m_NextSibling = m_FirstFree;
  298. node.m_PrevSibling = elem; // Marks it as being in the free list
  299. node.m_Parent = node.m_FirstChild = INVALID_NTREE_IDX;
  300. m_FirstFree = elem;
  301. // one less element baby
  302. --m_ElementCount;
  303. }
  304. template <class T, class I>
  305. void CUtlNTree<T,I>::FreeSubTree( I elem )
  306. {
  307. Assert( IsValidIndex( elem ) );
  308. I child = FirstChild( elem );
  309. while ( child != INVALID_NTREE_IDX )
  310. {
  311. I next = NextSibling( child );
  312. FreeSubTree( child );
  313. child = next;
  314. }
  315. Free( elem );
  316. }
  317. //-----------------------------------------------------------------------------
  318. // Clears the tree
  319. //-----------------------------------------------------------------------------
  320. template <class T, class I>
  321. void CUtlNTree<T,I>::RemoveAll()
  322. {
  323. if ( m_MaxElementIndex == 0 )
  324. return;
  325. // Put everything into the free list (even unlinked things )
  326. I prev = InvalidIndex();
  327. for (int i = (int)m_MaxElementIndex; --i >= 0; prev = (I)i )
  328. {
  329. Node_t &node = InternalNode( i );
  330. if ( IsInTree( i ) )
  331. {
  332. Destruct( &node.m_Element );
  333. }
  334. node.m_NextSibling = prev;
  335. node.m_PrevSibling = (I)i; // Marks it as being in the free list
  336. node.m_Parent = node.m_FirstChild = INVALID_NTREE_IDX;
  337. }
  338. // First free points to the first element
  339. m_FirstFree = 0;
  340. // Clear everything else out
  341. m_Root = INVALID_NTREE_IDX;
  342. m_ElementCount = 0;
  343. }
  344. //-----------------------------------------------------------------------------
  345. // list modification
  346. //-----------------------------------------------------------------------------
  347. template <class T, class I>
  348. void CUtlNTree<T,I>::SetRoot( I root )
  349. {
  350. // Resetting the root while it's got stuff in it is bad...
  351. Assert( m_Root == InvalidIndex() );
  352. m_Root = root;
  353. }
  354. //-----------------------------------------------------------------------------
  355. // Links a node after a particular node
  356. //-----------------------------------------------------------------------------
  357. template <class T, class I>
  358. void CUtlNTree<T,I>::LinkChildAfter( I parent, I after, I elem )
  359. {
  360. Assert( IsInTree(elem) );
  361. // Unlink it if it's in the list at the moment
  362. Unlink(elem);
  363. Node_t& newElem = InternalNode(elem);
  364. newElem.m_Parent = parent;
  365. newElem.m_PrevSibling = after;
  366. if ( after != INVALID_NTREE_IDX )
  367. {
  368. Node_t& prevSiblingNode = InternalNode( after );
  369. newElem.m_NextSibling = prevSiblingNode.m_NextSibling;
  370. prevSiblingNode.m_NextSibling = elem;
  371. }
  372. else
  373. {
  374. if ( parent != INVALID_NTREE_IDX )
  375. {
  376. Node_t& parentNode = InternalNode( parent );
  377. newElem.m_NextSibling = parentNode.m_FirstChild;
  378. parentNode.m_FirstChild = elem;
  379. }
  380. else
  381. {
  382. newElem.m_NextSibling = m_Root;
  383. if ( m_Root != INVALID_NTREE_IDX )
  384. {
  385. Node_t& rootNode = InternalNode( m_Root );
  386. rootNode.m_PrevSibling = elem;
  387. }
  388. m_Root = elem;
  389. }
  390. }
  391. if ( newElem.m_NextSibling != INVALID_NTREE_IDX )
  392. {
  393. Node_t& nextSiblingNode = InternalNode( newElem.m_NextSibling );
  394. nextSiblingNode.m_PrevSibling = elem;
  395. }
  396. }
  397. //-----------------------------------------------------------------------------
  398. // Links a node before a particular node
  399. //-----------------------------------------------------------------------------
  400. template <class T, class I>
  401. void CUtlNTree<T,I>::LinkChildBefore( I parent, I before, I elem )
  402. {
  403. Assert( IsValidIndex(elem) );
  404. if ( before != INVALID_NTREE_IDX )
  405. {
  406. LinkChildAfter( parent, InternalNode( before ).m_PrevSibling, elem );
  407. return;
  408. }
  409. // NOTE: I made the choice to do an O(n) operation here
  410. // instead of store more data per node (LastChild).
  411. // This might not be the right choice. Revisit if we get perf problems.
  412. I after;
  413. if ( parent != INVALID_NTREE_IDX )
  414. {
  415. after = InternalNode( parent ).m_FirstChild;
  416. }
  417. else
  418. {
  419. after = m_Root;
  420. }
  421. if ( after == INVALID_NTREE_IDX )
  422. {
  423. LinkChildAfter( parent, after, elem );
  424. return;
  425. }
  426. I next = InternalNode( after ).m_NextSibling;
  427. while ( next != InvalidIndex() )
  428. {
  429. after = next;
  430. next = InternalNode( next ).m_NextSibling;
  431. }
  432. LinkChildAfter( parent, after, elem );
  433. }
  434. //-----------------------------------------------------------------------------
  435. // Unlinks a node from the tree
  436. //-----------------------------------------------------------------------------
  437. template <class T, class I>
  438. void CUtlNTree<T,I>::Unlink( I elem )
  439. {
  440. Assert( IsInTree(elem) );
  441. Node_t *pOldNode = &InternalNode( elem );
  442. // If we're the first guy, reset the head
  443. // otherwise, make our previous node's next pointer = our next
  444. if ( pOldNode->m_PrevSibling != INVALID_NTREE_IDX )
  445. {
  446. InternalNode( pOldNode->m_PrevSibling ).m_NextSibling = pOldNode->m_NextSibling;
  447. }
  448. else
  449. {
  450. if ( pOldNode->m_Parent != INVALID_NTREE_IDX )
  451. {
  452. InternalNode( pOldNode->m_Parent ).m_FirstChild = pOldNode->m_NextSibling;
  453. }
  454. else if ( m_Root == elem )
  455. {
  456. m_Root = pOldNode->m_NextSibling;
  457. }
  458. }
  459. // If we're the last guy, reset the tail
  460. // otherwise, make our next node's prev pointer = our prev
  461. if ( pOldNode->m_NextSibling != INVALID_NTREE_IDX )
  462. {
  463. InternalNode( pOldNode->m_NextSibling ).m_PrevSibling = pOldNode->m_PrevSibling;
  464. }
  465. // Unlink everything except children
  466. pOldNode->m_Parent = pOldNode->m_PrevSibling = pOldNode->m_NextSibling = INVALID_NTREE_IDX;
  467. }
  468. //-----------------------------------------------------------------------------
  469. // Alloc + link combined
  470. //-----------------------------------------------------------------------------
  471. template <class T, class I>
  472. I CUtlNTree<T,I>::InsertChildBefore( I parent, I before )
  473. {
  474. I elem = AllocInternal();
  475. Construct( &Element( elem ) );
  476. LinkChildBefore( parent, before, elem );
  477. return elem;
  478. }
  479. template <class T, class I>
  480. I CUtlNTree<T,I>::InsertChildAfter( I parent, I after )
  481. {
  482. I elem = AllocInternal();
  483. Construct( &Element( elem ) );
  484. LinkChildAfter( parent, after, elem );
  485. return elem;
  486. }
  487. template <class T, class I>
  488. I CUtlNTree<T,I>::InsertChildBefore( I parent, I before, const T &data )
  489. {
  490. I elem = AllocInternal();
  491. CopyConstruct( &Element( elem ), data );
  492. LinkChildBefore( parent, before, elem );
  493. return elem;
  494. }
  495. template <class T, class I>
  496. I CUtlNTree<T,I>::InsertChildAfter( I parent, I after, const T &data )
  497. {
  498. I elem = AllocInternal();
  499. CopyConstruct( &Element( elem ), data );
  500. LinkChildAfter( parent, after, elem );
  501. return elem;
  502. }
  503. //-----------------------------------------------------------------------------
  504. // Unlink + free combined
  505. //-----------------------------------------------------------------------------
  506. template <class T, class I>
  507. void CUtlNTree<T,I>::Remove( I elem )
  508. {
  509. Unlink( elem );
  510. Free( elem );
  511. }
  512. template <class T, class I>
  513. void CUtlNTree<T,I>::RemoveSubTree( I elem )
  514. {
  515. UnlinkSubTree( elem );
  516. Free( elem );
  517. }
  518. #endif // UTLNTREE_H