Leaked source code of windows server 2003
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.

892 lines
15 KiB

  1. /*++
  2. TFDLIST.H
  3. This header file defines templates for manipulating doubly linked lists.
  4. These are intrusive lists - the client must provide a DLIST_ENTRY item
  5. within each data member for us to maintain the list.
  6. --*/
  7. #ifndef _TFDLIST_H_
  8. #define _TFDLIST_H_
  9. class DLIST_ENTRY {
  10. /*++
  11. Class Description :
  12. This class is intended to be incorporated into classes which are held
  13. within doubly linked lists. This class will define two pointers used
  14. to chain the items within the lists.
  15. IMPORTANT : m_pNext and m_pPrev point to DLIST_ENTRY's and not to the
  16. top of the containing item - the template classes provided following here
  17. are to be used to manipulate these items.
  18. --*/
  19. private :
  20. //
  21. // These are private - they don't make sense for clients !
  22. //
  23. DLIST_ENTRY( DLIST_ENTRY& ) ;
  24. DLIST_ENTRY& operator=(DLIST_ENTRY&) ;
  25. protected :
  26. //
  27. // The items which allows maintain the doubly linked list !
  28. //
  29. class DLIST_ENTRY* m_pNext ;
  30. class DLIST_ENTRY* m_pPrev ;
  31. //
  32. // The base class for all iterators !
  33. //
  34. friend class DLISTIterator ;
  35. void
  36. InsertAfter( DLIST_ENTRY* p ) {
  37. /*++
  38. Routine Description :
  39. Insert an item into the list after THIS !
  40. Arguments :
  41. p - the item to be inserted !
  42. Return Value
  43. None.
  44. --*/
  45. _ASSERT( m_pNext != 0 ) ;
  46. _ASSERT( m_pPrev != 0 ) ;
  47. _ASSERT( p->m_pNext == p ) ;
  48. _ASSERT( p->m_pPrev == p ) ;
  49. DLIST_ENTRY* pNext = m_pNext ;
  50. p->m_pNext = pNext ;
  51. p->m_pPrev = this ;
  52. pNext->m_pPrev = p ;
  53. m_pNext = p ;
  54. }
  55. void
  56. InsertBefore( DLIST_ENTRY* p ) {
  57. /*++
  58. Routine Description :
  59. Insert an item into the list before THIS !
  60. Arguments :
  61. p - the item to be inserted !
  62. Return Value
  63. None.
  64. --*/
  65. _ASSERT( m_pNext != 0 ) ;
  66. _ASSERT( m_pPrev != 0 ) ;
  67. _ASSERT( p->m_pNext == p ) ;
  68. _ASSERT( p->m_pPrev == p ) ;
  69. DLIST_ENTRY* pPrev = m_pPrev ;
  70. p->m_pNext = this ;
  71. p->m_pPrev = pPrev ;
  72. pPrev->m_pNext = p ;
  73. m_pPrev = p ;
  74. }
  75. public :
  76. //
  77. // Initialize a list !
  78. //
  79. DLIST_ENTRY() {
  80. m_pNext = this ;
  81. m_pPrev = this ;
  82. }
  83. //
  84. // It would be nice to comment out this Destructor in Retail builds,
  85. // however - VC5 has a compiler bug where if you allocate an array of
  86. // DLIST_ENTRY objects it adds a DWORD to hold the number of allocated
  87. // objects. Unless you have a Destructor (even a do nothing like this
  88. // one will be in retail), the delete[] operator won't do the math
  89. // to account for the DWORD counter - and you get Assert's etc...
  90. // in your memory allocators.
  91. //
  92. //#ifdef DEBUG
  93. //
  94. // Destroy an item in a list - should be empty when destroyed !
  95. //
  96. ~DLIST_ENTRY() {
  97. _ASSERT( m_pNext == this ) ;
  98. _ASSERT( m_pPrev == this ) ;
  99. _ASSERT( m_pNext == m_pPrev ) ;
  100. }
  101. //#endif
  102. BOOL
  103. IsEmpty() {
  104. /*++
  105. Routine Description :
  106. This function returns TRUE if there is nothing else in the list but us.
  107. Arguments :
  108. None.
  109. Return Value :
  110. TRUE if Empty, FALSE otherwise !
  111. --*/
  112. _ASSERT( m_pPrev != 0 && m_pNext != 0 ) ;
  113. return m_pPrev == this ;
  114. }
  115. void
  116. RemoveEntry( ) {
  117. /*++
  118. Routine Description :
  119. Remote this item from the list !
  120. Arguments :
  121. None.
  122. Return Value :
  123. None.
  124. --*/
  125. _ASSERT( m_pNext != 0 ) ;
  126. _ASSERT( m_pPrev != 0 ) ;
  127. DLIST_ENTRY* pPrev = m_pPrev ;
  128. DLIST_ENTRY* pNext = m_pNext ;
  129. pPrev->m_pNext = pNext ;
  130. pNext->m_pPrev = pPrev ;
  131. m_pPrev = this ;
  132. m_pNext = this ;
  133. }
  134. void
  135. Join( DLIST_ENTRY& head ) {
  136. /*++
  137. Routine Description :
  138. Take one list and join it with another.
  139. The referenced head of the list is not to become an element in the list,
  140. and is left with an empty head !
  141. Arguments ;
  142. head - the head of the list that is to become empty, and whose elements
  143. are to be joined into this list !
  144. Return Value :
  145. None.
  146. --*/
  147. _ASSERT( m_pNext != 0 ) ;
  148. _ASSERT( m_pPrev != 0 ) ;
  149. if( !head.IsEmpty() ) {
  150. //
  151. // First - save the guy that is at the head of our list !
  152. //
  153. DLIST_ENTRY* pNext = m_pNext ;
  154. head.m_pPrev->m_pNext = pNext ;
  155. pNext->m_pPrev = head.m_pPrev ;
  156. head.m_pNext->m_pPrev = this ;
  157. m_pNext = head.m_pNext ;
  158. head.m_pNext = &head ;
  159. head.m_pPrev = &head ;
  160. }
  161. _ASSERT( head.IsEmpty() ) ;
  162. }
  163. } ;
  164. class DLISTIterator {
  165. /*++
  166. Class Description :
  167. Implement an iterator which can go both directions over
  168. doubly linked lists built on the DLIST_ENTRY class !
  169. This is the base class for a set of templates that will
  170. provide iteration over generic items which contain DLIST_ENTRY
  171. objects for their list manipulation !
  172. --*/
  173. protected :
  174. //
  175. // The current position in the list !
  176. //
  177. DLIST_ENTRY *m_pCur ;
  178. //
  179. // the DLIST_ENTRY which is both head & tail of the list
  180. // (since it is circular !)
  181. //
  182. DLIST_ENTRY *m_pHead ;
  183. public :
  184. //
  185. // TRUE if we're using the m_pNext pointers to go forward !
  186. // This member should not be manipulated by clients - its exposed
  187. // for read only purposes only.
  188. //
  189. BOOL m_fForward ;
  190. DLISTIterator(
  191. DLIST_ENTRY* pHead,
  192. BOOL fForward = TRUE
  193. ) :
  194. m_pHead( pHead ),
  195. m_fForward( fForward ),
  196. m_pCur( fForward ? pHead->m_pNext : pHead->m_pPrev ) {
  197. _ASSERT( m_pHead != 0 ) ;
  198. }
  199. void
  200. ReBind( DLIST_ENTRY* pHead,
  201. BOOL fForward
  202. ) {
  203. m_pHead = pHead ;
  204. m_fForward = fForward ;
  205. m_pCur = fForward ? pHead->m_pNext : pHead->m_pPrev ;
  206. }
  207. void
  208. ReBind( DLIST_ENTRY* pHead ) {
  209. m_pHead = pHead ;
  210. m_pCur = m_fForward ? pHead->m_pNext : pHead->m_pPrev ;
  211. }
  212. void
  213. Prev() {
  214. /*++
  215. Routine Description :
  216. This function moves the iterator back one slot.
  217. Note that m_pHead is the end of the list, and we avoiud
  218. setting m_pCur equal to m_pHead !
  219. Arguments :
  220. None.
  221. Return Value :
  222. None.
  223. --*/
  224. _ASSERT( m_pCur != m_pHead || m_pHead->IsEmpty() || m_fForward ) ;
  225. m_pCur = m_pCur->m_pPrev ;
  226. m_fForward = FALSE ;
  227. }
  228. void
  229. Next() {
  230. /*++
  231. Routine Description :
  232. This function moves the iterator forward one slot.
  233. Note that m_pHead is the end of the list, and we avoiud
  234. setting m_pCur equal to m_pHead !
  235. Arguments :
  236. None.
  237. Return Value :
  238. None.
  239. --*/
  240. _ASSERT( m_pCur != m_pHead || m_pHead->IsEmpty() || !m_fForward ) ;
  241. m_pCur = m_pCur->m_pNext ;
  242. m_fForward = TRUE ;
  243. }
  244. void
  245. Front() {
  246. /*++
  247. Routine Description :
  248. Reset the iterator to reference the first item of the list !
  249. Arguments :
  250. None.
  251. Return Value :
  252. None.
  253. --*/
  254. m_pCur = m_pHead->m_pNext ;
  255. m_fForward = TRUE ;
  256. }
  257. void
  258. Back() {
  259. /*++
  260. Routine Description :
  261. Reset the iterator to reference the last item of the list !
  262. Arguments :
  263. None.
  264. Return Value :
  265. None.
  266. --*/
  267. m_pCur = m_pHead->m_pPrev ;
  268. m_fForward = FALSE ;
  269. }
  270. BOOL
  271. AtEnd() {
  272. /*++
  273. Routine Description :
  274. Return TRUE if we are at the end of the list !
  275. This is a little more complicated to compute -
  276. depends on which way we are going !
  277. Arguments :
  278. None.
  279. Return Value :
  280. None.
  281. --*/
  282. return m_pCur == m_pHead ;
  283. }
  284. DLIST_ENTRY*
  285. CurrentEntry() {
  286. return m_pCur ;
  287. }
  288. DLIST_ENTRY*
  289. RemoveItemEntry() {
  290. /*++
  291. Routine Description :
  292. Remove the item that the iterator currently
  293. references from the list.
  294. If we are going forward then the iterator
  295. will be setting on the previous element,
  296. otherwise the iterator is left on the next element.
  297. We have to take care that we don't leave the iterator
  298. sitting on an invalid element.
  299. Arguments :
  300. None.
  301. Return Value :
  302. Pointer to the removed item.
  303. --*/
  304. if( m_pCur == m_pHead )
  305. return 0 ;
  306. DLIST_ENTRY* pTemp = m_pCur ;
  307. if( m_fForward ) {
  308. m_pCur = pTemp->m_pNext;
  309. } else {
  310. m_pCur = pTemp->m_pPrev ;
  311. }
  312. pTemp->RemoveEntry() ;
  313. return pTemp ;
  314. }
  315. void
  316. InsertBefore( DLIST_ENTRY* p ) {
  317. /*++
  318. Routine Description :
  319. Insert an item before our current position in the list !
  320. Arguments :
  321. None.
  322. Return Value :
  323. Nothin
  324. --*/
  325. m_pCur->InsertBefore( p ) ;
  326. }
  327. void
  328. InsertAfter( DLIST_ENTRY* p ) {
  329. /*++
  330. Routine Description :
  331. Insert an Item after our current position in the list !
  332. Arguments :
  333. None.
  334. Return Value :
  335. Nothin
  336. --*/
  337. m_pCur->InsertAfter( p ) ;
  338. }
  339. } ;
  340. template< class LISTHEAD >
  341. class TDListIterator : public DLISTIterator {
  342. /*++
  343. Class Description :
  344. This class provides an iterator which can walk over a specified List !
  345. --*/
  346. public :
  347. typedef typename LISTHEAD::EXPORTDATA Data ;
  348. private :
  349. #if 0
  350. //
  351. // Make the following functions private !
  352. // They come from DLISTIterator and are not for use by our customers !
  353. //
  354. void
  355. ReBind( DLIST_ENTRY* pHead,
  356. BOOL fForward
  357. ) ;
  358. void
  359. ReBind( DLIST_ENTRY* pHead ) ;
  360. #endif
  361. //
  362. // Make the following functions private !
  363. // They come from DLISTIterator and are not for use by our customers !
  364. //
  365. DLIST_ENTRY*
  366. RemoveItemEntry() ;
  367. //
  368. // Make the following functions private !
  369. // They come from DLISTIterator and are not for use by our customers !
  370. //
  371. DLIST_ENTRY*
  372. CurrentEntry() ;
  373. //
  374. // Make the following functions private !
  375. // They come from DLISTIterator and are not for use by our customers !
  376. //
  377. void
  378. InsertBefore( DLIST_ENTRY* ) ;
  379. //
  380. // Make the following functions private !
  381. // They come from DLISTIterator and are not for use by our customers !
  382. //
  383. void
  384. InsertAfter( DLIST_ENTRY* ) ;
  385. public :
  386. TDListIterator(
  387. LISTHEAD* pHead,
  388. BOOL fForward = TRUE
  389. ) :
  390. DLISTIterator( pHead, fForward ) {
  391. }
  392. TDListIterator(
  393. LISTHEAD& head,
  394. BOOL fForward = TRUE
  395. ) : DLISTIterator( &head, fForward ) {
  396. }
  397. TDListIterator(
  398. DLIST_ENTRY* pHead,
  399. BOOL fForward = TRUE
  400. ) :
  401. DLISTIterator( pHead, fForward ) {
  402. }
  403. void
  404. ReBind( LISTHEAD* pHead ) {
  405. DLISTIterator::ReBind( pHead ) ;
  406. }
  407. void
  408. ReBind( LISTHEAD* pHead, BOOL fForward ) {
  409. DLISTIterator::ReBind( pHead, fForward ) ;
  410. }
  411. inline Data*
  412. Current( ) {
  413. return LISTHEAD::Convert( m_pCur ) ;
  414. }
  415. inline Data*
  416. RemoveItem( ) {
  417. DLIST_ENTRY* pTemp = DLISTIterator::RemoveItemEntry() ;
  418. return LISTHEAD::Convert( pTemp ) ;
  419. }
  420. inline void
  421. InsertBefore( Data* p ) {
  422. DLIST_ENTRY* pTemp = LISTHEAD::Convert( p ) ;
  423. DLISTIterator::InsertBefore( pTemp ) ;
  424. }
  425. inline void
  426. InsertAfter( Data* p ) {
  427. DLIST_ENTRY* pTemp = LISTHEAD::Convert( p ) ;
  428. DLISTIterator::InsertAfter( pTemp ) ;
  429. }
  430. //
  431. // For debug purposes - let people know what the head is !
  432. //
  433. LISTHEAD*
  434. GetHead() {
  435. return (LISTHEAD*)m_pHead ;
  436. }
  437. } ;
  438. template< class Data,
  439. typename Data::PFNDLIST pfnConvert >
  440. class TDListHead : private DLIST_ENTRY {
  441. /*++
  442. Class Description :
  443. This class defines the head of a doubly linked list of items of DATAHELPER::LISTDATA
  444. We provide all the functions required to manipulate the list, and a mechanism
  445. for creating iterators.
  446. --*/
  447. public :
  448. //
  449. // Publicly redefine the type that we deal with into a nice short form !
  450. //
  451. typedef Data EXPORTDATA ;
  452. private :
  453. //
  454. // These kinds of iterators are our friends !
  455. //
  456. friend class TDListIterator< TDListHead<Data, pfnConvert> > ;
  457. static inline Data*
  458. Convert( DLIST_ENTRY* p ) {
  459. /*++
  460. Routine Description :
  461. This function takes a pointer to a DLIST_ENTRY and returns a pointer
  462. to the beginning of the data item !
  463. Arguments :
  464. p - pointer to a DLIST_ENTRY found within our list !
  465. Return Value :
  466. Pointer to the Data Item containing the referenced DLIST_ENTRY !
  467. --*/
  468. if( p ) {
  469. return (Data*)(((PCHAR)p) - (PCHAR)(pfnConvert(0))) ;
  470. }
  471. return 0 ;
  472. }
  473. static inline DLIST_ENTRY*
  474. Convert( Data* pData ) {
  475. return pfnConvert(pData) ;
  476. }
  477. //
  478. // Copy Constructor and Operator= are private, as they don't make sense !
  479. //
  480. public :
  481. //
  482. // Redefine this to be public !
  483. //
  484. inline BOOL
  485. IsEmpty() {
  486. return DLIST_ENTRY::IsEmpty() ;
  487. }
  488. inline void
  489. PushFront( Data* pData ) {
  490. /*++
  491. Routine Description :
  492. Push the Data item onto the front of the doubly linked list !
  493. Arguments :
  494. pData - item to add to the front of the list
  495. Return Value :
  496. None.
  497. --*/
  498. _ASSERT( pData != 0 ) ;
  499. _ASSERT( m_pNext != 0 ) ;
  500. _ASSERT( m_pPrev != 0 ) ;
  501. DLIST_ENTRY* p = Convert(pData);
  502. InsertAfter( p ) ;
  503. _ASSERT( m_pNext != 0 ) ;
  504. _ASSERT( m_pPrev != 0 ) ;
  505. }
  506. inline void
  507. PushBack( Data* pData ) {
  508. /*++
  509. Routine Description :
  510. Push the Data item onto the back of the doubly linked list !
  511. Arguments :
  512. pData - item to add to the front of the list
  513. Return Value :
  514. None.
  515. --*/
  516. _ASSERT( pData != 0 ) ;
  517. _ASSERT( m_pNext != 0 ) ;
  518. _ASSERT( m_pPrev != 0 ) ;
  519. DLIST_ENTRY* p = Convert(pData) ;
  520. InsertBefore( p ) ;
  521. _ASSERT( m_pNext != 0 ) ;
  522. _ASSERT( m_pPrev != 0 ) ;
  523. }
  524. inline Data*
  525. PopFront() {
  526. /*++
  527. Routine Description :
  528. Remove the data item from the front of the List !
  529. Arguments :
  530. None.
  531. Return Value :
  532. The front of the list - NULL if empty !
  533. --*/
  534. _ASSERT( m_pNext != 0 ) ;
  535. _ASSERT( m_pPrev != 0 ) ;
  536. DLIST_ENTRY* pReturn = 0;
  537. if( m_pNext != this ) {
  538. pReturn = m_pNext ;
  539. pReturn->RemoveEntry() ;
  540. }
  541. _ASSERT( m_pNext != 0 ) ;
  542. _ASSERT( m_pPrev != 0 ) ;
  543. return Convert( pReturn ) ;
  544. }
  545. inline Data*
  546. PopBack() {
  547. /*++
  548. Routine Description :
  549. Remove the data item from the Back of the List !
  550. Arguments :
  551. None.
  552. Return Value :
  553. The Back of the list - NULL if empty !
  554. --*/
  555. _ASSERT( m_pNext != 0 ) ;
  556. _ASSERT( m_pPrev != 0 ) ;
  557. DLIST_ENTRY* pReturn = 0 ;
  558. if( m_pPrev != this ) {
  559. pReturn = m_pPrev ;
  560. pReturn->RemoveEntry() ;
  561. }
  562. _ASSERT( m_pNext != 0 ) ;
  563. _ASSERT( m_pPrev != 0 ) ;
  564. return Convert( pReturn ) ;
  565. }
  566. static inline void
  567. Remove( Data* pData ) {
  568. /*++
  569. Routine Description :
  570. Remove the specified item from the list !
  571. Arguments :
  572. None.
  573. Return Value :
  574. The Back of the list - NULL if empty !
  575. --*/
  576. DLIST_ENTRY* p = Convert( pData ) ;
  577. p->RemoveEntry() ;
  578. }
  579. inline Data*
  580. GetFront() {
  581. /*++
  582. Routine Description :
  583. Return the data item from the Front of the List !
  584. Arguments :
  585. None.
  586. Return Value :
  587. The Front of the list - NULL if empty !
  588. --*/
  589. _ASSERT( m_pNext != 0 ) ;
  590. _ASSERT( m_pPrev != 0 ) ;
  591. if( m_pNext == this ) {
  592. return 0 ;
  593. }
  594. return Convert( m_pNext ) ;
  595. }
  596. inline Data*
  597. GetBack() {
  598. /*++
  599. Routine Description :
  600. Return the data item from the Back of the List !
  601. Arguments :
  602. None.
  603. Return Value :
  604. The Back of the list - NULL if empty !
  605. --*/
  606. _ASSERT( m_pNext != 0 ) ;
  607. _ASSERT( m_pPrev != 0 ) ;
  608. if( m_pPrev == this ) {
  609. return 0 ;
  610. }
  611. return Convert( m_pPrev ) ;
  612. }
  613. inline void
  614. Join( TDListHead& head ) {
  615. /*++
  616. Routine Description :
  617. Take one list and join it with another.
  618. The referenced head of the list is not to become an element in the list,
  619. and is left with an empty head !
  620. Arguments ;
  621. head - the head of the list that is to become empty, and whose elements
  622. are to be joined into this list !
  623. Return Value :
  624. None.
  625. --*/
  626. DLIST_ENTRY::Join( head ) ;
  627. }
  628. } ;
  629. #endif // _TFDLIST_H_