EPICS Base  7.0.6.1
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
tsDLList.h
1 /*************************************************************************\
2 * Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3 * National Laboratory.
4 * Copyright (c) 2002 The Regents of the University of California, as
5 * Operator of Los Alamos National Laboratory.
6 * SPDX-License-Identifier: EPICS
7 * EPICS Base is distributed subject to a Software License Agreement found
8 * in file LICENSE that is included with this distribution.
9 \*************************************************************************/
10 /*
11  * type safe doubly linked list templates
12  *
13  * Author Jeffrey O. Hill
15  * 505 665 1831
16  */
17 
18 #ifndef tsDLListH_include
19 #define tsDLListH_include
20 
21 template <class T> class tsDLList;
22 template <class T> class tsDLIterConst;
23 template <class T> class tsDLIter;
24 
25 //
26 // class tsDLNode<T>
27 //
28 // a node in a doubly linked list containing entries of type T
29 // ( class T must publicly derive from class tsDLNode<T> )
30 //
31 template < class T >
32 class tsDLNode {
33 public:
34  tsDLNode ();
35  tsDLNode ( const tsDLNode<T> & );
36  const tsDLNode <T> & operator = ( const tsDLNode<T> & );
37 private:
38  T * pNext;
39  T * pPrev;
40  friend class tsDLList<T>;
41  friend class tsDLIter<T>;
42  friend class tsDLIterConst<T>;
43 };
44 
45 //
46 // class tsDLList<T>
47 //
48 // a doubly linked list containing entries of type T
49 // ( class T must publicly derive from class tsDLNode<T> )
50 //
51 template < class T >
52 class tsDLList {
53 public:
54  tsDLList (); // create empty list
55  unsigned count () const; // number of items on list
56  void add ( T & item ); // add item to end of list
57  void add ( tsDLList<T> & addList ); // add to end of list - addList left empty
58  void push ( T & item ); // add item to beginning of list
59  void push ( tsDLList<T> & pushList ); // add to beg of list - pushList left empty
60  void remove ( T & item ); // remove item from list
61  void removeAll ( tsDLList <T> & destination );
62  T * get (); // removes first item on list
63  T * pop (); // same as get ()
64  void insertAfter ( T & item, T & itemBefore ); // insert item immediately after itemBefore
65  void insertBefore ( T & item, T & itemAfter ); // insert item immediately before itemAfter
66  int find ( const T & item ) const; // returns -1 if not present, node number if present
67  T * first ( void ) const; // ptr to first item on list
68  T * last ( void ) const; // ptr to last item on list
69  tsDLIterConst <T> firstIter () const;
70  tsDLIter <T> firstIter ();
71  tsDLIterConst <T> lastIter () const;
72  tsDLIter <T> lastIter ();
73  static tsDLIterConst <T> invalidConstIter ();
74  static tsDLIter <T> invalidIter ();
75 private:
76  T * pFirst;
77  T * pLast;
78  unsigned itemCount;
79  void clear ();
80  tsDLList ( const tsDLList & ); // not allowed
81  const tsDLList <T> & operator = ( const tsDLList <T> & ); // not allowed
82 };
83 
84 //
85 // class tsDLIterConst<T>
86 //
87 // bi-directional iterator for a const doubly linked list
88 //
89 template <class T>
90 class tsDLIterConst {
91 public:
92  tsDLIterConst ();
93  bool valid () const;
94  bool operator == ( const tsDLIterConst<T> & rhs ) const;
95  bool operator != ( const tsDLIterConst<T> & rhs ) const;
96  tsDLIterConst<T> & operator = ( const tsDLIterConst<T> & );
97  const T & operator * () const;
98  const T * operator -> () const;
99  tsDLIterConst<T> & operator ++ ();
100  tsDLIterConst<T> operator ++ (int);
101  tsDLIterConst<T> & operator -- ();
102  tsDLIterConst<T> operator -- (int);
103  const T * pointer () const;
104 private:
105  const T * pEntry;
106  tsDLIterConst ( const T * pInitialEntry );
107  friend class tsDLList <T>;
108 };
109 
110 //
111 // class tsDLIter<T>
112 //
113 // bi-directional iterator for a doubly linked list
114 //
115 template <class T>
116 class tsDLIter {
117 public:
118  tsDLIter ();
119  bool valid () const;
120  bool operator == ( const tsDLIter<T> & rhs ) const;
121  bool operator != ( const tsDLIter<T> & rhs ) const;
122  tsDLIter<T> & operator = ( const tsDLIter<T> & );
123  T & operator * () const;
124  T * operator -> () const;
125  tsDLIter<T> & operator ++ ();
126  tsDLIter<T> operator ++ ( int );
127  tsDLIter<T> & operator -- ();
128  tsDLIter<T> operator -- ( int );
129  T * pointer () const;
130 private:
131  T * pEntry;
132  tsDLIter ( T *pInitialEntry );
133  friend class tsDLList <T>;
134 };
135 
137 // tsDLNode<T> member functions
139 
140 //
141 // tsDLNode<T>::tsDLNode ()
142 //
143 template <class T>
144 inline tsDLNode<T>::tsDLNode() : pNext(0), pPrev(0) {}
145 
146 template <class T>
147 inline tsDLNode<T>::tsDLNode ( const tsDLNode<T> & ) :
148  pNext (0), pPrev(0) {}
149 
150 //
151 // tsDLNode<T>::operator = ()
152 //
153 // when someone tries to copy another node into a node
154 // do _not_ change the node pointers
155 //
156 template <class T>
157 inline const tsDLNode<T> & tsDLNode<T>::operator = ( const tsDLNode<T> & )
158 {
159  return * this;
160 }
161 
163 // tsDLList<T> member functions
165 
166 //
167 // tsDLList<T>::tsDLList ()
168 //
169 template <class T>
170 inline tsDLList<T>::tsDLList ()
171 {
172  this->clear ();
173 }
174 
175 //
176 // tsDLList<T>::count ()
177 //
178 // (returns the number of items on the list)
179 //
180 template <class T>
181 inline unsigned tsDLList<T>::count () const
182 {
183  return this->itemCount;
184 }
185 
186 //
187 // tsDLList<T>::first ()
188 //
189 template <class T>
190 inline T * tsDLList<T>::first (void) const
191 {
192  return this->pFirst;
193 }
194 
195 //
196 // tsDLList<T>::last ()
197 //
198 template <class T>
199 inline T *tsDLList<T>::last (void) const
200 {
201  return this->pLast;
202 }
203 
204 //
205 // tsDLList<T>::clear ()
206 //
207 template <class T>
208 inline void tsDLList<T>::clear ()
209 {
210  this->pFirst = 0;
211  this->pLast = 0;
212  this->itemCount = 0u;
213 }
214 
215 //
216 // tsDLList<T>::remove ()
217 //
218 template <class T>
219 inline void tsDLList<T>::remove ( T &item )
220 {
221  tsDLNode<T> &theNode = item;
222 
223  if ( this->pLast == &item ) {
224  this->pLast = theNode.pPrev;
225  }
226  else {
227  tsDLNode<T> &nextNode = *theNode.pNext;
228  nextNode.pPrev = theNode.pPrev;
229  }
230 
231  if ( this->pFirst == &item ) {
232  this->pFirst = theNode.pNext;
233  }
234  else {
235  tsDLNode<T> &prevNode = *theNode.pPrev;
236  prevNode.pNext = theNode.pNext;
237  }
238 
239  this->itemCount--;
240 }
241 
242 //
243 // tsDLList<T>::removeAll ()
244 //
245 template <class T>
246 inline void tsDLList<T>::removeAll (
247  tsDLList <T> & destination )
248 {
249  destination.pFirst = this->pFirst;
250  destination.pLast = this->pLast;
251  destination.itemCount = this->itemCount;
252  this->pFirst = 0;
253  this->pLast = 0;
254  this->itemCount = 0;
255 }
256 
257 //
258 // tsDLList<T>::get ()
259 //
260 template <class T>
261 inline T * tsDLList<T>::get()
262 {
263  T *pItem = this->pFirst;
264 
265  if ( pItem ) {
266  this->remove ( *pItem );
267  }
268 
269  return pItem;
270 }
271 
272 //
273 // tsDLList<T>::pop ()
274 //
275 // (returns the first item on the list)
276 template <class T>
277 inline T * tsDLList<T>::pop ()
278 {
279  return this->get ();
280 }
281 
282 //
283 // tsDLList<T>::add ()
284 //
285 // adds addList to the end of the list
286 // (and removes all items from addList)
287 //
288 template <class T>
289 inline void tsDLList<T>::add ( tsDLList<T> &addList )
290 {
291  if ( addList.itemCount != 0u ) {
292  if ( this->itemCount == 0u ) {
293  this->pFirst = addList.pFirst;
294  }
295  else {
296  tsDLNode<T> *pLastNode = this->pLast;
297  tsDLNode<T> *pAddListFirstNode = addList.pFirst;
298  pLastNode->pNext = addList.pFirst;
299  pAddListFirstNode->pPrev = addList.pLast;
300  }
301  this->pLast = addList.pLast;
302  this->itemCount += addList.itemCount;
303  addList.clear();
304  }
305 }
306 
307 //
308 // tsDLList<T>::add ()
309 //
310 // add an item to the end of the list
311 //
312 template <class T>
313 inline void tsDLList<T>::add (T &item)
314 {
315  tsDLNode<T> &theNode = item;
316 
317  theNode.pNext = 0;
318  theNode.pPrev = this->pLast;
319 
320  if ( this->itemCount ) {
321  tsDLNode<T> &lastNode = *this->pLast;
322  lastNode.pNext = &item;
323  }
324  else {
325  this->pFirst = &item;
326  }
327 
328  this->pLast = &item;
329 
330  this->itemCount++;
331 }
332 
333 //
334 // tsDLList<T>::insertAfter ()
335 //
336 // place item in the list immediately after itemBefore
337 //
338 template <class T>
339 inline void tsDLList<T>::insertAfter (T &item, T &itemBefore)
340 {
341  tsDLNode<T> &nodeItem = item;
342  tsDLNode<T> &nodeBefore = itemBefore;
343 
344  nodeItem.pPrev = &itemBefore;
345  nodeItem.pNext = nodeBefore.pNext;
346  nodeBefore.pNext = &item;
347 
348  if (nodeItem.pNext) {
349  tsDLNode<T> *pNextNode = nodeItem.pNext;
350  pNextNode->pPrev = &item;
351  }
352  else {
353  this->pLast = &item;
354  }
355 
356  this->itemCount++;
357 }
358 
359 //
360 // tsDLList<T>::insertBefore ()
361 //
362 // place item in the list immediately before itemAfter
363 //
364 template <class T>
365 inline void tsDLList<T>::insertBefore (T &item, T &itemAfter)
366 {
367  tsDLNode<T> &node = item;
368  tsDLNode<T> &nodeAfter = itemAfter;
369 
370  node.pNext = &itemAfter;
371  node.pPrev = nodeAfter.pPrev;
372  nodeAfter.pPrev = &item;
373 
374  if (node.pPrev) {
375  tsDLNode<T> &prevNode = *node.pPrev;
376  prevNode.pNext = &item;
377  }
378  else {
379  this->pFirst = &item;
380  }
381 
382  this->itemCount++;
383 }
384 
385 //
386 // tsDLList<T>::push ()
387 //
388 // adds pushList to the beginning of the list
389 // (and removes all items from pushList)
390 //
391 template <class T>
392 inline void tsDLList<T>::push ( tsDLList<T> & pushList )
393 {
394  if ( pushList.itemCount != 0u ) {
395  if ( this->itemCount ) {
396  tsDLNode<T> * pFirstNode = this->pFirst;
397  tsDLNode<T> * pAddListLastNode = pushList.pLast;
398  pFirstNode->pPrev = pushList.pLast;
399  pAddListLastNode->pNext = this->pFirst;
400  }
401  else {
402  this->pLast = pushList.pLast;
403  }
404  this->pFirst = pushList.pFirst;
405  this->itemCount += pushList.itemCount;
406  pushList.clear();
407  }
408 }
409 
410 //
411 // tsDLList<T>::push ()
412 //
413 // add an item at the beginning of the list
414 //
415 template <class T>
416 inline void tsDLList<T>::push (T &item)
417 {
418  tsDLNode<T> &theNode = item;
419  theNode.pPrev = 0;
420  theNode.pNext = this->pFirst;
421 
422  if ( this->itemCount ) {
423  tsDLNode<T> *pFirstNode = this->pFirst;
424  pFirstNode->pPrev = & item;
425  }
426  else {
427  this->pLast = & item;
428  }
429 
430  this->pFirst = &item;
431 
432  this->itemCount++;
433 }
434 
435 //
436 // tsDLList<T>::find ()
437 // returns -1 if the item isn't on the list
438 // and the node number (beginning with zero if
439 // it is)
440 //
441 template < class T >
442 int tsDLList < T > :: find ( const T &item ) const
443 {
444  tsDLIterConst < T > thisItem ( &item );
445  tsDLIterConst < T > iter ( this->first () );
446  int itemNo = 0;
447 
448  while ( iter.valid () ) {
449  if ( iter == thisItem ) {
450  return itemNo;
451  }
452  itemNo++;
453  iter++;
454  }
455  return -1;
456 }
457 
458 template < class T >
459 inline tsDLIterConst <T> tsDLList < T > :: firstIter () const
460 {
461  return tsDLIterConst < T > ( this->pFirst );
462 }
463 
464 template < class T >
465 inline tsDLIter <T> tsDLList < T > :: firstIter ()
466 {
467  return tsDLIter < T > ( this->pFirst );
468 }
469 
470 template < class T >
471 inline tsDLIterConst <T> tsDLList < T > :: lastIter () const
472 {
473  return tsDLIterConst < T > ( this->pLast );
474 }
475 
476 template < class T >
477 inline tsDLIter <T> tsDLList < T > :: lastIter ()
478 {
479  return tsDLIter < T > ( this->pLast );
480 }
481 
482 template < class T >
483 inline tsDLIterConst <T> tsDLList < T > :: invalidConstIter ()
484 {
485  return tsDLIterConst < T > ( 0 );
486 }
487 
488 template < class T >
489 inline tsDLIter <T> tsDLList < T > :: invalidIter ()
490 {
491  return tsDLIter < T > ( 0 );
492 }
493 
495 // tsDLIterConst<T> member functions
497 template <class T>
498 inline tsDLIterConst<T>::tsDLIterConst ( const T *pInitialEntry ) :
499  pEntry ( pInitialEntry ) {}
500 
501 template <class T>
503  pEntry ( 0 ) {}
504 
505 template <class T>
506 inline bool tsDLIterConst<T>::valid () const
507 {
508  return this->pEntry != 0;
509 }
510 
511 template <class T>
512 inline bool tsDLIterConst<T>::operator == (const tsDLIterConst<T> &rhs) const
513 {
514  return this->pEntry == rhs.pEntry;
515 }
516 
517 template <class T>
518 inline bool tsDLIterConst<T>::operator != (const tsDLIterConst<T> &rhs) const
519 {
520  return this->pEntry != rhs.pEntry;
521 }
522 
523 template <class T>
525 {
526  this->pEntry = rhs.pEntry;
527  return *this;
528 }
529 
530 template <class T>
531 inline const T & tsDLIterConst<T>::operator * () const
532 {
533  return *this->pEntry;
534 }
535 
536 template <class T>
537 inline const T * tsDLIterConst<T>::operator -> () const
538 {
539  return this->pEntry;
540 }
541 
542 //
543 // prefix ++
544 //
545 template <class T>
547 {
548  const tsDLNode<T> &node = *this->pEntry;
549  this->pEntry = node.pNext;
550  return *this;
551 }
552 
553 //
554 // postfix ++
555 //
556 template <class T>
558 {
559  const tsDLIterConst<T> tmp = *this;
560  const tsDLNode<T> &node = *this->pEntry;
561  this->pEntry = node.pNext;
562  return tmp;
563 }
564 
565 //
566 // prefix --
567 //
568 template <class T>
570 {
571  const tsDLNode<T> &entryNode = *this->pEntry;
572  this->pEntry = entryNode.pPrev;
573  return *this;
574 }
575 
576 //
577 // postfix --
578 //
579 template <class T>
581 {
582  const tsDLIterConst<T> tmp = *this;
583  const tsDLNode<T> &entryNode = *this->pEntry;
584  this->pEntry = entryNode.pPrev;
585  return tmp;
586 }
587 
588 template <class T>
589 inline const T * tsDLIterConst<T>::pointer () const
590 {
591  return this->pEntry;
592 }
593 
595 // tsDLIter<T> member functions
597 
598 template <class T>
599 inline tsDLIter<T>::tsDLIter ( T * pInitialEntry ) :
600  pEntry ( pInitialEntry ) {}
601 
602 template <class T>
603 inline tsDLIter<T>::tsDLIter () :
604  pEntry ( 0 ) {}
605 
606 template <class T>
607 inline bool tsDLIter<T>::valid () const
608 {
609  return this->pEntry != 0;
610 }
611 
612 template <class T>
613 inline bool tsDLIter<T>::operator == (const tsDLIter<T> &rhs) const
614 {
615  return this->pEntry == rhs.pEntry;
616 }
617 
618 template <class T>
619 inline bool tsDLIter<T>::operator != (const tsDLIter<T> &rhs) const
620 {
621  return this->pEntry != rhs.pEntry;
622 }
623 
624 template <class T>
625 inline tsDLIter<T> & tsDLIter<T>::operator = ( const tsDLIter<T> & rhs )
626 {
627  this->pEntry = rhs.pEntry;
628  return *this;
629 }
630 
631 template <class T>
632 inline T & tsDLIter<T>::operator * () const
633 {
634  return *this->pEntry;
635 }
636 
637 template <class T>
638 inline T * tsDLIter<T>::operator -> () const
639 {
640  return this->pEntry;
641 }
642 
643 template <class T>
644 inline tsDLIter<T> & tsDLIter<T>::operator ++ () // prefix ++
645 {
646  const tsDLNode<T> &entryNode = *this->pEntry;
647  this->pEntry = entryNode.pNext;
648  return *this;
649 }
650 
651 template <class T>
652 inline tsDLIter<T> tsDLIter<T>::operator ++ (int) // postfix ++
653 {
654  const tsDLIter<T> tmp = *this;
655  const tsDLNode<T> &entryNode = *this->pEntry;
656  this->pEntry = entryNode.pNext;
657  return tmp;
658 }
659 
660 template <class T>
661 inline tsDLIter<T> & tsDLIter<T>::operator -- () // prefix --
662 {
663  const tsDLNode<T> &entryNode = *this->pEntry;
664  this->pEntry = entryNode.pPrev;
665  return *this;
666 }
667 
668 template <class T>
669 inline tsDLIter<T> tsDLIter<T>::operator -- (int) // postfix --
670 {
671  const tsDLIter<T> tmp = *this;
672  const tsDLNode<T> &entryNode = *this->pEntry;
673  this->pEntry = entryNode.pPrev;
674  return tmp;
675 }
676 
677 template <class T>
678 inline T * tsDLIter<T>::pointer () const
679 {
680  return this->pEntry;
681 }
682 
683 #endif // tsDLListH_include
684