/* * Default Constructor: creates an empty list */ template NodeList::NodeList() : sz(0) { header = new Node; // create sentinels trailer = new Node; header->next = trailer; // head points to trailer trailer->prev = header; // trailer points to head } /* * returns size of list */ template int NodeList::size() const { return sz; } /* * is the list empty? */ template bool NodeList::isEmpty() const { return (sz==0); } /* * return position of first element in list */ template typename NodeList::Position NodeList::first() const throw(EmptyContainerException) { if (isEmpty()) throw EmptyContainerException("List is empty"); return Position(this,header->next); } /* * return position of last element in list */ template typename NodeList::Position NodeList::last() const throw(EmptyContainerException) { if (isEmpty()) throw EmptyContainerException("List is empty"); return Position(this,trailer->prev); } /* * is this the first position? */ template bool NodeList::isFirst(const Position& p) const throw(InvalidPositionException) { NodePtr v = p.validate(this); return v->prev == header; } /* * is this the last position? */ template bool NodeList::isLast(const Position& p) const throw(InvalidPositionException) { NodePtr v = p.validate(this); return v->next == trailer; } /* * return position before the given position */ template typename NodeList::Position NodeList::before(const Position& p) const throw(BoundaryViolationException, InvalidPositionException) { NodePtr v = p.validate(this); NodePtr prev = v->prev; if (prev == header) throw BoundaryViolationException("Cannot traverse beyond beginning of list"); return Position(this,prev); } /* * return position after the given position */ template typename NodeList::Position NodeList::after(const Position& p) const throw(BoundaryViolationException, InvalidPositionException) { NodePtr v = p.validate(this); NodePtr next = v->next; if (next == trailer) throw BoundaryViolationException("Cannot traverse beyond end of list"); return Position(this,next); } /* * replace the element at the given position */ template void NodeList::replaceElement(const NodeList::Position& p, const Object& element) throw(InvalidPositionException) { NodePtr v = p.validate(this); v->element = element; } /* * swap the elements stored at the given positions */ template void NodeList::swap(const NodeList::Position& p, const NodeList::Position& q) throw(InvalidPositionException) { NodePtr v = p.validate(this); NodePtr w = q.nodePtr(this); Object e = v->element; v->element = w->element; w->element = e; } /* * insert new element e into list as the first element */ template typename NodeList::Position NodeList::insertFirst(const Object& element) { sz++; NodePtr newNode = new Node(element, header, header->next); newNode->next->prev = newNode; // link node into list newNode->prev->next = newNode; return Position(this,newNode); } /* * insert new element e into list as the last element */ template typename NodeList::Position NodeList::insertLast(const Object& element) { sz++; NodePtr newNode = new Node(element, trailer->prev, trailer); newNode->next->prev = newNode; // link node into list newNode->prev->next = newNode; return Position(this,newNode); } /* * insert new element before the given position */ template typename NodeList::Position NodeList::insertBefore(const Position& p, const Object& element) throw(InvalidPositionException) { NodePtr v = p.validate(this); sz++; NodePtr newNode = new Node(element, v->prev, v); newNode->prev->next = newNode; // link node into list newNode->next->prev = newNode; return Position(this,newNode); } /* * insert new element after the given position */ template typename NodeList::Position NodeList::insertAfter(const Position& p, const Object& element) throw(InvalidPositionException) { NodePtr v = p.validate(this); sz++; NodePtr newNode = new Node(element, v, v->next); newNode->next->prev = newNode; // link node into list newNode->prev->next = newNode; return Position(this,newNode); } /* * remove the element at the given position */ template void NodeList::remove(const Position& p) throw(InvalidPositionException) { sz--; NodePtr v = p.validate(this); v->prev->next = v->next; // unlink from the list v->next->prev = v->prev; v->next = v->prev = NULL; delete v; } /* * Copy Constructor */ template NodeList::NodeList(const NodeList& orig) { cloneList(orig); } /* * Overloaded Assignment Operator */ template NodeList& NodeList::operator=(const NodeList& orig) { if (this != &orig) { clearList(); cloneList(orig); } return *this; } /* * Destructor */ template NodeList::~NodeList() { clearList(); } /* * clears existing list (including header/trailer) */ template void NodeList::clearList() { while (!isEmpty()) remove(first()); delete header; delete trailer; } /* * clones an existing list */ template void NodeList::cloneList(const NodeList& orig) { sz = 0; // sz will later be incremented via insertLast header = new Node; trailer = new Node; header->next = trailer; trailer->prev = header; for (NodePtr n = orig.header->next; n != orig.trailer; n = n->next) insertLast(n->element); } /******************************************************* * Position methods *******************************************************/ /** * utility to convert Position to node pointer */ template typename NodeList::NodePtr NodeList::Position::validate(const NodeList* list) const throw(InvalidPositionException) { if (node == NULL) throw InvalidPositionException("Cannot use a NULL position"); if (container != list) throw InvalidPositionException("Position does not below to this list."); if (node->prev==NULL) throw InvalidPositionException("Position appears to involve an item which has since been removed from the list."); else return node; }