// A module of KPlib v1.4.2. // Written by Keith Pomakis during the summer of 1994. // Released to the public domain on October 10, 1994. // This version released on March 30, 1999. #ifndef KP_LIST_DEFINED #define KP_LIST_DEFINED #include #include #include "KPbasic.h" // To insure that KPList isn't defined before KPString, so that // KPList will be considered a complete type in the KPString.h // header file. This is probably a g++-specific problem. #include "KPString.h" template class KPReadOnlyIterator; template class KPIterator; // Assumes Element has a default constructor and operator=(). template class KPList { friend class KPReadOnlyIterator; friend class KPIterator; public: KPList(); KPList(const KPList &list); KPList(const Element &element); virtual ~KPList(); KPList operator+(const KPList &list) const; KPList operator+(const Element &element) const; void operator+=(const KPList &list); void operator+=(const Element &element); KPList &operator=(const KPList &list); KPList &operator=(const Element &element); Element &head(); Element &tail(); const Element &head() const; const Element &tail() const; void add_to_head(const Element &element); void add_to_tail(const Element &element); void remove_head(); void remove_tail(); Element &operator[](int index); const Element &operator[](int index) const; int size() const; bool is_empty() const; void clear(); KPList all_such_that(bool (*f)(const Element &)) const; protected: struct Node { Element element; Node *previous; Node *next; }; static void error(const char *msg); int my_size; unsigned int my_iterator_count; Node *my_head; Node *my_tail; }; // Assumes Element has the above plus operator==(). template class KPComparableList: public KPList { public: KPComparableList(); KPComparableList(const KPComparableList &list); KPComparableList(const KPList &list); KPComparableList(const Element &element); virtual ~KPComparableList(); KPComparableList &operator=(const KPList &list); KPComparableList &operator=(const Element &element); KPComparableList operator+(const KPList &list) const; KPComparableList operator+(const Element &element) const; KPComparableList operator-(const KPComparableList &list) const; KPComparableList operator-(const Element &element) const; void operator-=(const KPComparableList &list); void operator-=(const Element &element); bool operator==(const KPComparableList &list) const; bool operator!=(const KPComparableList &list) const; bool contains(const KPComparableList &list) const; bool contains(const Element &element) const; int occurrences_of(const Element &element) const; void clear(); void clear(const Element &element); void clear(const KPComparableList &list); protected: static void error(const char *msg); }; // Assumes Element has the above plus operator<(). Note that this operator // must place a total ordering on the set of Elements. template class KPSortableList: public KPComparableList { public: KPSortableList(); KPSortableList(const KPSortableList &list); KPSortableList(const KPList &list); KPSortableList(const Element &element); virtual ~KPSortableList(); KPSortableList &operator=(const KPList &list); KPSortableList &operator=(const Element &element); bool operator<(const KPSortableList &list) const; void sort(); Element &min(); const Element &min() const; Element &max(); const Element &max() const; protected: static void error(const char *msg); static int findpivot(int i, int j, Element **elementlist); static int partition(int l, int r, const Element &pivot, Element **elementlist); static void quicksort(int i, int j, Element **elementlist); }; // A list keeps track of the number of iterators iterating over it. Rules: // // - If a list has no iterators, one can add to and remove from that // list without restriction. // // - If a list has one iterator, one can add to and remove elements from // the list through the iterator without restriction, although one // cannot remove elements from the list directly. // // - If a list has more than one iterator, one cannot remove elements // from the list at all. // // As a result, if a list goes out of scope while there is still an // iterator attached to it, this is an error. Usually the declaration of // an iterator appears after the declaration of the list it is to iterate // over (or it is in a more local scope), so this is usually not a problem // (since it's destructor is called first, detaching it implicitly). To // detach an iterator from a list explicitly, call iterate_over(). // Use KPReadOnlyIterator if you wish to iterate over a const KPList or if you // do not intend to modify the list through the iterator. template class KPReadOnlyIterator { public: KPReadOnlyIterator(); KPReadOnlyIterator(const KPList &list); KPReadOnlyIterator(const KPReadOnlyIterator &iterator); ~KPReadOnlyIterator(); KPReadOnlyIterator &iterate_over(const KPList &list); KPReadOnlyIterator &iterate_over(); KPReadOnlyIterator & operator=(const KPReadOnlyIterator &iterator); const Element ¤t() const; const Element *ptr() const; KPReadOnlyIterator &beginning(); KPReadOnlyIterator &end(); KPReadOnlyIterator &operator++(); // Prefix KPReadOnlyIterator &operator--(); // Prefix void operator++(int); // Postfix void operator--(int); // Postfix const Element &operator*() const; const Element *operator->() const; bool at_beginning() const; bool at_end() const; int size() const; bool is_empty() const; const KPList &list() const; protected: static void error(const char *msg); const KPList *my_list; const KPList::Node *my_current; }; // The rules defining what happens when odd combinations of element // removals and insertions are performed are fairly intuitive. An element // can be deleted while the list is being parsed, and the parse can // continue. "Previous" and "next" retain their meanings. Just don't try // to access an element after it has been deleted! template class KPIterator { public: KPIterator(); KPIterator(KPList &list); KPIterator(const KPIterator &iterator); ~KPIterator(); KPIterator &iterate_over(KPList &list); KPIterator &iterate_over(); KPIterator &operator=(const KPIterator &iterator); KPIterator &insert_before_current(const Element &element); KPIterator &insert_after_current(const Element &element); KPIterator &replace_current_with(const Element &element); Element ¤t(); Element *ptr(); void remove_current(); KPIterator &beginning(); KPIterator &end(); KPIterator &operator++(); // Prefix KPIterator &operator--(); // Prefix void operator++(int); // Postfix void operator--(int); // Postfix Element &operator*(); Element *operator->(); bool at_beginning() const; bool at_end() const; int size() const; bool is_empty() const; KPList &list(); protected: static void error(const char *msg); KPList *my_list; KPList::Node my_deleted; KPList::Node *my_current; }; // The following macro is defined as a convenience. Here is an example of // its usage: // // KPSortableList intlist; // intlist += 42; // intlist += 11; // intlist += 76; // intlist += 9; // intlist.sort(); // // KPReadOnlyIterator iter(intlist); // FOREACH(iter) cout << *iter << '\n'; #define FOREACH(iter) for (iter.beginning(); iter.ptr(); iter++) /****************************************************************************/ template inline KPList::KPList() { my_size = my_iterator_count = 0; my_head = my_tail = NULL; } /****************************************************************************/ template inline KPList::KPList(const KPList &list) { my_size = my_iterator_count = 0; my_head = my_tail = NULL; *this = list; } /****************************************************************************/ template inline KPList::KPList(const Element &element) { my_size = my_iterator_count = 0; my_head = my_tail = NULL; *this = element; } /****************************************************************************/ template inline KPList::~KPList() { if (my_iterator_count > 0) error("~KPList() - cannot destroy, iterators present"); clear(); } /****************************************************************************/ template inline KPList KPList::operator+(const KPList &list) const { KPList new_list(*this); new_list += list; return new_list; } /****************************************************************************/ template inline KPList KPList::operator+(const Element &element) const { KPList new_list(*this); new_list += element; return new_list; } /****************************************************************************/ template void KPList::operator+=(const KPList &list) { register const Node *node; const int size = list.my_size; int i; // Must use size as stopping condition in case *this == list. for (node = list.my_head, i=0; i < size; node = node->next, i++) *this += node->element; } /****************************************************************************/ template void KPList::operator+=(const Element &element) { Node *newnode = new Node; check_mem(newnode); newnode->next = NULL; newnode->element = element; if (my_size++ == 0) { my_head = newnode; newnode->previous = NULL; } else { my_tail->next = newnode; newnode->previous = my_tail; } my_tail = newnode; } /****************************************************************************/ template KPList & KPList::operator=(const KPList &list) { if (this == &list) return *this; if (my_iterator_count > 0) error("operator=() - cannot reassign, iterators present"); register Node *node; Node *newnode, *prevnode; clear(); if (!(node = list.my_head)) return *this; newnode = new Node; check_mem(newnode); newnode->previous = NULL; newnode->element = node->element; my_head = prevnode = newnode; for (node = node->next; node; node = node->next) { newnode = new Node; check_mem(newnode); newnode->element = node->element; prevnode->next = newnode; newnode->previous = prevnode; prevnode = newnode; } newnode->next = NULL; my_tail = newnode; my_size = list.my_size; return *this; } /****************************************************************************/ template KPList & KPList::operator=(const Element &element) { if (my_iterator_count > 0) error("operator=() - cannot reassign, iterators present"); clear(); Node *newnode = new Node; check_mem(newnode); newnode->element = element; newnode->previous = newnode->next = NULL; my_head = my_tail = newnode; my_size = 1; return *this; } /****************************************************************************/ template inline Element & KPList::head() { if (!my_head) error("head() - list is empty"); return my_head->element; } /****************************************************************************/ template inline Element & KPList::tail() { if (!my_tail) error("tail() - list is empty"); return my_tail->element; } /****************************************************************************/ template inline const Element & KPList::head() const { if (!my_head) error("head() - list is empty"); return my_head->element; } /****************************************************************************/ template inline const Element & KPList::tail() const { if (!my_tail) error("tail() - list is empty"); return my_tail->element; } /****************************************************************************/ template void KPList::add_to_head(const Element &element) { Node *newnode = new Node; check_mem(newnode); newnode->element = element; newnode->previous = NULL; newnode->next = my_head; if (my_size++) my_head->previous = newnode; else my_tail = newnode; my_head = newnode; } /****************************************************************************/ template void KPList::add_to_tail(const Element &element) { Node *newnode = new Node; check_mem(newnode); newnode->element = element; newnode->previous = my_tail; newnode->next = NULL; if (my_size++) my_tail->next = newnode; else my_head = newnode; my_tail = newnode; } /****************************************************************************/ template void KPList::remove_head() { if (my_iterator_count > 0) error("remove_head() - cannot remove element, iterators present"); Node *old_head = my_head; if (old_head) { if (old_head->next) { old_head->next->previous = NULL; my_head = old_head->next; } else my_head = my_tail = NULL; delete old_head; my_size--; } } /****************************************************************************/ template void KPList::remove_tail() { if (my_iterator_count > 0) error("remove_tail() - cannot remove element, iterators present"); Node *old_tail = my_tail; if (old_tail) { if (old_tail->previous) { old_tail->previous->next = NULL; my_tail = old_tail->previous; } else my_head = my_tail = NULL; delete old_tail; my_size--; } } /****************************************************************************/ template Element & KPList::operator[](int index) { if (index < 0 || index >= my_size) error("operator[] - invalid index"); register Node *node = my_head; for (register int i=0; inext; return node->element; } /****************************************************************************/ template const Element & KPList::operator[](int index) const { if (index < 0 || index >= my_size) error("operator[] - invalid index"); register Node *node = my_head; for (register int i=0; inext; return node->element; } /****************************************************************************/ template inline int KPList::size() const { return my_size; } /****************************************************************************/ template inline bool KPList::is_empty() const { return (my_size == 0); } /****************************************************************************/ template void KPList::clear() { register Node *nextnode; if (my_iterator_count > 0) error("clear() - cannot clear, iterators present"); for (register Node *node = my_head; node; node = nextnode) { nextnode = node->next; delete node; } my_size = 0; my_head = my_tail = NULL; } /****************************************************************************/ template KPList KPList::all_such_that(bool (*f)(const Element &)) const { KPList new_list; for (register const Node *node = my_head; node; node = node->next) if (f(node->element)) new_list += node->element; return new_list; } /****************************************************************************/ template void KPList::error(const char *msg) { cerr << "KPList: " << msg << '\n'; exit(EXIT_FAILURE); } /****************************************************************************/ template inline KPComparableList::KPComparableList(): KPList() { /* do nothing new. */ } /****************************************************************************/ template inline KPComparableList::KPComparableList( const KPComparableList &list): KPList(list) { /* do nothing new. */ } /****************************************************************************/ template inline KPComparableList::KPComparableList(const KPList &list): KPList(list) { /* do nothing new. */ } /****************************************************************************/ template inline KPComparableList::KPComparableList(const Element &element): KPList(element) { /* do nothing new. */ } /****************************************************************************/ template inline KPComparableList::~KPComparableList() { /* do nothing new. */ } /****************************************************************************/ template inline KPComparableList & KPComparableList::operator=(const KPList &list) { KPList::operator=(list); return *this; } /****************************************************************************/ template inline KPComparableList & KPComparableList::operator=(const Element &element) { KPList::operator=(element); return *this; } /****************************************************************************/ template inline KPComparableList KPComparableList::operator+(const KPList &list) const { KPComparableList new_list(*this); new_list += list; return new_list; } /****************************************************************************/ template inline KPComparableList KPComparableList::operator+(const Element &element) const { KPComparableList new_list(*this); new_list += element; return new_list; } /****************************************************************************/ template inline KPComparableList KPComparableList::operator-(const KPComparableList &list) const { KPComparableList new_list(*this); new_list -= list; return new_list; } /****************************************************************************/ template inline KPComparableList KPComparableList::operator-(const Element &element) const { KPComparableList new_list(*this); new_list -= element; return new_list; } /****************************************************************************/ template void KPComparableList::operator-=(const KPComparableList &list) { for (register const Node *node = list.my_head; node; node = node->next) *this -= node->element; } /****************************************************************************/ template void KPComparableList::operator-=(const Element &element) { if (my_iterator_count > 0) error("operator-=() - cannot remove elements, iterators present"); for (register Node *node = my_tail; node; node = node->previous) if (node->element == element) { if (node->previous) node->previous->next = node->next; else my_head = node->next; if (node->next) node->next->previous = node->previous; else my_tail = node->previous; delete node; my_size--; break; } } /****************************************************************************/ template bool KPComparableList::operator==(const KPComparableList &list) const { if (this == &list) return true; if (my_size != list.my_size) return false; register const Node *node1, *node2; for (node1 = my_head, node2 = list.my_head; node1; node1 = node1->next, node2 = node2->next) if (!(node1->element == node2->element)) return false; return true; } /****************************************************************************/ template inline bool KPComparableList::operator!=(const KPComparableList &list) const { return !(*this == list); } /****************************************************************************/ template bool KPComparableList::contains(const KPComparableList &list) const { for (register const Node *node = list.my_head; node; node = node->next) if (!contains(node->element)) return false; return true; } /****************************************************************************/ template bool KPComparableList::contains(const Element &element) const { for (register const Node *node = my_head; node; node = node->next) if (node->element == element) return true; return false; } /****************************************************************************/ template int KPComparableList::occurrences_of(const Element &element) const { int occurrences = 0; for (register const Node *node = my_head; node; node = node->next) if (node->element == element) occurrences++; return occurrences; } /****************************************************************************/ // I don't know why I have to redeclare clear() here. I think it's another // one of those infamous g++ bugs. template void KPComparableList::clear() { KPList::clear(); } /****************************************************************************/ template void KPComparableList::clear(const Element &element) { register Node *prevnode; if (my_iterator_count > 0) error("clear() - cannot remove elements, iterators present"); for (register Node *node = my_tail; node; node = prevnode) { prevnode = node->previous; if (node->element == element) { if (node->previous) node->previous->next = node->next; else my_head = node->next; if (node->next) node->next->previous = node->previous; else my_tail = node->previous; delete node; my_size--; } } } /****************************************************************************/ template void KPComparableList::clear(const KPComparableList &list) { if (my_iterator_count > 0) error("clear() - cannot remove elements, iterators present"); for (register Node *node = list.my_head; node; node = node->next) clear(node->element); } /****************************************************************************/ template void KPComparableList::error(const char *msg) { cerr << "KPComparableList: " << msg << '\n'; exit(EXIT_FAILURE); } /****************************************************************************/ template inline KPSortableList::KPSortableList(): KPComparableList() { /* do nothing new. */ } /****************************************************************************/ template inline KPSortableList::KPSortableList(const KPSortableList &list): KPComparableList(list) { /* do nothing new. */ } /****************************************************************************/ template inline KPSortableList::KPSortableList(const KPList &list): KPComparableList(list) { /* do nothing new. */ } /****************************************************************************/ template inline KPSortableList::KPSortableList(const Element &element): KPComparableList(element) { /* do nothing new. */ } /****************************************************************************/ template inline KPSortableList::~KPSortableList() { /* do nothing new. */ } /****************************************************************************/ template inline KPSortableList & KPSortableList::operator=(const KPList &list) { KPComparableList::operator=(list); return *this; } /****************************************************************************/ template inline KPSortableList & KPSortableList::operator=(const Element &element) { KPComparableList::operator=(element); return *this; } /****************************************************************************/ template bool KPSortableList::operator<(const KPSortableList &list) const { if (my_size < list.my_size) return true; if (my_size > list.my_size || this == &list) return false; register const Node *node1, *node2; for (node1 = my_head, node2 = list.my_head; node1; node1 = node1->next, node2 = node2->next) if (node1->element < node2->element) return true; else if (node2->element < node1->element) return false; return false; } /****************************************************************************/ template int KPSortableList::findpivot(int i, int j, Element **elementlist) { register const Element *first = elementlist[i]; for (register int k=i+1; k<=j; k++) { if (*first < *elementlist[k]) return k; else if (*elementlist[k] < *first) return i; } return -1; } template int KPSortableList::partition(int l, int r, const Element &pivot, Element **elementlist) { do { swap(*elementlist[l], *elementlist[r]); while (*elementlist[l] < pivot) l++; while (!(*elementlist[r] < pivot)) r--; } while (l <= r); return l; } template void KPSortableList::quicksort(int i, int j, Element **elementlist) { Element pivot; int k, index; index = findpivot(i, j, elementlist); if (index != -1) { pivot = *elementlist[index]; k = partition(i, j, pivot, elementlist); quicksort(i, k-1, elementlist); quicksort(k, j, elementlist); } } template void KPSortableList::sort() { if (my_size < 2) return; register int i; register Node *node; register Element **elementlist = new Element *[my_size]; for (node = my_head, i=0; node; node = node->next, i++) elementlist[i] = &node->element; quicksort(0, my_size-1, elementlist); delete [] elementlist; } /****************************************************************************/ template Element & KPSortableList::min() { if (my_size < 1) error("min() - empty list"); register Element *min = &my_head->element; for (register Node *node = my_head->next; node; node = node->next) if (node->element < *min) min = &node->element; return *min; } /****************************************************************************/ template const Element & KPSortableList::min() const { if (my_size < 1) error("min() - empty list"); register const Element *min = &my_head->element; for (register const Node *node = my_head->next; node; node = node->next) if (node->element < *min) min = &node->element; return *min; } /****************************************************************************/ template Element & KPSortableList::max() { if (my_size < 1) error("max() - empty list"); register Element *max = &my_head->element; for (register Node *node = my_head->next; node; node = node->next) if (*max < node->element) max = &node->element; return *max; } /****************************************************************************/ template const Element & KPSortableList::max() const { if (my_size < 1) error("max() - empty list"); register const Element *max = &my_head->element; for (register const Node *node = my_head->next; node; node = node->next) if (*max < node->element) max = &node->element; return *max; } /****************************************************************************/ template void KPSortableList::error(const char *msg) { cerr << "KPSortableList: " << msg << '\n'; exit(EXIT_FAILURE); } /****************************************************************************/ template inline KPReadOnlyIterator::KPReadOnlyIterator() { my_list = NULL; my_current = NULL; } /****************************************************************************/ template inline KPReadOnlyIterator::KPReadOnlyIterator(const KPList &list) { my_list = &list; // Even though list is a const, update its iterator count. ((KPList &)list).my_iterator_count++; my_current = list.my_head; } /****************************************************************************/ template inline KPReadOnlyIterator::KPReadOnlyIterator( const KPReadOnlyIterator &iterator) : my_list(iterator.my_list) { if (my_list) ((KPList *)my_list)->my_iterator_count++; my_current = iterator.my_current; } /****************************************************************************/ template inline KPReadOnlyIterator::~KPReadOnlyIterator() { if (my_list) ((KPList *)my_list)->my_iterator_count--; } /****************************************************************************/ template inline KPReadOnlyIterator & KPReadOnlyIterator::iterate_over(const KPList &list) { if (my_list) ((KPList *)my_list)->my_iterator_count--; my_list = &list; ((KPList *)my_list)->my_iterator_count++; my_current = my_list->my_head; return *this; } /****************************************************************************/ template inline KPReadOnlyIterator & KPReadOnlyIterator::iterate_over() { if (my_list) { ((KPList *)my_list)->my_iterator_count--; my_list = NULL; my_current = NULL; } return *this; } /****************************************************************************/ template inline KPReadOnlyIterator & KPReadOnlyIterator::operator=(const KPReadOnlyIterator &iterator) { if (my_list) ((KPList *)my_list)->my_iterator_count--; my_list = iterator.my_list; if (my_list) ((KPList *)my_list)->my_iterator_count++; my_current = iterator.my_current; return *this; } /****************************************************************************/ template inline const Element & KPReadOnlyIterator::current() const { if(!my_current) error("current() - no current element"); return my_current->element; } /****************************************************************************/ template inline const Element * KPReadOnlyIterator::ptr() const { if (my_current) return &my_current->element; else return NULL; } /****************************************************************************/ template inline KPReadOnlyIterator & KPReadOnlyIterator::beginning() { if (my_list) my_current = my_list->my_head; return *this; } /****************************************************************************/ template inline KPReadOnlyIterator & KPReadOnlyIterator::end() { if (my_list) my_current = my_list->my_tail; return *this; } /****************************************************************************/ template inline KPReadOnlyIterator & KPReadOnlyIterator::operator++() // Prefix { if (!my_current) error("operator++() - no next element"); my_current = my_current->next; return *this; } /****************************************************************************/ template inline KPReadOnlyIterator & KPReadOnlyIterator::operator--() // Prefix { if (!my_current) error("operator--() - no previous element"); my_current = my_current->previous; return *this; } /****************************************************************************/ template inline void KPReadOnlyIterator::operator++(int) // Postfix { if (!my_current) error("operator++() - no next element"); my_current = my_current->next; } /****************************************************************************/ template inline void KPReadOnlyIterator::operator--(int) // Postfix { if (!my_current) error("operator--() - no previous element"); my_current = my_current->previous; } /****************************************************************************/ template inline const Element & KPReadOnlyIterator::operator*() const { if (!my_current) error("operator*() - no current element"); return my_current->element; } /****************************************************************************/ template inline const Element * KPReadOnlyIterator::operator->() const { if (!my_current) error("operator->() - no current element"); return &my_current->element; } /****************************************************************************/ template inline bool KPReadOnlyIterator::at_beginning() const { return (my_current && !my_current->previous); } /****************************************************************************/ template inline bool KPReadOnlyIterator::at_end() const { return (my_current && !my_current->next); } /****************************************************************************/ template inline int KPReadOnlyIterator::size() const { return my_list->size(); } /****************************************************************************/ template inline bool KPReadOnlyIterator::is_empty() const { return my_list->is_empty(); } /****************************************************************************/ template inline const KPList & KPReadOnlyIterator::list() const { if (!my_list) error("list() - no list associated with iterator"); return *my_list; } /****************************************************************************/ template void KPReadOnlyIterator::error(const char *msg) { cerr << "KPReadOnlyIterator: " << msg << '\n'; exit(EXIT_FAILURE); } /****************************************************************************/ template inline KPIterator::KPIterator() { my_list = NULL; my_current = NULL; } /****************************************************************************/ template inline KPIterator::KPIterator(KPList &list) { my_list = &list; list.my_iterator_count++; my_current = list.my_head; } /****************************************************************************/ template inline KPIterator::KPIterator(const KPIterator &iterator) : my_list(iterator.my_list) { if (my_list) my_list->my_iterator_count++; my_current = iterator.my_current; } /****************************************************************************/ template inline KPIterator::~KPIterator() { if (my_list) my_list->my_iterator_count--; } /****************************************************************************/ template inline KPIterator & KPIterator::iterate_over(KPList &list) { if (my_list) my_list->my_iterator_count--; my_list = &list; my_list->my_iterator_count++; my_current = my_list->my_head; return *this; } /****************************************************************************/ template inline KPIterator & KPIterator::iterate_over() { if (my_list) { my_list->my_iterator_count--; my_list = NULL; my_current = NULL; } return *this; } /****************************************************************************/ template inline KPIterator & KPIterator::operator=(const KPIterator &iterator) { if (my_list) my_list->my_iterator_count--; my_list = iterator.my_list; if (my_list) my_list->my_iterator_count++; my_current = iterator.my_current; return *this; } /****************************************************************************/ template KPIterator & KPIterator::insert_before_current(const Element &element) { if (!my_current) error("insert_before_current() - no current element"); KPList::Node *newnode = new KPList::Node; check_mem(newnode); newnode->element = element; if (my_current->previous) { if (my_current == &my_deleted) { newnode->previous = my_current->previous; newnode->next = my_current->next; my_current->previous->next = newnode; if (my_current->next) my_current->next->previous = newnode; else my_list->my_tail = newnode; my_current->previous = newnode; } else { newnode->previous = my_current->previous; newnode->next = my_current; my_current->previous->next = newnode; my_current->previous = newnode; } } else { my_list->my_head->previous = newnode; my_current->previous = newnode; // in case my_current == my_deleted newnode->next = my_list->my_head; newnode->previous = NULL; my_list->my_head = newnode; } my_list->my_size++; return *this; } /****************************************************************************/ template KPIterator & KPIterator::insert_after_current(const Element &element) { if (!my_current) error("insert_after_current() - no current element"); KPList::Node *newnode = new KPList::Node; check_mem(newnode); newnode->element = element; if (my_current->next) { if (my_current == &my_deleted) { newnode->next = my_current->next; newnode->previous = my_current->previous; my_current->next->previous = newnode; if (my_current->previous) my_current->previous->next = newnode; else my_list->my_head = newnode; my_current->next = newnode; } else { newnode->next = my_current->next; newnode->previous = my_current; my_current->next->previous = newnode; my_current->next = newnode; } } else { my_list->my_tail->next = newnode; my_current->next = newnode; // in case my_current == my_deleted newnode->previous = my_list->my_tail; newnode->next = NULL; my_list->my_tail = newnode; } my_list->my_size++; return *this; } /****************************************************************************/ template KPIterator & KPIterator::replace_current_with(const Element &element) { if (!my_current) error("replace_current_with() - no current element"); if (my_current == &my_deleted) error("replace_current_with() - current element has been deleted"); my_current->element = element; return *this; } /****************************************************************************/ template inline Element & KPIterator::current() { if(!my_current) error("current() - no current element"); return my_current->element; } /****************************************************************************/ template inline Element * KPIterator::ptr() { if (my_current) return &my_current->element; else return NULL; } /****************************************************************************/ template void KPIterator::remove_current() { if (!my_current) error("remove_current() - no current element"); else if (my_current == &my_deleted) error("remove_current() - current element has already been removed"); else if (my_list->my_iterator_count > 1) error("remove_current() - cannot remove element, " "more than one iterator"); else { my_deleted.previous = my_current->previous; my_deleted.next = my_current->next; delete my_current; my_current = &my_deleted; if (my_deleted.previous) my_deleted.previous->next = my_deleted.next; else my_list->my_head = my_deleted.next; if (my_deleted.next) my_deleted.next->previous = my_deleted.previous; else my_list->my_tail = my_deleted.previous; my_list->my_size--; } } /****************************************************************************/ template inline KPIterator & KPIterator::beginning() { if (my_list) my_current = my_list->my_head; return *this; } /****************************************************************************/ template inline KPIterator & KPIterator::end() { if (my_list) my_current = my_list->my_tail; return *this; } /****************************************************************************/ template inline KPIterator & KPIterator::operator++() // Prefix { if (!my_current) error("operator++() - no next element"); my_current = my_current->next; return *this; } /****************************************************************************/ template inline KPIterator & KPIterator::operator--() // Prefix { if (!my_current) error("operator--() - no previous element"); my_current = my_current->previous; return *this; } /****************************************************************************/ template inline void KPIterator::operator++(int) // Postfix { if (!my_current) error("operator++() - no next element"); my_current = my_current->next; } /****************************************************************************/ template inline void KPIterator::operator--(int) // Postfix { if (!my_current) error("operator--() - no previous element"); my_current = my_current->previous; } /****************************************************************************/ template inline Element & KPIterator::operator*() { if (!my_current) error("operator*() - no current element"); return my_current->element; } /****************************************************************************/ template inline Element * KPIterator::operator->() { if (!my_current) error("operator->() - no current element"); return &my_current->element; } /****************************************************************************/ template inline bool KPIterator::at_beginning() const { return (my_current && !my_current->previous); } /****************************************************************************/ template inline bool KPIterator::at_end() const { return (my_current && !my_current->next); } /****************************************************************************/ template inline int KPIterator::size() const { return my_list->size(); } /****************************************************************************/ template inline bool KPIterator::is_empty() const { return my_list->is_empty(); } /****************************************************************************/ template inline KPList & KPIterator::list() { if (!my_list) error("list() - no list associated with iterator"); return *my_list; } /****************************************************************************/ template void KPIterator::error(const char *msg) { cerr << "KPIterator: " << msg << '\n'; exit(EXIT_FAILURE); } /****************************************************************************/ #endif /* KP_LIST_DEFINED */