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.

1064 lines
23 KiB

  1. //===== Copyright (c) 1996-2006, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose: Intrusive linked list templates, both for singly and doubly linked lists
  4. //
  5. // $Revision: $
  6. // $NoKeywords: $
  7. //===========================================================================//
  8. #ifndef UTILINTRUSIVELIST_H
  9. #define UTILINTRUSIVELIST_H
  10. #ifdef _WIN32
  11. #pragma once
  12. #endif
  13. #include "tier0/basetypes.h"
  14. #include "utlmemory.h"
  15. #include "tier0/dbg.h"
  16. #include "tier1/generichash.h"
  17. #include "tier0/threadtools.h"
  18. //
  19. // These templates are used for intrusive linked list classes. Intrusive linked list templates
  20. // force the structs and classes contained within them to have their own m_pNext, (optionally),
  21. // m_pPrev, and other fields contained within. All memory management is up to the caller and their
  22. // classes. No data will ever be copied. Nodes can only exist on one list at a time, because of
  23. // only having on m_Next field, and manipulating the list while walking it requires that care on
  24. // the part of the caller. All accessing and searching functions work by passing and returning
  25. // pointers.
  26. //
  27. //
  28. //
  29. // naming and field conventions:
  30. // functions referring to a DList are for doubly linked lists. nodes must have m_pHead and
  31. // m_pPrev pointer fields.
  32. // Functions using Priority require an m_Priority field, which must be comparable.
  33. //
  34. // Some functions are mean for use with lists which maintain both a head and tail pointer
  35. // in order to support fast adding to the end.
  36. /// validates that the doubly linked list has the proper structure, pointer-wise
  37. //#define SUPERSLOW_DEBUG_VERSION
  38. namespace IntrusiveList
  39. {
  40. #ifdef SUPERSLOW_DEBUG_VERSION
  41. template<class T> inline void ValidateDList(T *head)
  42. {
  43. if (head)
  44. {
  45. Assert(head->m_pPrev==0);
  46. }
  47. while(head)
  48. {
  49. if (head->m_pNext)
  50. {
  51. Assert(head->m_pNext->m_pPrev==head);
  52. }
  53. if (head->m_pPrev)
  54. {
  55. Assert(head->m_pPrev->m_pNext==head);
  56. }
  57. head=head->m_pNext;
  58. }
  59. }
  60. #else
  61. template<class T> inline void ValidateDList(T * /*head*/)
  62. {
  63. }
  64. #endif
  65. // move a node in a doubly linked list backwards one step.
  66. template <class T> inline void MoveDNodeBackwards( T *which, T * &head)
  67. {
  68. if (which->m_pPrev)
  69. {
  70. T *p=which->m_pPrev;
  71. T *pp=p->m_pPrev;
  72. T *n=which->m_pNext;
  73. Assert(p->m_pNext == which);
  74. if (n)
  75. {
  76. Assert(n->m_pPrev==which);
  77. n->m_pPrev=p;
  78. }
  79. if (pp)
  80. {
  81. Assert(pp->m_pNext==p);
  82. pp->m_pNext=which;
  83. }
  84. else
  85. {
  86. head=which; // this node is the new root!
  87. }
  88. which->m_pNext=p;
  89. which->m_pPrev=pp;
  90. p->m_pNext=n;
  91. p->m_pPrev=which;
  92. }
  93. ValidateDList(head);
  94. }
  95. // removes node 'which' from doubly linked list with 'head'
  96. template<class T> inline void RemoveFromDList(T * &head, T *which)
  97. {
  98. if (which->m_pPrev)
  99. {
  100. Assert(which->m_pPrev->m_pNext==which);
  101. which->m_pPrev->m_pNext=which->m_pNext;
  102. if (which->m_pNext)
  103. {
  104. Assert(which->m_pNext->m_pPrev==which);
  105. which->m_pNext->m_pPrev=which->m_pPrev;
  106. }
  107. }
  108. else
  109. {
  110. if (head==which)
  111. {
  112. head=which->m_pNext;
  113. if (head)
  114. {
  115. Assert(head->m_pPrev==which);
  116. head->m_pPrev=0;
  117. }
  118. }
  119. }
  120. which->m_pNext=which->m_pPrev=0;
  121. ValidateDList(head);
  122. }
  123. //checks to see if node is in doubly linked list
  124. template<class T> bool OnDList(T const *head, T const *which)
  125. {
  126. return (head==which) || (which->m_pNext !=0) || (which->m_pPrev !=0);
  127. }
  128. // add a node to the end of a singly linked list
  129. template<class T> void AddToDTail(T * & head, T * node)
  130. {
  131. node->m_pNext=0;
  132. if (! head)
  133. {
  134. head=node;
  135. node->m_pPrev = NULL;
  136. node->m_pNext = NULL;
  137. }
  138. else
  139. {
  140. T *ptr = head;
  141. while(ptr->m_pNext)
  142. {
  143. ptr=ptr->m_pNext;
  144. }
  145. ptr->m_pNext = node;
  146. node->m_pPrev = ptr; //
  147. node->m_pNext = NULL;
  148. }
  149. }
  150. // add a node to end of doubly linked list.
  151. template<class T> inline void AddToDHead(T * &head, T *which)
  152. {
  153. which->m_pNext=head;
  154. if (head)
  155. {
  156. head->m_pPrev=which;
  157. }
  158. which->m_pPrev=0;
  159. head=which;
  160. ValidateDList(head);
  161. }
  162. // add a node to front of doubly linked list which maintains a tail ptr
  163. template<class T> inline void AddToDHeadWithTailPtr(T * &head, T *which, T * &tailptr)
  164. {
  165. which->m_pNext=head;
  166. if (head)
  167. {
  168. head->m_pPrev=which;
  169. }
  170. else
  171. {
  172. tailptr=which;
  173. }
  174. which->m_pPrev=0;
  175. head=which;
  176. ValidateDList(head);
  177. }
  178. // add a node to end of doubly linked list which maintains a tail ptr
  179. template<class T> inline void AddToDTailWithTailPtr(T * &head, T *which, T * & tailptr)
  180. {
  181. if (! tailptr)
  182. {
  183. Assert(! head);
  184. which->m_pPrev=which->m_pNext=0;
  185. tailptr=head=which;
  186. }
  187. else
  188. {
  189. which->m_pNext=0;
  190. which->m_pPrev=tailptr;
  191. tailptr->m_pNext=which;
  192. tailptr=which;
  193. }
  194. ValidateDList( head );
  195. }
  196. // Remove a node from a dlist , maintaining the tail ptr. node is not 'delete' d
  197. template<class T> inline void RemoveFromDListWithTailPtr(T * &head, T *which, T * & tailptr)
  198. {
  199. if (which==tailptr)
  200. {
  201. tailptr=which->m_pPrev;
  202. }
  203. if (which->m_pPrev)
  204. {
  205. Assert(which->m_pPrev->m_pNext==which);
  206. which->m_pPrev->m_pNext=which->m_pNext;
  207. if (which->m_pNext)
  208. {
  209. Assert(which->m_pNext->m_pPrev==which);
  210. which->m_pNext->m_pPrev=which->m_pPrev;
  211. }
  212. }
  213. else
  214. {
  215. if (head==which)
  216. {
  217. head=which->m_pNext;
  218. if (head)
  219. {
  220. Assert(head->m_pPrev==which);
  221. head->m_pPrev=0;
  222. }
  223. }
  224. }
  225. which->m_pNext=which->m_pPrev=0;
  226. ValidateDList(head);
  227. }
  228. // this function removes a node, and delete's the node
  229. template<class T> inline void DeleteFromDListWithTailPtr(T * &head, T *which, T * & tailptr)
  230. {
  231. T *tmp=which;
  232. if (which==tailptr)
  233. {
  234. tailptr=which->m_pPrev;
  235. }
  236. if (which->m_pPrev)
  237. {
  238. Assert(which->m_pPrev->m_pNext==which);
  239. which->m_pPrev->m_pNext=which->m_pNext;
  240. if (which->m_pNext)
  241. {
  242. Assert(which->m_pNext->m_pPrev==which);
  243. which->m_pNext->m_pPrev=which->m_pPrev;
  244. }
  245. }
  246. else
  247. {
  248. if (head==which)
  249. {
  250. head=which->m_pNext;
  251. if (head)
  252. {
  253. Assert(head->m_pPrev==which);
  254. head->m_pPrev=0;
  255. }
  256. }
  257. }
  258. which->m_pNext=which->m_pPrev=0;
  259. delete tmp;
  260. ValidateDList(head);
  261. }
  262. // Add a node to a d-list, keeping the highest priority nodes first. This is a simple
  263. // linear search to insert, NOT a O(logn) heap.
  264. template<class T> inline void AddToDPriority(T * &head, T *which)
  265. {
  266. T* prevnode=0;
  267. for(T *curnode=head;curnode;curnode=curnode->m_pNext)
  268. {
  269. if (which->m_Priority>=curnode->m_Priority)
  270. break;
  271. prevnode=curnode;
  272. }
  273. // now, we have either run out of list, or we have found an
  274. // element to add this one before
  275. if (! prevnode)
  276. {
  277. AddToDHead(head,which);
  278. }
  279. else
  280. {
  281. which->m_pNext=prevnode->m_pNext;
  282. prevnode->m_pNext=which;
  283. which->m_pPrev=prevnode;
  284. if (which->m_pNext)
  285. which->m_pNext->m_pPrev=which;
  286. }
  287. }
  288. // same as AddToDPriority, except with reverse order
  289. template<class T> inline void AddToDPriorityLowestFirst(T * &head, T *which)
  290. {
  291. T* prevnode=0;
  292. for(T *curnode=head;curnode;curnode=curnode->m_pNext)
  293. {
  294. if (which->m_Priority<=curnode->m_Priority)
  295. break;
  296. prevnode=curnode;
  297. }
  298. // now, we have either run out of list, or we have found an
  299. // element to add this one before
  300. if (! prevnode)
  301. {
  302. AddToDHead(head,which);
  303. }
  304. else
  305. {
  306. which->m_pNext=prevnode->m_pNext;
  307. prevnode->m_pNext=which;
  308. which->m_pPrev=prevnode;
  309. if (which->m_pNext)
  310. which->m_pNext->m_pPrev=which;
  311. }
  312. }
  313. // return a pointer to the last node in a singly-linked (or doubly) list
  314. template<class T> T * LastNode(T * head)
  315. {
  316. if (head)
  317. {
  318. while(head->m_pNext)
  319. {
  320. head=head->m_pNext;
  321. }
  322. }
  323. return head;
  324. }
  325. // Remove from a singly linked list. no delete called.
  326. template<class T,class V> void RemoveFromList(T * & head, V *which)
  327. {
  328. if (head==which)
  329. {
  330. head=which->m_pNext;
  331. }
  332. else
  333. {
  334. for(T * i=head; i; i=i->m_pNext)
  335. {
  336. if (i->m_pNext==which)
  337. {
  338. i->m_pNext=which->m_pNext;
  339. return;
  340. }
  341. }
  342. }
  343. }
  344. // same as RemoveFromList, but 'delete' is called.
  345. template<class T,class V> void DeleteFromList(T * & head, V *which)
  346. {
  347. T *tmp;
  348. if (head==which)
  349. {
  350. tmp=which->m_pNext;
  351. delete(head);
  352. head=tmp;
  353. }
  354. else
  355. {
  356. for(T * i=head; i; i=i->m_pNext)
  357. {
  358. if (i->m_pNext==which)
  359. {
  360. tmp=which->m_pNext;
  361. delete(which);
  362. i->m_pNext=tmp;
  363. return;
  364. }
  365. }
  366. }
  367. }
  368. // find the position in a list of a node. -1 if not found. Linear search.
  369. // nodes must have comparison functions
  370. template<class T,class V> int PositionInList(T *head, V *node)
  371. {
  372. int pos=0;
  373. while(head)
  374. {
  375. if (head==node) return pos;
  376. head=head->m_pNext;
  377. pos++;
  378. }
  379. return -1;
  380. }
  381. // find the Nth node in a list. null if index too high.
  382. template<class T> T *NthNode(T * head, int idx)
  383. {
  384. while(idx && head)
  385. {
  386. idx--;
  387. head=head->m_pNext;
  388. }
  389. return head;
  390. }
  391. //Add a node to the head of a singly-linked
  392. // Note that the head var passed to this will be modified.
  393. template<class T,class V> FORCEINLINE void AddToHead(T * & head, V * node)
  394. {
  395. node->m_pNext=head;
  396. head=node;
  397. }
  398. //Add a node to the head of a singly-linked list in a thread safe fashion. NOTE RESTRICTIONS
  399. // EXTREMELY CAREFULLY: the ONLY thing that is thread safe about this is multiple threads
  400. // adding to a list at the same time. ANY other simultaneous operations (walking the list,
  401. // modifying it in any way, ANYTHING else) is NOT thread safe. The only way to use this
  402. // function in code and have that code WORK is to follow the restriction that the only
  403. // simultaneous operation is an AddHead. CTSList is a better choice for ALMOST ANYTHING that
  404. // wants this functionality. The m_pNext pointer in the node needs to be properly aligned for
  405. // interlocked compare exchange. Do NOT use this function unless you understand every
  406. // implication of the above paragraph and want something lighter than ctslist.
  407. template<class T,class V> FORCEINLINE void AddToHeadTS( T * &pHead, V * pNode)
  408. {
  409. for(;; )
  410. {
  411. T *pCurHead = ReadVolatileMemory<T *>( &pHead );
  412. pNode->m_pNext = pCurHead;
  413. ThreadMemoryBarrier();
  414. if ( ThreadInterlockedAssignPointerIf( ( void * volatile * ) ( &pHead ) , pNode, pCurHead ) )
  415. {
  416. break;
  417. }
  418. }
  419. }
  420. // a version of AddToHeadTS which uses an alternate field to m_pnext for the linkage. Same
  421. // restrictions as above.
  422. template<class T,class V> FORCEINLINE void AddToHeadByFieldTS( T * &pHead, V * pNode, T * V::*field )
  423. {
  424. for(;; )
  425. {
  426. T *pCurHead = ReadVolatileMemory<T *>( &pHead );
  427. ( *pNode ).*field = pCurHead;
  428. ThreadMemoryBarrier();
  429. if ( ThreadInterlockedAssignPointerIf( ( void * volatile * ) ( &pHead ) , pNode, pCurHead ) )
  430. {
  431. break;
  432. }
  433. }
  434. }
  435. // remove the head node of a list in a thread safe fashion. It is NOT SAFE to do ANYTHING else
  436. // with the list during this operation. The only thread safe usage pattern for this is multiple
  437. // threads grabbing the head node at the same time.
  438. template<class T> FORCEINLINE T *RemoveHeadTS( T * &pHead )
  439. {
  440. for(;; )
  441. {
  442. T *pCurHead = ReadVolatileMemory<T *>( &pHead );
  443. if ( ! pCurHead )
  444. {
  445. return NULL;
  446. }
  447. ThreadMemoryBarrier();
  448. if ( ThreadInterlockedAssignPointerIf( ( void * volatile * ) ( &pHead ) , pCurHead->m_pNext, pCurHead ) )
  449. {
  450. return pCurHead;
  451. }
  452. }
  453. }
  454. //Add a node to the tail of a singly-linked. Not fast
  455. // Note that the head var passed to this will be modified.
  456. template<class T,class V> FORCEINLINE void AddToTail(T * & head, V * node)
  457. {
  458. node->m_pNext = NULL;
  459. if ( ! head )
  460. head = node;
  461. else
  462. {
  463. T *pLastNode = head;
  464. while( pLastNode->m_pNext )
  465. pLastNode = pLastNode->m_pNext;
  466. pLastNode->m_pNext = node;
  467. }
  468. }
  469. //Add a node to the head of a singly-linked list, maintaining a tail pointer
  470. template<class T,class V> FORCEINLINE void AddToHead(T * & head, T * &tail,V * node)
  471. {
  472. if (! head)
  473. {
  474. tail=node;
  475. }
  476. node->m_pNext=head;
  477. head=node;
  478. }
  479. // return the node in head before in a singly linked list. returns null if head is empty, n is
  480. // null, or if n is the first node. not fast.
  481. template<class T> FORCEINLINE T * PrevNode(T *head, T *node)
  482. {
  483. T *i;
  484. for( i = head; i ; i = i->m_pNext)
  485. {
  486. if ( i->m_pNext == node )
  487. break;
  488. }
  489. return i;
  490. }
  491. // add a node to the end of a singly linked list. Not fast.
  492. template<class T,class V> void AddToEnd(T * & head, V * node)
  493. {
  494. node->m_pNext=0;
  495. if (! head)
  496. {
  497. head=node;
  498. }
  499. else
  500. {
  501. T *ptr=head;
  502. while(ptr->m_pNext)
  503. {
  504. ptr=ptr->m_pNext;
  505. }
  506. ptr->m_pNext=node;
  507. }
  508. }
  509. // add a node to the end of a singly linked list, maintaining a tail pointer.
  510. // the head and tail pointer can be modified by this routine.
  511. template<class T,class V> void AddToEndWithTail(T * & head, V * node, T * & tail )
  512. {
  513. Assert((head && tail) || ((!head) && (!tail)));
  514. node->m_pNext=0;
  515. if (! head)
  516. {
  517. head=tail=node;
  518. }
  519. else
  520. {
  521. tail->m_pNext=node;
  522. tail=node;
  523. }
  524. }
  525. // Add a node to a singly linked list, sorting by the m_Name field
  526. template<class T> void AddSortedByName(T * & head, T * node)
  527. {
  528. if ( (! head) || // empty list?
  529. (stricmp(node->m_Name,head->m_Name)==-1)) // or we should be first?
  530. {
  531. node->m_pNext=head; // make us head
  532. head=node;
  533. }
  534. else
  535. {
  536. T * t;
  537. for( t = head ; t->m_pNext ; t = t->m_pNext ) // find the node we should be before
  538. {
  539. if ( stricmp( t->m_pNext->m_Name, node->m_Name) >= 0 )
  540. {
  541. break;
  542. }
  543. }
  544. node->m_pNext = t->m_pNext;
  545. t->m_pNext = node;
  546. }
  547. }
  548. // count # of elements in list
  549. template<class T> int ListLength(T *head)
  550. {
  551. int len=0;
  552. while(head)
  553. {
  554. len++;
  555. head = static_cast< T* >( head->m_pNext );
  556. }
  557. return len;
  558. }
  559. // this will kill a list if the list is of objects which automatically
  560. // remove themselves from the list when delete is called
  561. template<class T> void KillList(T * & head)
  562. {
  563. while(head)
  564. {
  565. delete head;
  566. }
  567. }
  568. // this will kill all elements in a list if
  569. // the elements are of a type which does NOT remove itself from
  570. // the list when the destructor is called.
  571. template<class T> void DeleteList(T * & head)
  572. {
  573. while (head)
  574. {
  575. T* tmp=head->m_pNext;
  576. delete head;
  577. head=tmp;
  578. }
  579. }
  580. // find a named node in any list which has both a Next field and a Name field.
  581. template <class T> FORCEINLINE T * FindNamedNode(T * head, char const *name)
  582. {
  583. for(;head && stricmp(head->m_Name,name); head=head->m_pNext)
  584. {
  585. }
  586. return head;
  587. }
  588. template <class T> FORCEINLINE T * FindNamedNodeCaseSensitive(T * head, char const *name)
  589. {
  590. for(;head && strcmp(head->m_Name,name); head=head->m_pNext)
  591. {
  592. }
  593. return head;
  594. }
  595. // find data in a singly linked list, using equality match on any field
  596. // usage: FindNodeByField(listptr,data,&list::fieldname)
  597. template <class T, class U, class V> FORCEINLINE T * FindNodeByField(T * head, U data, U V::*field)
  598. {
  599. while( head )
  600. {
  601. if (data == (*head).*field)
  602. return head;
  603. head = head->m_pNext;
  604. }
  605. return 0;
  606. }
  607. // find a node and its predecessor, matching on equality of a given field.
  608. // usage: FindNodeByFieldWithPrev(listptr,data,&list::fieldname, prevptr)
  609. template <class T, class U, class V> FORCEINLINE T * FindNodeByFieldWithPrev(T * head, U data, U V::*field, T * & prev)
  610. {
  611. prev=0;
  612. for(T *i=head; i; i = i->m_pNext)
  613. {
  614. if( data == (*i).*field)
  615. return i;
  616. prev = i;
  617. }
  618. prev = 0;
  619. return 0;
  620. }
  621. /// sort a list. comparefn should return 0 if the items are equal, 1 if A goes first, and -1 if A goes last.
  622. // NOT fast.
  623. template<class T> void SortList(T * &head, int (*comparefn)(T * a, T * b))
  624. {
  625. int didswap=1;
  626. while(didswap)
  627. {
  628. didswap=0;
  629. T *prev=0;
  630. for(T *i=head;i && i->m_pNext; i=i->m_pNext)
  631. {
  632. /// compare i and i+1
  633. int rslt=(*comparefn)(i,i->m_pNext);
  634. if (rslt==-1)
  635. {
  636. /// need to swap
  637. didswap=1;
  638. T *newfirst=i->m_pNext;
  639. if (prev)
  640. {
  641. prev->m_pNext=newfirst;
  642. i->m_pNext=newfirst->m_pNext;
  643. newfirst->m_pNext=i;
  644. }
  645. else
  646. {
  647. head=i->m_pNext;
  648. i->m_pNext=newfirst->m_pNext;
  649. newfirst->m_pNext=i;
  650. }
  651. i=newfirst;
  652. }
  653. prev=i;
  654. }
  655. }
  656. }
  657. // sort a doubly linked list. NOt fast.
  658. template <class T> void SortDList(T * & head, int (*comparefn)(T * a, T * b))
  659. {
  660. SortList(head,comparefn);
  661. /// now, regen prev ptrs
  662. T *prev=0;
  663. for(T *i=head;i;i=i->m_pNext)
  664. {
  665. i->m_pPrev=prev;
  666. prev=i;
  667. }
  668. }
  669. // reverse a singly linked list. not recommended for anything other than valve programming
  670. // interview :-)
  671. template <class T> T *ReversedList( T * head )
  672. {
  673. T * pNewHead=NULL;
  674. while( head )
  675. {
  676. T *pNext=head->m_pNext;
  677. #ifdef INTERVIEW_QUESTION
  678. head->m_pNext=pNewHead;
  679. pNewHead = head;
  680. #else
  681. AddToHead( pNewHead, head );
  682. #endif
  683. head = pNext;
  684. }
  685. return pNewHead;
  686. }
  687. };
  688. // singly linked list
  689. template<class T> class CUtlIntrusiveList
  690. {
  691. public:
  692. T *m_pHead;
  693. FORCEINLINE T *Head( void ) const
  694. {
  695. return m_pHead;
  696. }
  697. FORCEINLINE CUtlIntrusiveList(void)
  698. {
  699. m_pHead = NULL;
  700. }
  701. FORCEINLINE void RemoveAll( void )
  702. {
  703. // empty list. doesn't touch nodes at all
  704. m_pHead = NULL;
  705. }
  706. FORCEINLINE void AddToHead( T * node )
  707. {
  708. IntrusiveList::AddToHead( m_pHead, node );
  709. }
  710. FORCEINLINE void AddToHeadTS( T * pNode)
  711. {
  712. IntrusiveList::AddToHeadTS( m_pHead, pNode );
  713. }
  714. FORCEINLINE void AddToTail( T * node )
  715. {
  716. IntrusiveList::AddToTail( m_pHead, node );
  717. }
  718. void RemoveNode(T *which)
  719. {
  720. IntrusiveList::RemoveFromList( m_pHead, which );
  721. }
  722. // this will kill a list if the list is of objects which automatically
  723. // remove themselves from the list when delete is called
  724. void KillList( void )
  725. {
  726. while(m_pHead)
  727. {
  728. delete m_pHead;
  729. }
  730. }
  731. // return the node in head before in a singly linked list. returns null if head is empty, n is
  732. // null, or if n is the first node. not fast. Fast for dlists
  733. T * PrevNode(T *node)
  734. {
  735. return IntrusiveList::PrevNode( m_pHead, node );
  736. }
  737. int NthNode( int n )
  738. {
  739. return NthNode( m_pHead, n );
  740. }
  741. // this will kill all elements in a list if
  742. // the elements are of a type which does NOT remove itself from
  743. // the list when the destructor is called.
  744. void Purge( void )
  745. {
  746. while (m_pHead)
  747. {
  748. T* tmp=m_pHead->m_pNext;
  749. delete m_pHead;
  750. m_pHead=tmp;
  751. }
  752. }
  753. int Count( void ) const
  754. {
  755. return IntrusiveList::ListLength( m_pHead );
  756. }
  757. FORCEINLINE T * FindNamedNodeCaseSensitive( char const *pName ) const
  758. {
  759. return IntrusiveList::FindNamedNodeCaseSensitive( m_pHead, pName );
  760. }
  761. // find data in a singly linked list, using equality match on any field
  762. // usage: FindNodeByField(data,&list::fieldname)
  763. template <class U, class V> FORCEINLINE T * FindNodeByField( U data, U V::*field)
  764. {
  765. return IntrusiveList::FindNodeByField( m_pHead, data, field );
  766. }
  767. T *RemoveHead( void )
  768. {
  769. if ( m_pHead )
  770. {
  771. T *pRet = m_pHead;
  772. m_pHead = static_cast< T* >( pRet->m_pNext );
  773. return pRet;
  774. }
  775. else
  776. return NULL;
  777. }
  778. };
  779. // doubly linked list
  780. template<class T> class CUtlIntrusiveDList : public CUtlIntrusiveList<T>
  781. {
  782. public:
  783. FORCEINLINE void AddToHead( T * node )
  784. {
  785. IntrusiveList::AddToDHead( CUtlIntrusiveList<T>::m_pHead, node );
  786. }
  787. FORCEINLINE void AddToTail( T * node )
  788. {
  789. IntrusiveList::AddToDTail( CUtlIntrusiveList<T>::m_pHead, node );
  790. }
  791. void RemoveNode(T *which)
  792. {
  793. IntrusiveList::RemoveFromDList( CUtlIntrusiveList<T>::m_pHead, which );
  794. }
  795. T *RemoveHead( void )
  796. {
  797. if ( CUtlIntrusiveList<T>::m_pHead )
  798. {
  799. T *pRet = CUtlIntrusiveList<T>::m_pHead;
  800. CUtlIntrusiveList<T>::m_pHead = CUtlIntrusiveList<T>::m_pHead->m_pNext;
  801. if ( CUtlIntrusiveList<T>::m_pHead )
  802. CUtlIntrusiveList<T>::m_pHead->m_pPrev = NULL;
  803. return pRet;
  804. }
  805. else
  806. return NULL;
  807. }
  808. T * PrevNode(T *node)
  809. {
  810. return ( node )?node->m_Prev:NULL;
  811. }
  812. };
  813. // doubly linked list with a tail ptr for fast addtotail.
  814. template<class T> class CUtlIntrusiveDListWithTailPtr : public CUtlIntrusiveDList<T>
  815. {
  816. public:
  817. T *m_pTailPtr;
  818. FORCEINLINE CUtlIntrusiveDListWithTailPtr( void ) : CUtlIntrusiveDList<T>()
  819. {
  820. m_pTailPtr = NULL;
  821. }
  822. FORCEINLINE void AddToHead( T * node )
  823. {
  824. IntrusiveList::AddToDHeadWithTailPtr( CUtlIntrusiveList<T>::m_pHead, node, m_pTailPtr );
  825. }
  826. FORCEINLINE void AddToTail( T * node )
  827. {
  828. IntrusiveList::AddToDTailWithTailPtr( CUtlIntrusiveList<T>::m_pHead, node, m_pTailPtr );
  829. }
  830. void RemoveNode( T *pWhich )
  831. {
  832. IntrusiveList::RemoveFromDListWithTailPtr( CUtlIntrusiveList<T>::m_pHead, pWhich, m_pTailPtr );
  833. }
  834. void Purge( void )
  835. {
  836. CUtlIntrusiveList<T>::Purge();
  837. m_pTailPtr = NULL;
  838. }
  839. void Kill( void )
  840. {
  841. CUtlIntrusiveList<T>::Purge();
  842. m_pTailPtr = NULL;
  843. }
  844. T *RemoveHead( void )
  845. {
  846. if ( CUtlIntrusiveDList<T>::m_pHead )
  847. {
  848. T *pRet = CUtlIntrusiveDList<T>::m_pHead;
  849. CUtlIntrusiveDList<T>::m_pHead = CUtlIntrusiveDList<T>::m_pHead->m_pNext;
  850. if ( CUtlIntrusiveDList<T>::m_pHead )
  851. CUtlIntrusiveDList<T>::m_pHead->m_pPrev = NULL;
  852. if (! CUtlIntrusiveDList<T>::m_pHead )
  853. m_pTailPtr = NULL;
  854. IntrusiveList::ValidateDList( CUtlIntrusiveDList<T>::m_pHead );
  855. return pRet;
  856. }
  857. else
  858. return NULL;
  859. }
  860. T * PrevNode(T *node)
  861. {
  862. return ( node )?node->m_Prev:NULL;
  863. }
  864. };
  865. template<class T> void PrependDListWithTailToDList( CUtlIntrusiveDListWithTailPtr<T> &src,
  866. CUtlIntrusiveDList<T> &dest )
  867. {
  868. if ( src.m_pHead )
  869. {
  870. src.m_pTailPtr->m_pNext = dest.m_pHead;
  871. if ( dest.m_pHead )
  872. dest.m_pHead->m_pPrev = src.m_pTailPtr;
  873. dest.m_pHead = src.m_pHead;
  874. IntrusiveList::ValidateDList( dest.m_pHead );
  875. }
  876. }
  877. template<class T> class CUtlIntrusiveListWithTailPtr : public CUtlIntrusiveList<T>
  878. {
  879. public:
  880. T *m_pTailPtr;
  881. FORCEINLINE CUtlIntrusiveListWithTailPtr( void ) : CUtlIntrusiveList<T>()
  882. {
  883. m_pTailPtr = NULL;
  884. }
  885. FORCEINLINE void AddToHead( T * pNode )
  886. {
  887. if ( !this->m_pHead )
  888. {
  889. m_pTailPtr = pNode;
  890. }
  891. IntrusiveList::AddToHead( CUtlIntrusiveList<T>::m_pHead, pNode );
  892. }
  893. FORCEINLINE void AddToTail( T * node )
  894. {
  895. IntrusiveList::AddToEndWithTail( CUtlIntrusiveList<T>::m_pHead, node, m_pTailPtr );
  896. }
  897. void Purge( void )
  898. {
  899. CUtlIntrusiveList<T>::Purge();
  900. m_pTailPtr = NULL;
  901. }
  902. void Kill( void )
  903. {
  904. CUtlIntrusiveList<T>::Purge();
  905. m_pTailPtr = NULL;
  906. }
  907. T *RemoveHead( void )
  908. {
  909. if ( CUtlIntrusiveList<T>::m_pHead )
  910. {
  911. T *pRet = CUtlIntrusiveList<T>::RemoveHead();
  912. if ( CUtlIntrusiveList<T>::m_pHead == NULL )
  913. {
  914. m_pTailPtr = NULL;
  915. }
  916. return pRet;
  917. }
  918. else
  919. return NULL;
  920. }
  921. int Count( void ) const
  922. {
  923. return CUtlIntrusiveList<T>::Count();
  924. }
  925. };
  926. template<class T, int BUCKETSIZE> class CUtlSymbolStore
  927. {
  928. struct SymbolNode_t
  929. {
  930. SymbolNode_t *m_pNext;
  931. T *m_pData;
  932. };
  933. CUtlIntrusiveList<SymbolNode_t> m_Buckets[BUCKETSIZE];
  934. public:
  935. T const *FindOrAdd( T const *pData )
  936. {
  937. // see if it is there. add if not. return permanent pointer
  938. uint hVal = HashItem( *pData ) % BUCKETSIZE;
  939. for( SymbolNode_t *i = m_Buckets[hVal].m_pHead; i; i = i->m_pNext )
  940. {
  941. if ( memcmp( pData, i->m_pData, sizeof( T ) ) == 0 )
  942. return i->m_pData;
  943. }
  944. // need to add it
  945. SymbolNode_t *pNew = new SymbolNode_t;
  946. pNew->m_pData = new T;
  947. *( pNew->m_pData ) = ( *pData );
  948. m_Buckets[hVal].AddToHead( pNew );
  949. return pNew->m_pData;
  950. }
  951. };
  952. #endif