2 * Copyright 2001 Adrian Thurston <thurston@complang.org>
5 /* This file is part of Aapl.
7 * Aapl is free software; you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free
9 * Software Foundation; either version 2.1 of the License, or (at your option)
12 * Aapl is distributed in the hope that it will be useful, but WITHOUT ANY
13 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with Aapl; if not, write to the Free Software Foundation, Inc., 59
19 * Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 /* This header is not wrapped in ifndef becuase it is not intended to
23 * be included by the user. */
29 #if defined( DOUBLELIST_VALUE )
31 * \brief Double list element for DListVal.
33 * DListValEl stores the type T of DListVal by value.
35 template <class T> struct DListValEl
38 * \brief Construct a DListValEl with a given value.
40 * The only constructor available initializes the value element. This
41 * enforces that DListVal elements are never created without having their
42 * value intialzed by the user. T's copy constructor is used to copy the
45 DListValEl( const T &val ) : value(val) { }
48 * \brief Value stored by the list element.
50 * Value is always copied into new list elements using the copy
56 * \brief List previous pointer.
58 * Points to the previous item in the list. If this is the first item in
59 * the list, then prev is NULL. If this element is not in a list then
65 * \brief List next pointer.
67 * Points to the next item in the list. If this is the list item in the
68 * list, then next is NULL. If this element is not in a list then next is
75 #ifndef __AAPL_DOUBLE_LIST_EL
76 #define __AAPL_DOUBLE_LIST_EL
78 * \brief Double list element properties.
80 * This class can be inherited to make a class suitable to be a double list
81 * element. It simply provides the next and previous pointers. An alternative
82 * is to put the next and previous pointers in the class directly.
84 template <class Element> struct DListEl
87 * \brief List previous pointer.
89 * Points to the previous item in the list. If this is the first item in
90 * the list, then prev is NULL. If this element is not in a list then
96 * \brief List next pointer.
98 * Points to the next item in the list. If this is the list item in the
99 * list, then next is NULL. If this element is not in a list then next is
104 #endif /* __AAPL_DOUBLE_LIST_EL */
108 /* Doubly Linked List */
109 template <DLMEL_TEMPDEF> class DList
112 /** \brief Initialize an empty list. */
113 DList() : head(0), tail(0), listLen(0) {}
116 * \brief Perform a deep copy of the list.
118 * The elements of the other list are duplicated and put into this list.
119 * Elements are copied using the copy constructor.
121 DList(const DList &other);
123 #ifdef DOUBLELIST_VALUE
125 * \brief Clear the double list contents.
127 * All elements are deleted.
129 ~DList() { empty(); }
132 * \brief Assign another list into this list using a deep copy.
134 * The elements of the other list are duplicated and put into this list.
135 * Each list item is created using the copy constructor. If this list
136 * contains any elements before the copy, they are deleted first.
138 * \returns A reference to this.
140 DList &operator=(const DList &other);
143 * \brief Transfer the contents of another list into this list.
145 * The elements of the other list moved in. The other list will be empty
146 * afterwards. If this list contains any elements before the copy, then
149 void transfer(DList &other);
152 * \brief Abandon all elements in the list.
154 * List elements are not deleted.
159 * \brief Perform a deep copy of the list.
161 * The elements of the other list are duplicated and put into this list.
162 * Each list item is created using the copy constructor. If this list
163 * contains any elements before the copy, they are abandoned.
165 * \returns A reference to this.
167 DList &operator=(const DList &other);
170 * \brief Transfer the contents of another list into this list.
172 * The elements of the other list moved in. The other list will be empty
173 * afterwards. If this list contains any elements before the copy, they
176 void transfer(DList &other);
180 #ifdef DOUBLELIST_VALUE
182 * \brief Make a new element and prepend it to the front of the list.
184 * The item is copied into the new element using the copy constructor.
185 * Equivalent to list.addBefore(list.head, item).
187 void prepend(const T &item);
190 * \brief Make a new element and append it to the end of the list.
192 * The item is copied into the new element using the copy constructor.
193 * Equivalent to list.addAfter(list.tail, item).
195 void append(const T &item);
198 * \brief Make a new element and insert it immediately after an element in
201 * The item is copied into the new element using the copy constructor. If
202 * prev_el is NULL then the new element is prepended to the front of the
203 * list. If prev_el is not already in the list then undefined behaviour
204 * results. Equivalent to list.addAfter(prev_el, new DListValEl(item)).
206 void addAfter(Element *prev_el, const T &item);
209 * \brief Make a new element and insert it immediately before an element
212 * The item is copied into the new element using the copy construcotor. If
213 * next_el is NULL then the new element is appended to the end of the
214 * list. If next_el is not already in the list then undefined behaviour
215 * results. Equivalent to list.addBefore(next_el, new DListValEl(item)).
217 void addBefore(Element *next_el, const T &item);
221 * \brief Prepend a single element to the front of the list.
223 * If new_el is already an element of some list, then undefined behaviour
224 * results. Equivalent to list.addBefore(list.head, new_el).
226 void prepend(Element *new_el) { addBefore(head, new_el); }
229 * \brief Append a single element to the end of the list.
231 * If new_el is alreay an element of some list, then undefined behaviour
232 * results. Equivalent to list.addAfter(list.tail, new_el).
234 void append(Element *new_el) { addAfter(tail, new_el); }
237 * \brief Prepend an entire list to the beginning of this list.
239 * All items are moved, not copied. Afterwards, the other list is emtpy.
240 * All items are prepended at once, so this is an O(1) operation.
241 * Equivalent to list.addBefore(list.head, dl).
243 void prepend(DList &dl) { addBefore(head, dl); }
246 * \brief Append an entire list to the end of the list.
248 * All items are moved, not copied. Afterwards, the other list is empty.
249 * All items are appened at once, so this is an O(1) operation.
250 * Equivalent to list.addAfter(list.tail, dl).
252 void append(DList &dl) { addAfter(tail, dl); }
254 void addAfter(Element *prev_el, Element *new_el);
255 void addBefore(Element *next_el, Element *new_el);
257 void addAfter(Element *prev_el, DList &dl);
258 void addBefore(Element *next_el, DList &dl);
261 * \brief Detach the head of the list
263 * The element detached is not deleted. If there is no head of the list
264 * (the list is empty) then undefined behaviour results. Equivalent to
265 * list.detach(list.head).
267 * \returns The element detached.
269 Element *detachFirst() { return detach(head); }
272 * \brief Detach the tail of the list
274 * The element detached is not deleted. If there is no tail of the list
275 * (the list is empty) then undefined behaviour results. Equivalent to
276 * list.detach(list.tail).
278 * \returns The element detached.
280 Element *detachLast() { return detach(tail); }
282 /* Detaches an element from the list. Does not free any memory. */
283 Element *detach(Element *el);
286 * \brief Detach and delete the first element in the list.
288 * If there is no first element (the list is empty) then undefined
289 * behaviour results. Equivalent to delete list.detach(list.head);
291 void removeFirst() { delete detach( head ); }
294 * \brief Detach and delete the last element in the list.
296 * If there is no last element (the list is emtpy) then undefined
297 * behaviour results. Equivalent to delete list.detach(list.tail);
299 void removeLast() { delete detach( tail ); }
302 * \brief Detach and delete an element from the list.
304 * If the element is not in the list, then undefined behaviour results.
305 * Equivalent to delete list.detach(el);
307 void remove(Element *el) { delete detach( el ); }
312 /** \brief The number of elements in the list. */
313 long length() const { return listLen; }
315 /** \brief Head and tail of the linked list. */
316 Element *head, *tail;
318 /** \brief The number of element in the list. */
321 /* Convenience access. */
322 long size() const { return listLen; }
324 /* Forward this so a ref can be used. */
327 /* Class for setting the iterator. */
328 struct IterFirst { IterFirst( const DList &l ) : l(l) { } const DList &l; };
329 struct IterLast { IterLast( const DList &l ) : l(l) { } const DList &l; };
330 struct IterNext { IterNext( const Iter &i ) : i(i) { } const Iter &i; };
331 struct IterPrev { IterPrev( const Iter &i ) : i(i) { } const Iter &i; };
334 * \brief Double List Iterator.
339 /* Default construct. */
342 /* Construct from a double list. */
343 Iter( const DList &dl ) : ptr(dl.head) { }
344 Iter( Element *el ) : ptr(el) { }
345 Iter( const IterFirst &dlf ) : ptr(dlf.l.head) { }
346 Iter( const IterLast &dll ) : ptr(dll.l.tail) { }
347 Iter( const IterNext &dln ) : ptr(dln.i.ptr->BASE_EL(next)) { }
348 Iter( const IterPrev &dlp ) : ptr(dlp.i.ptr->BASE_EL(prev)) { }
350 /* Assign from a double list. */
351 Iter &operator=( const DList &dl ) { ptr = dl.head; return *this; }
352 Iter &operator=( Element *el ) { ptr = el; return *this; }
353 Iter &operator=( const IterFirst &af ) { ptr = af.l.head; return *this; }
354 Iter &operator=( const IterLast &al ) { ptr = al.l.tail; return *this; }
355 Iter &operator=( const IterNext &an ) { ptr = an.i.ptr->BASE_EL(next); return *this; }
356 Iter &operator=( const IterPrev &ap ) { ptr = ap.i.ptr->BASE_EL(prev); return *this; }
358 /** \brief Less than end? */
359 bool lte() const { return ptr != 0; }
361 /** \brief At end? */
362 bool end() const { return ptr == 0; }
364 /** \brief Greater than beginning? */
365 bool gtb() const { return ptr != 0; }
367 /** \brief At beginning? */
368 bool beg() const { return ptr == 0; }
370 /** \brief At first element? */
371 bool first() const { return ptr && ptr->BASE_EL(prev) == 0; }
373 /** \brief At last element? */
374 bool last() const { return ptr && ptr->BASE_EL(next) == 0; }
376 /** \brief Implicit cast to Element*. */
377 operator Element*() const { return ptr; }
379 /** \brief Dereference operator returns Element&. */
380 Element &operator *() const { return *ptr; }
382 /** \brief Arrow operator returns Element*. */
383 Element *operator->() const { return ptr; }
385 /** \brief Move to next item. */
386 inline Element *operator++() { return ptr = ptr->BASE_EL(next); }
388 /** \brief Move to next item. */
389 inline Element *increment() { return ptr = ptr->BASE_EL(next); }
391 /** \brief Move to next item. */
392 inline Element *operator++(int);
394 /** \brief Move to previous item. */
395 inline Element *operator--() { return ptr = ptr->BASE_EL(prev); }
397 /** \brief Move to previous item. */
398 inline Element *decrement() { return ptr = ptr->BASE_EL(prev); }
400 /** \brief Move to previous item. */
401 inline Element *operator--(int);
403 /** \brief Return the next item. Does not modify this. */
404 inline IterNext next() const { return IterNext(*this); }
406 /** \brief Return the prev item. Does not modify this. */
407 inline IterPrev prev() const { return IterPrev(*this); }
409 /** \brief The iterator is simply a pointer. */
413 /** \brief Return first element. */
414 IterFirst first() { return IterFirst(*this); }
416 /** \brief Return last element. */
417 IterLast last() { return IterLast(*this); }
420 /* Copy constructor, does a deep copy of other. */
421 template <DLMEL_TEMPDEF> DList<DLMEL_TEMPUSE>::
422 DList(const DList<DLMEL_TEMPUSE> &other) :
423 head(0), tail(0), listLen(0)
425 Element *el = other.head;
427 append( new Element(*el) );
428 el = el->BASE_EL(next);
432 #ifdef DOUBLELIST_VALUE
434 /* Assignement operator does deep copy. */
435 template <DLMEL_TEMPDEF> DList<DLMEL_TEMPUSE> &DList<DLMEL_TEMPUSE>::
436 operator=(const DList &other)
438 /* Free the old list. The value list assumes items were allocated on the
442 Element *el = other.head;
444 append( new Element(*el) );
445 el = el->BASE_EL(next);
450 template <DLMEL_TEMPDEF> void DList<DLMEL_TEMPUSE>::
451 transfer(DList &other)
453 /* Free the old list. The value list assumes items were allocated on the
459 listLen = other.listLen;
466 /* Assignement operator does deep copy. */
467 template <DLMEL_TEMPDEF> DList<DLMEL_TEMPUSE> &DList<DLMEL_TEMPUSE>::
468 operator=(const DList &other)
470 Element *el = other.head;
472 append( new Element(*el) );
473 el = el->BASE_EL(next);
478 template <DLMEL_TEMPDEF> void DList<DLMEL_TEMPUSE>::
479 transfer(DList &other)
483 listLen = other.listLen;
490 #ifdef DOUBLELIST_VALUE
492 /* Prepend a new item. Inlining this bloats the caller with new overhead. */
493 template <DLMEL_TEMPDEF> void DList<DLMEL_TEMPUSE>::
494 prepend(const T &item)
496 addBefore(head, new Element(item));
499 /* Append a new item. Inlining this bloats the caller with the new overhead. */
500 template <DLMEL_TEMPDEF> void DList<DLMEL_TEMPUSE>::
501 append(const T &item)
503 addAfter(tail, new Element(item));
506 /* Add a new item after a prev element. Inlining this bloats the caller with
507 * the new overhead. */
508 template <DLMEL_TEMPDEF> void DList<DLMEL_TEMPUSE>::
509 addAfter(Element *prev_el, const T &item)
511 addAfter(prev_el, new Element(item));
514 /* Add a new item before a next element. Inlining this bloats the caller with
515 * the new overhead. */
516 template <DLMEL_TEMPDEF> void DList<DLMEL_TEMPUSE>::
517 addBefore(Element *next_el, const T &item)
519 addBefore(next_el, new Element(item));
525 * The larger iterator operators.
529 template <DLMEL_TEMPDEF> Element *DList<DLMEL_TEMPUSE>::Iter::
533 ptr = ptr->BASE_EL(next);
538 template <DLMEL_TEMPDEF> Element *DList<DLMEL_TEMPUSE>::Iter::
542 ptr = ptr->BASE_EL(prev);
547 * \brief Insert an element immediately after an element in the list.
549 * If prev_el is NULL then new_el is prepended to the front of the list. If
550 * prev_el is not in the list or if new_el is already in a list, then
551 * undefined behaviour results.
553 template <DLMEL_TEMPDEF> void DList<DLMEL_TEMPUSE>::
554 addAfter(Element *prev_el, Element *new_el)
556 /* Set the previous pointer of new_el to prev_el. We do
557 * this regardless of the state of the list. */
558 new_el->BASE_EL(prev) = prev_el;
560 /* Set forward pointers. */
562 /* There was no prev_el, we are inserting at the head. */
563 new_el->BASE_EL(next) = head;
567 /* There was a prev_el, we can access previous next. */
568 new_el->BASE_EL(next) = prev_el->BASE_EL(next);
569 prev_el->BASE_EL(next) = new_el;
572 /* Set reverse pointers. */
573 if (new_el->BASE_EL(next) == 0) {
574 /* There is no next element. Set the tail pointer. */
578 /* There is a next element. Set it's prev pointer. */
579 new_el->BASE_EL(next)->BASE_EL(prev) = new_el;
582 /* Update list length. */
587 * \brief Insert an element immediatly before an element in the list.
589 * If next_el is NULL then new_el is appended to the end of the list. If
590 * next_el is not in the list or if new_el is already in a list, then
591 * undefined behaviour results.
593 template <DLMEL_TEMPDEF> void DList<DLMEL_TEMPUSE>::
594 addBefore(Element *next_el, Element *new_el)
596 /* Set the next pointer of the new element to next_el. We do
597 * this regardless of the state of the list. */
598 new_el->BASE_EL(next) = next_el;
600 /* Set reverse pointers. */
602 /* There is no next elememnt. We are inserting at the tail. */
603 new_el->BASE_EL(prev) = tail;
607 /* There is a next element and we can access next's previous. */
608 new_el->BASE_EL(prev) = next_el->BASE_EL(prev);
609 next_el->BASE_EL(prev) = new_el;
612 /* Set forward pointers. */
613 if (new_el->BASE_EL(prev) == 0) {
614 /* There is no previous element. Set the head pointer.*/
618 /* There is a previous element, set it's next pointer to new_el. */
619 new_el->BASE_EL(prev)->BASE_EL(next) = new_el;
622 /* Update list length. */
627 * \brief Insert an entire list immediatly after an element in this list.
629 * Elements are moved, not copied. Afterwards, the other list is empty. If
630 * prev_el is NULL then the elements are prepended to the front of the list.
631 * If prev_el is not in the list then undefined behaviour results. All
632 * elements are inserted into the list at once, so this is an O(1) operation.
634 template <DLMEL_TEMPDEF> void DList<DLMEL_TEMPUSE>::
635 addAfter( Element *prev_el, DList<DLMEL_TEMPUSE> &dl )
637 /* Do not bother if dl has no elements. */
638 if ( dl.listLen == 0 )
641 /* Set the previous pointer of dl.head to prev_el. We do
642 * this regardless of the state of the list. */
643 dl.head->BASE_EL(prev) = prev_el;
645 /* Set forward pointers. */
647 /* There was no prev_el, we are inserting at the head. */
648 dl.tail->BASE_EL(next) = head;
652 /* There was a prev_el, we can access previous next. */
653 dl.tail->BASE_EL(next) = prev_el->BASE_EL(next);
654 prev_el->BASE_EL(next) = dl.head;
657 /* Set reverse pointers. */
658 if (dl.tail->BASE_EL(next) == 0) {
659 /* There is no next element. Set the tail pointer. */
663 /* There is a next element. Set it's prev pointer. */
664 dl.tail->BASE_EL(next)->BASE_EL(prev) = dl.tail;
667 /* Update the list length. */
668 listLen += dl.listLen;
671 dl.head = dl.tail = 0;
676 * \brief Insert an entire list immediately before an element in this list.
678 * Elements are moved, not copied. Afterwards, the other list is empty. If
679 * next_el is NULL then the elements are appended to the end of the list. If
680 * next_el is not in the list then undefined behaviour results. All elements
681 * are inserted at once, so this is an O(1) operation.
683 template <DLMEL_TEMPDEF> void DList<DLMEL_TEMPUSE>::
684 addBefore( Element *next_el, DList<DLMEL_TEMPUSE> &dl )
686 /* Do not bother if dl has no elements. */
687 if ( dl.listLen == 0 )
690 /* Set the next pointer of dl.tail to next_el. We do
691 * this regardless of the state of the list. */
692 dl.tail->BASE_EL(next) = next_el;
694 /* Set reverse pointers. */
696 /* There is no next elememnt. We are inserting at the tail. */
697 dl.head->BASE_EL(prev) = tail;
701 /* There is a next element and we can access next's previous. */
702 dl.head->BASE_EL(prev) = next_el->BASE_EL(prev);
703 next_el->BASE_EL(prev) = dl.tail;
706 /* Set forward pointers. */
707 if (dl.head->BASE_EL(prev) == 0) {
708 /* There is no previous element. Set the head pointer.*/
712 /* There is a previous element, set it's next pointer to new_el. */
713 dl.head->BASE_EL(prev)->BASE_EL(next) = dl.head;
716 /* Update list length. */
717 listLen += dl.listLen;
720 dl.head = dl.tail = 0;
726 * \brief Detach an element from the list.
728 * The element is not deleted. If the element is not in the list, then
729 * undefined behaviour results.
731 * \returns The element detached.
733 template <DLMEL_TEMPDEF> Element *DList<DLMEL_TEMPUSE>::
736 /* Set forward pointers to skip over el. */
737 if (el->BASE_EL(prev) == 0)
738 head = el->BASE_EL(next);
740 el->BASE_EL(prev)->BASE_EL(next) =
744 /* Set reverse pointers to skip over el. */
745 if (el->BASE_EL(next) == 0)
746 tail = el->BASE_EL(prev);
748 el->BASE_EL(next)->BASE_EL(prev) =
752 /* Update List length and return element we detached. */
758 * \brief Clear the list by deleting all elements.
760 * Each item in the list is deleted. The list is reset to its initial state.
762 template <DLMEL_TEMPDEF> void DList<DLMEL_TEMPUSE>::empty()
764 Element *nextToGo = 0, *cur = head;
768 nextToGo = cur->BASE_EL(next);
777 * \brief Clear the list by forgetting all elements.
779 * All elements are abandoned, not deleted. The list is reset to it's initial
782 template <DLMEL_TEMPDEF> void DList<DLMEL_TEMPUSE>::abandon()
788 #ifdef AAPL_NAMESPACE