// List.h // // A class List similar to the STL container list. // Version 1.2 // // Included from Versions 1.0 and 1.1: // List(), back(), push_back(e), pop_back() // iterators, constant iterators // begin, end, cbegin, cend // insert, erase // // New in this version: // copy constructor, assignment operator, destructor #ifndef _List_h_ #define _List_h_ template class List; template class ListIterator; template class ConstListIterator; template class ListNode // T is the type of element stored in the List. { friend class List; friend class ListIterator; friend class ConstListIterator; private: ListNode() : element(), next(nullptr), previous(nullptr) {} ListNode(const T & e, ListNode * next0, ListNode * previous0); T element; ListNode * next; ListNode * previous; }; template ListNode::ListNode(const T & e, ListNode * next0, ListNode * previous0) : element(e), next(next0), previous(previous0) {} template class ListIterator // T is the type of element stored in the List. { friend class List; friend class ConstListIterator; public: ListIterator() : p_current_node(nullptr) {} T & operator*() const { return p_current_node->element; } T * operator->() const { return &(p_current_node->element); } bool operator==(const ListIterator & rhs) const { return (p_current_node == rhs.p_current_node); } bool operator!=(const ListIterator & rhs) const { return (p_current_node != rhs.p_current_node); } ListIterator & operator++(); // prefix version (++itr) ListIterator & operator--(); ListIterator operator++(int); // postfix version (itr++) ListIterator operator--(int); private: explicit ListIterator(ListNode * p) : p_current_node(p) {} ListNode * p_current_node; // points to the node that contains the element that the // iterator currently points to }; template inline ListIterator & ListIterator::operator++() // prefix version (++itr) { p_current_node = p_current_node->next; return *this; } template inline ListIterator & ListIterator::operator--() // prefix version (--itr) { p_current_node = p_current_node->previous; return *this; } template inline ListIterator ListIterator::operator++(int) // postfix version (itr++) { ListIterator original_itr = *this; p_current_node = p_current_node->next; return original_itr; } template inline ListIterator ListIterator::operator--(int) // postfix version (itr++) { ListIterator original_itr = *this; p_current_node = p_current_node->previous; return original_itr; } template class ConstListIterator // T is the type of element stored in the List. { friend class List; public: ConstListIterator() : p_current_node(nullptr) {} ConstListIterator(const ListIterator & itr) : p_current_node(itr.p_current_node) {} const T & operator*() const { return p_current_node->element; } const T * operator->() const { return &(p_current_node->element); } bool operator==(const ConstListIterator & rhs) const { return (p_current_node == rhs.p_current_node); } bool operator!=(const ConstListIterator & rhs) const { return (p_current_node != rhs.p_current_node); } ConstListIterator & operator++(); // prefix version (++itr) ConstListIterator & operator--(); ConstListIterator operator++(int); // postfix version (itr++) ConstListIterator operator--(int); private: explicit ConstListIterator(const ListNode * p) : p_current_node(p) {} const ListNode * p_current_node; // points to the node that contains the element that the // iterator currently points to }; template inline ConstListIterator & ConstListIterator::operator++() // prefix version (++itr) { p_current_node = p_current_node->next; return *this; } template inline ConstListIterator & ConstListIterator::operator--() // prefix version (--itr) { p_current_node = p_current_node->previous; return *this; } template inline ConstListIterator ConstListIterator::operator++(int) // postfix version (itr++) { ConstListIterator original_itr = *this; p_current_node = p_current_node->next; return original_itr; } template inline ConstListIterator ConstListIterator::operator--(int) // postfix version (itr++) { ConstListIterator original_itr = *this; p_current_node = p_current_node->previous; return original_itr; } template class List // T is the type of element stored in the List. { public: typedef ListIterator iterator; typedef ConstListIterator const_iterator; List(); List(const List & ls); ~List(); T & back() { return p_head_node->previous->element; } const T & back() const { return p_head_node->previous->element; } void push_back(const T & new_element); void pop_back(); iterator begin() { return iterator(p_head_node->next); } iterator end() { return iterator(p_head_node); } const_iterator begin() const { return const_iterator(p_head_node->next); } const_iterator end() const { return const_iterator(p_head_node); } const_iterator cbegin() const { return const_iterator(p_head_node->next); } const_iterator cend() const { return const_iterator(p_head_node); } iterator insert(const_iterator itr, const T & new_element); iterator erase(const_iterator itr ); List & operator=( const List & rhs ); private: ListNode * p_head_node; }; template inline List::List() { p_head_node = new ListNode; p_head_node->next = p_head_node->previous = p_head_node; } template inline void List::push_back(const T & new_element) { // set a pointer to the last node ListNode * p_last_node = p_head_node->previous; // create new node and set its contents ListNode * p_new_node = new ListNode(new_element, p_head_node, p_last_node); // finish linking new node to list p_last_node->next = p_new_node; p_head_node->previous = p_new_node; } template inline void List::pop_back() { // set pointers to last node and node that will become last ListNode * p_last_node = p_head_node->previous; ListNode * p_new_last_node = p_last_node->previous; // modify the list to skip the last node p_new_last_node->next = p_head_node; p_head_node->previous = p_new_last_node; // deallocate the last node p_last_node->next = p_last_node->previous = nullptr; delete p_last_node; } template inline typename List::iterator List::insert( const_iterator const_itr, const T & new_element) { // set pointer to the node that should follow the new one ListNode * p_next_node = (ListNode *)(const_itr.p_current_node); // set pointer to the node that should precede the new one ListNode * p_previous_node = p_next_node->previous; // create new node and set its contents ListNode * p_new_node = new ListNode(new_element, p_next_node, p_previous_node); // set next and previous nodes to point to the new node p_previous_node->next = p_new_node; p_next_node->previous = p_new_node; return iterator(p_new_node); } template inline typename List::iterator List::erase( const_iterator const_itr) { // set pointer to the node to be deleted ListNode * p_target_node = (ListNode *)(const_itr.p_current_node); // set pointers to the nodes that precede and follow the target // node ListNode * p_previous_node = p_target_node->previous; ListNode * p_next_node = p_target_node->next; // modify the list to skip the target node p_previous_node->next = p_next_node; p_next_node->previous = p_previous_node; // deallocate the target node p_target_node->next = p_target_node->previous = nullptr; delete p_target_node; return iterator(p_next_node); } template List::List(const List & ls) : List() { for (const T & e : ls) push_back(e); } template List::~List() { // erase all elements while (begin() != end()) pop_back(); // deallocate dummy head node delete p_head_node; } template inline List & List::operator=(const List & rhs) { List copy_of_rhs = rhs; std::swap(p_head_node, copy_of_rhs.p_head_node); return *this; // old contents of receiver is deallocated when copy_of_rhs // is destroyed } #endif