/** * Copyright (C) 2013-2014 Justin James. * * This license must be preserved. * Any applications, libraries, or code which make any use of any * component of this program must not be commercial, unless explicit * permission is granted from the original author. The use of this * program for non-profit purposes is permitted. * * This program 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. * * In the event that this license restricts you from making desired use of this program, contact the original author. * Written by Justin James */ #if !defined _DLLIST_H_HEADER #define _DLLIST_H_HEADER /** * @file DLList.h * @brief Provides a generic Doubly Linked List implementation using the List interface. */ #include "Jupiter.h" #include "List.h" namespace Jupiter { /** * @brief Provides a Doubly Linked List implementation using the List interface. */ template class DLList : public List { public: /** * @brief Stores a pointer to data, and a pointer to the next node in the list. */ struct Node { Node *next; Node *previous; T *data; }; /** * @brief Returns the n'th Node in the list. * * @param n Index of the node to return. * @return n'th Node in the list. */ Node *getNode(size_t n) const; /** * @brief Gets the data at a specified index. * * @param index Index of the data to get. * @return Data stored at the specified index. */ T *get(size_t index) const; /** * @brief Removes the n'th Node in the list, and returns its contents. * * @param n Index of the node to remove. * @return Contents of the node removed. */ T *remove(size_t n); /** * @brief Removes a node from the list. * * @param data Node to remove. * @return Contents of the node removed. */ T *remove(Node *data); /** * @brief Adds data to the list at a specified index. * * @param data Data to add to the list. * @param index Position in the list to add the data to. */ void add(T *data, size_t index); /** * @brief Adds data to the end of the list. * * @param data Data to add to the list. */ void add(T *data); /** * @brief Default constructor for the DLList class. */ DLList(); /** * @brief Copy constructor for the DLList class. */ DLList(const DLList &); /** * @brief Destructor for the DLList class. * Note: This does not delete data added to the list. */ ~DLList(); /** Private members */ private: Node *head; Node *end; }; } // Implementation template Jupiter::DLList::DLList() { Jupiter::DLList::head = nullptr; Jupiter::DLList::end = nullptr; Jupiter::List::length = 0; } template Jupiter::DLList::DLList(const Jupiter::DLList &source) { Jupiter::List::length = source.length; if (Jupiter::List::length == 0) { Jupiter::DLList::head = nullptr; Jupiter::DLList::end = nullptr; } else if (Jupiter::List::length == 1) { Jupiter::DLList::Node *n = new Jupiter::DLList::Node; n->data = source.getNode(0)->data; Jupiter::DLList::head = n; Jupiter::DLList::end = n; } else { Jupiter::DLList::Node *sourceNode = source.getNode(0); Jupiter::DLList::Node *n = new Jupiter::DLList::Node; n->data = sourceNode->data; Jupiter::DLList::head = n; sourceNode = sourceNode->next; while (sourceNode->next != nullptr) { n->next = new Jupiter::DLList::Node; n = n->next; n->data = sourceNode->data; sourceNode = sourceNode->next; } n->next = new Jupiter::DLList::Node; n = n->next; n->data = sourceNode->data; Jupiter::DLList::end = n; } } template Jupiter::DLList::~DLList() { Jupiter::DLList::Node *p; Jupiter::DLList::Node *c = Jupiter::DLList::head; while (c != nullptr) { p = c; c = c->next; delete p; } } template typename Jupiter::DLList::Node *Jupiter::DLList::getNode(size_t index) const { Jupiter::DLList::Node *r; if (index * 2 < Jupiter::List::length) { r = Jupiter::DLList::head; for (size_t i = 0; i < index; i++) r = r->next; return r; } r = Jupiter::DLList::end; for (size_t i = Jupiter::List::length - 1; i > index; i--) r = r->previous; return r; } template T *Jupiter::DLList::get(size_t index) const { return Jupiter::DLList::getNode(index)->data; } template T *Jupiter::DLList::remove(size_t index) { return Jupiter::DLList::remove(Jupiter::DLList::getNode(index)); } template T *Jupiter::DLList::remove(Node *data) { if (Jupiter::DLList::head == data) { Jupiter::DLList::head = data->next; if (data->next != nullptr) data->next->previous = data->previous; else Jupiter::DLList::end = nullptr; } else if (Jupiter::DLList::end == data) { Jupiter::DLList::end = data->previous; Jupiter::DLList::end->next = nullptr; } else { data->next->previous = data->previous; data->previous->next = data->next; } T *r = data->data; delete data; Jupiter::List::length--; return r; } template void Jupiter::DLList::add(T *data, size_t index) { Jupiter::DLList::Node *node = new Jupiter::DLList::Node(); node->data = data; if (index == 0) { node->next = Jupiter::DLList::head; Jupiter::DLList::head->previous = node; Jupiter::DLList::head = node; node->previous = nullptr; } else if (index == Jupiter::List::length) { node->previous = Jupiter::DLList::end; Jupiter::DLList::end->next = node; Jupiter::DLList::end = node; node->next = nullptr; } else { Jupiter::DLList::Node *n = Jupiter::DLList::getNode(index); node->next = n; node->previous = n->previous; node->previous->next = node; n->previous = node; } Jupiter::List::length++; } template void Jupiter::DLList::add(T *data) { Jupiter::DLList::Node *n = new Jupiter::DLList::Node(); n->data = data; n->next = nullptr; if (Jupiter::List::length == 0) { Jupiter::DLList::head = n; Jupiter::DLList::end = n; n->previous = nullptr; } else { n->previous = Jupiter::DLList::end; Jupiter::DLList::end->next = n; Jupiter::DLList::end = n; } Jupiter::List::length++; } #endif // _DLLIST_H_HEADER