/* * Copyright 2001 Adrian Thurston */ /* This file is part of Aapl. * * Aapl is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * Aapl is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for * more details. * * You should have received a copy of the GNU Lesser General Public License * along with Aapl; if not, write to the Free Software Foundation, Inc., 59 * Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* This header is not wrapped in ifndef becuase it is not intended to * be included by the user. */ #ifdef AAPL_NAMESPACE namespace Aapl { #endif #if defined( DOUBLELIST_VALUE ) /** * \brief Double list element for DListVal. * * DListValEl stores the type T of DListVal by value. */ template struct DListValEl { /** * \brief Construct a DListValEl with a given value. * * The only constructor available initializes the value element. This * enforces that DListVal elements are never created without having their * value intialzed by the user. T's copy constructor is used to copy the * value in. */ DListValEl( const T &val ) : value(val) { } /** * \brief Value stored by the list element. * * Value is always copied into new list elements using the copy * constructor. */ T value; /** * \brief List previous pointer. * * Points to the previous item in the list. If this is the first item in * the list, then prev is NULL. If this element is not in a list then * prev is undefined. */ DListValEl *prev; /** * \brief List next pointer. * * Points to the next item in the list. If this is the list item in the * list, then next is NULL. If this element is not in a list then next is * undefined. */ DListValEl *next; }; #else #ifndef __AAPL_DOUBLE_LIST_EL #define __AAPL_DOUBLE_LIST_EL /** * \brief Double list element properties. * * This class can be inherited to make a class suitable to be a double list * element. It simply provides the next and previous pointers. An alternative * is to put the next and previous pointers in the class directly. */ template struct DListEl { /** * \brief List previous pointer. * * Points to the previous item in the list. If this is the first item in * the list, then prev is NULL. If this element is not in a list then * prev is undefined. */ Element *prev; /** * \brief List next pointer. * * Points to the next item in the list. If this is the list item in the * list, then next is NULL. If this element is not in a list then next is * undefined. */ Element *next; }; #endif /* __AAPL_DOUBLE_LIST_EL */ #endif /* Doubly Linked List */ template class DList { public: /** \brief Initialize an empty list. */ DList() : head(0), tail(0), listLen(0) {} /** * \brief Perform a deep copy of the list. * * The elements of the other list are duplicated and put into this list. * Elements are copied using the copy constructor. */ DList(const DList &other); #ifdef DOUBLELIST_VALUE /** * \brief Clear the double list contents. * * All elements are deleted. */ ~DList() { empty(); } /** * \brief Assign another list into this list using a deep copy. * * The elements of the other list are duplicated and put into this list. * Each list item is created using the copy constructor. If this list * contains any elements before the copy, they are deleted first. * * \returns A reference to this. */ DList &operator=(const DList &other); /** * \brief Transfer the contents of another list into this list. * * The elements of the other list moved in. The other list will be empty * afterwards. If this list contains any elements before the copy, then * they are deleted. */ void transfer(DList &other); #else /** * \brief Abandon all elements in the list. * * List elements are not deleted. */ ~DList() {} /** * \brief Perform a deep copy of the list. * * The elements of the other list are duplicated and put into this list. * Each list item is created using the copy constructor. If this list * contains any elements before the copy, they are abandoned. * * \returns A reference to this. */ DList &operator=(const DList &other); /** * \brief Transfer the contents of another list into this list. * * The elements of the other list moved in. The other list will be empty * afterwards. If this list contains any elements before the copy, they * are abandoned. */ void transfer(DList &other); #endif #ifdef DOUBLELIST_VALUE /** * \brief Make a new element and prepend it to the front of the list. * * The item is copied into the new element using the copy constructor. * Equivalent to list.addBefore(list.head, item). */ void prepend(const T &item); /** * \brief Make a new element and append it to the end of the list. * * The item is copied into the new element using the copy constructor. * Equivalent to list.addAfter(list.tail, item). */ void append(const T &item); /** * \brief Make a new element and insert it immediately after an element in * the list. * * The item is copied into the new element using the copy constructor. If * prev_el is NULL then the new element is prepended to the front of the * list. If prev_el is not already in the list then undefined behaviour * results. Equivalent to list.addAfter(prev_el, new DListValEl(item)). */ void addAfter(Element *prev_el, const T &item); /** * \brief Make a new element and insert it immediately before an element * in the list. * * The item is copied into the new element using the copy construcotor. If * next_el is NULL then the new element is appended to the end of the * list. If next_el is not already in the list then undefined behaviour * results. Equivalent to list.addBefore(next_el, new DListValEl(item)). */ void addBefore(Element *next_el, const T &item); #endif /** * \brief Prepend a single element to the front of the list. * * If new_el is already an element of some list, then undefined behaviour * results. Equivalent to list.addBefore(list.head, new_el). */ void prepend(Element *new_el) { addBefore(head, new_el); } /** * \brief Append a single element to the end of the list. * * If new_el is alreay an element of some list, then undefined behaviour * results. Equivalent to list.addAfter(list.tail, new_el). */ void append(Element *new_el) { addAfter(tail, new_el); } /** * \brief Prepend an entire list to the beginning of this list. * * All items are moved, not copied. Afterwards, the other list is emtpy. * All items are prepended at once, so this is an O(1) operation. * Equivalent to list.addBefore(list.head, dl). */ void prepend(DList &dl) { addBefore(head, dl); } /** * \brief Append an entire list to the end of the list. * * All items are moved, not copied. Afterwards, the other list is empty. * All items are appened at once, so this is an O(1) operation. * Equivalent to list.addAfter(list.tail, dl). */ void append(DList &dl) { addAfter(tail, dl); } void addAfter(Element *prev_el, Element *new_el); void addBefore(Element *next_el, Element *new_el); void addAfter(Element *prev_el, DList &dl); void addBefore(Element *next_el, DList &dl); /** * \brief Detach the head of the list * * The element detached is not deleted. If there is no head of the list * (the list is empty) then undefined behaviour results. Equivalent to * list.detach(list.head). * * \returns The element detached. */ Element *detachFirst() { return detach(head); } /** * \brief Detach the tail of the list * * The element detached is not deleted. If there is no tail of the list * (the list is empty) then undefined behaviour results. Equivalent to * list.detach(list.tail). * * \returns The element detached. */ Element *detachLast() { return detach(tail); } /* Detaches an element from the list. Does not free any memory. */ Element *detach(Element *el); /** * \brief Detach and delete the first element in the list. * * If there is no first element (the list is empty) then undefined * behaviour results. Equivalent to delete list.detach(list.head); */ void removeFirst() { delete detach( head ); } /** * \brief Detach and delete the last element in the list. * * If there is no last element (the list is emtpy) then undefined * behaviour results. Equivalent to delete list.detach(list.tail); */ void removeLast() { delete detach( tail ); } /** * \brief Detach and delete an element from the list. * * If the element is not in the list, then undefined behaviour results. * Equivalent to delete list.detach(el); */ void remove(Element *el) { delete detach( el ); } void empty(); void abandon(); /** \brief The number of elements in the list. */ long length() const { return listLen; } /** \brief Head and tail of the linked list. */ Element *head, *tail; /** \brief The number of element in the list. */ long listLen; /* Convenience access. */ long size() const { return listLen; } /* Forward this so a ref can be used. */ struct Iter; /* Class for setting the iterator. */ struct IterFirst { IterFirst( const DList &l ) : l(l) { } const DList &l; }; struct IterLast { IterLast( const DList &l ) : l(l) { } const DList &l; }; struct IterNext { IterNext( const Iter &i ) : i(i) { } const Iter &i; }; struct IterPrev { IterPrev( const Iter &i ) : i(i) { } const Iter &i; }; /** * \brief Double List Iterator. * \ingroup iterators */ struct Iter { /* Default construct. */ Iter() : ptr(0) { } /* Construct from a double list. */ Iter( const DList &dl ) : ptr(dl.head) { } Iter( Element *el ) : ptr(el) { } Iter( const IterFirst &dlf ) : ptr(dlf.l.head) { } Iter( const IterLast &dll ) : ptr(dll.l.tail) { } Iter( const IterNext &dln ) : ptr(dln.i.ptr->BASE_EL(next)) { } Iter( const IterPrev &dlp ) : ptr(dlp.i.ptr->BASE_EL(prev)) { } /* Assign from a double list. */ Iter &operator=( const DList &dl ) { ptr = dl.head; return *this; } Iter &operator=( Element *el ) { ptr = el; return *this; } Iter &operator=( const IterFirst &af ) { ptr = af.l.head; return *this; } Iter &operator=( const IterLast &al ) { ptr = al.l.tail; return *this; } Iter &operator=( const IterNext &an ) { ptr = an.i.ptr->BASE_EL(next); return *this; } Iter &operator=( const IterPrev &ap ) { ptr = ap.i.ptr->BASE_EL(prev); return *this; } /** \brief Less than end? */ bool lte() const { return ptr != 0; } /** \brief At end? */ bool end() const { return ptr == 0; } /** \brief Greater than beginning? */ bool gtb() const { return ptr != 0; } /** \brief At beginning? */ bool beg() const { return ptr == 0; } /** \brief At first element? */ bool first() const { return ptr && ptr->BASE_EL(prev) == 0; } /** \brief At last element? */ bool last() const { return ptr && ptr->BASE_EL(next) == 0; } /** \brief Implicit cast to Element*. */ operator Element*() const { return ptr; } /** \brief Dereference operator returns Element&. */ Element &operator *() const { return *ptr; } /** \brief Arrow operator returns Element*. */ Element *operator->() const { return ptr; } /** \brief Move to next item. */ inline Element *operator++() { return ptr = ptr->BASE_EL(next); } /** \brief Move to next item. */ inline Element *increment() { return ptr = ptr->BASE_EL(next); } /** \brief Move to next item. */ inline Element *operator++(int); /** \brief Move to previous item. */ inline Element *operator--() { return ptr = ptr->BASE_EL(prev); } /** \brief Move to previous item. */ inline Element *decrement() { return ptr = ptr->BASE_EL(prev); } /** \brief Move to previous item. */ inline Element *operator--(int); /** \brief Return the next item. Does not modify this. */ inline IterNext next() const { return IterNext(*this); } /** \brief Return the prev item. Does not modify this. */ inline IterPrev prev() const { return IterPrev(*this); } /** \brief The iterator is simply a pointer. */ Element *ptr; }; /** \brief Return first element. */ IterFirst first() { return IterFirst(*this); } /** \brief Return last element. */ IterLast last() { return IterLast(*this); } }; /* Copy constructor, does a deep copy of other. */ template DList:: DList(const DList &other) : head(0), tail(0), listLen(0) { Element *el = other.head; while( el != 0 ) { append( new Element(*el) ); el = el->BASE_EL(next); } } #ifdef DOUBLELIST_VALUE /* Assignement operator does deep copy. */ template DList &DList:: operator=(const DList &other) { /* Free the old list. The value list assumes items were allocated on the * heap by itself. */ empty(); Element *el = other.head; while( el != 0 ) { append( new Element(*el) ); el = el->BASE_EL(next); } return *this; } template void DList:: transfer(DList &other) { /* Free the old list. The value list assumes items were allocated on the * heap by itself. */ empty(); head = other.head; tail = other.tail; listLen = other.listLen; other.abandon(); } #else /* Assignement operator does deep copy. */ template DList &DList:: operator=(const DList &other) { Element *el = other.head; while( el != 0 ) { append( new Element(*el) ); el = el->BASE_EL(next); } return *this; } template void DList:: transfer(DList &other) { head = other.head; tail = other.tail; listLen = other.listLen; other.abandon(); } #endif #ifdef DOUBLELIST_VALUE /* Prepend a new item. Inlining this bloats the caller with new overhead. */ template void DList:: prepend(const T &item) { addBefore(head, new Element(item)); } /* Append a new item. Inlining this bloats the caller with the new overhead. */ template void DList:: append(const T &item) { addAfter(tail, new Element(item)); } /* Add a new item after a prev element. Inlining this bloats the caller with * the new overhead. */ template void DList:: addAfter(Element *prev_el, const T &item) { addAfter(prev_el, new Element(item)); } /* Add a new item before a next element. Inlining this bloats the caller with * the new overhead. */ template void DList:: addBefore(Element *next_el, const T &item) { addBefore(next_el, new Element(item)); } #endif /* * The larger iterator operators. */ /* Postfix ++ */ template Element *DList::Iter:: operator++(int) { Element *rtn = ptr; ptr = ptr->BASE_EL(next); return rtn; } /* Postfix -- */ template Element *DList::Iter:: operator--(int) { Element *rtn = ptr; ptr = ptr->BASE_EL(prev); return rtn; } /** * \brief Insert an element immediately after an element in the list. * * If prev_el is NULL then new_el is prepended to the front of the list. If * prev_el is not in the list or if new_el is already in a list, then * undefined behaviour results. */ template void DList:: addAfter(Element *prev_el, Element *new_el) { /* Set the previous pointer of new_el to prev_el. We do * this regardless of the state of the list. */ new_el->BASE_EL(prev) = prev_el; /* Set forward pointers. */ if (prev_el == 0) { /* There was no prev_el, we are inserting at the head. */ new_el->BASE_EL(next) = head; head = new_el; } else { /* There was a prev_el, we can access previous next. */ new_el->BASE_EL(next) = prev_el->BASE_EL(next); prev_el->BASE_EL(next) = new_el; } /* Set reverse pointers. */ if (new_el->BASE_EL(next) == 0) { /* There is no next element. Set the tail pointer. */ tail = new_el; } else { /* There is a next element. Set it's prev pointer. */ new_el->BASE_EL(next)->BASE_EL(prev) = new_el; } /* Update list length. */ listLen++; } /** * \brief Insert an element immediatly before an element in the list. * * If next_el is NULL then new_el is appended to the end of the list. If * next_el is not in the list or if new_el is already in a list, then * undefined behaviour results. */ template void DList:: addBefore(Element *next_el, Element *new_el) { /* Set the next pointer of the new element to next_el. We do * this regardless of the state of the list. */ new_el->BASE_EL(next) = next_el; /* Set reverse pointers. */ if (next_el == 0) { /* There is no next elememnt. We are inserting at the tail. */ new_el->BASE_EL(prev) = tail; tail = new_el; } else { /* There is a next element and we can access next's previous. */ new_el->BASE_EL(prev) = next_el->BASE_EL(prev); next_el->BASE_EL(prev) = new_el; } /* Set forward pointers. */ if (new_el->BASE_EL(prev) == 0) { /* There is no previous element. Set the head pointer.*/ head = new_el; } else { /* There is a previous element, set it's next pointer to new_el. */ new_el->BASE_EL(prev)->BASE_EL(next) = new_el; } /* Update list length. */ listLen++; } /** * \brief Insert an entire list immediatly after an element in this list. * * Elements are moved, not copied. Afterwards, the other list is empty. If * prev_el is NULL then the elements are prepended to the front of the list. * If prev_el is not in the list then undefined behaviour results. All * elements are inserted into the list at once, so this is an O(1) operation. */ template void DList:: addAfter( Element *prev_el, DList &dl ) { /* Do not bother if dl has no elements. */ if ( dl.listLen == 0 ) return; /* Set the previous pointer of dl.head to prev_el. We do * this regardless of the state of the list. */ dl.head->BASE_EL(prev) = prev_el; /* Set forward pointers. */ if (prev_el == 0) { /* There was no prev_el, we are inserting at the head. */ dl.tail->BASE_EL(next) = head; head = dl.head; } else { /* There was a prev_el, we can access previous next. */ dl.tail->BASE_EL(next) = prev_el->BASE_EL(next); prev_el->BASE_EL(next) = dl.head; } /* Set reverse pointers. */ if (dl.tail->BASE_EL(next) == 0) { /* There is no next element. Set the tail pointer. */ tail = dl.tail; } else { /* There is a next element. Set it's prev pointer. */ dl.tail->BASE_EL(next)->BASE_EL(prev) = dl.tail; } /* Update the list length. */ listLen += dl.listLen; /* Empty out dl. */ dl.head = dl.tail = 0; dl.listLen = 0; } /** * \brief Insert an entire list immediately before an element in this list. * * Elements are moved, not copied. Afterwards, the other list is empty. If * next_el is NULL then the elements are appended to the end of the list. If * next_el is not in the list then undefined behaviour results. All elements * are inserted at once, so this is an O(1) operation. */ template void DList:: addBefore( Element *next_el, DList &dl ) { /* Do not bother if dl has no elements. */ if ( dl.listLen == 0 ) return; /* Set the next pointer of dl.tail to next_el. We do * this regardless of the state of the list. */ dl.tail->BASE_EL(next) = next_el; /* Set reverse pointers. */ if (next_el == 0) { /* There is no next elememnt. We are inserting at the tail. */ dl.head->BASE_EL(prev) = tail; tail = dl.tail; } else { /* There is a next element and we can access next's previous. */ dl.head->BASE_EL(prev) = next_el->BASE_EL(prev); next_el->BASE_EL(prev) = dl.tail; } /* Set forward pointers. */ if (dl.head->BASE_EL(prev) == 0) { /* There is no previous element. Set the head pointer.*/ head = dl.head; } else { /* There is a previous element, set it's next pointer to new_el. */ dl.head->BASE_EL(prev)->BASE_EL(next) = dl.head; } /* Update list length. */ listLen += dl.listLen; /* Empty out dl. */ dl.head = dl.tail = 0; dl.listLen = 0; } /** * \brief Detach an element from the list. * * The element is not deleted. If the element is not in the list, then * undefined behaviour results. * * \returns The element detached. */ template Element *DList:: detach(Element *el) { /* Set forward pointers to skip over el. */ if (el->BASE_EL(prev) == 0) head = el->BASE_EL(next); else { el->BASE_EL(prev)->BASE_EL(next) = el->BASE_EL(next); } /* Set reverse pointers to skip over el. */ if (el->BASE_EL(next) == 0) tail = el->BASE_EL(prev); else { el->BASE_EL(next)->BASE_EL(prev) = el->BASE_EL(prev); } /* Update List length and return element we detached. */ listLen--; return el; } /** * \brief Clear the list by deleting all elements. * * Each item in the list is deleted. The list is reset to its initial state. */ template void DList::empty() { Element *nextToGo = 0, *cur = head; while (cur != 0) { nextToGo = cur->BASE_EL(next); delete cur; cur = nextToGo; } head = tail = 0; listLen = 0; } /** * \brief Clear the list by forgetting all elements. * * All elements are abandoned, not deleted. The list is reset to it's initial * state. */ template void DList::abandon() { head = tail = 0; listLen = 0; } #ifdef AAPL_NAMESPACE } #endif