#ifndef DOUBLY_LINKED_LIST_IMPL_ #define DOUBLY_LINKED_LIST_IMPL_ #include template class DoublyLinkedList { private: struct DLListNode { T data; DLListNode* next; DLListNode* prev; DLListNode(const T& d, DLListNode* n = nullptr, DLListNode* p = nullptr) : data {d}, next {n}, prev {p} {} }; using Node = DLListNode; Node* head; Node* tail; void copy(const DoublyLinkedList& other); void free(); class Iterator { private: Node* current; Iterator(Node* c = nullptr) : current { c } {} public: Iterator& operator++() { if(current == nullptr) return *this; current = current->next; return *this; } Iterator operator++(int) { if(current == nullptr) return *this; Iterator tmp = *this; current = current->next; return tmp; } Iterator& operator--() { if(current == nullptr) return *this; current = current->prev; return *this; } Iterator operator--(int) { if(current == nullptr) return *this; Iterator tmp = *this; current = current->prev; return tmp; } const T& operator*() { if(current == nullptr) throw std::exception(); return current->data; } bool operator==(const Iterator& other) const { return current == other.current; } bool operator!=(const Iterator& other) const { return !(*this == other); } friend class DoublyLinkedList; }; public: DoublyLinkedList(); DoublyLinkedList(const DoublyLinkedList&); DoublyLinkedList& operator=(const DoublyLinkedList&); DoublyLinkedList(DoublyLinkedList&&); DoublyLinkedList& operator=(DoublyLinkedList&&); void pushBack(const T&); void popBack(); void pushFront(const T&); void popFront(); bool empty() const; const T& back() const; const T& front() const; Iterator begin(); Iterator end(); void insert(Iterator at, const T& elem); ~DoublyLinkedList(); }; template DoublyLinkedList::DoublyLinkedList() : head { nullptr }, tail { nullptr } {} template DoublyLinkedList::DoublyLinkedList(const DoublyLinkedList& other) : head {nullptr}, tail {nullptr} { copy(other); } template DoublyLinkedList& DoublyLinkedList::operator=(const DoublyLinkedList& other) { if(this != &other) { free(); copy(other); } return *this; } template DoublyLinkedList::DoublyLinkedList(DoublyLinkedList&& other) { head = other.head; tail = other.tail; other.head = other.tail = nullptr; } template DoublyLinkedList& DoublyLinkedList::operator=(DoublyLinkedList&& other) { if(this != &other) { free(); head = other.head; tail = other.tail; other.head = other.tail = nullptr; } return *this; } template void DoublyLinkedList::copy(const DoublyLinkedList& other) { Node* iter = other.head; while(iter) { pushBack(iter->data); iter = iter->next; } } template void DoublyLinkedList::free() { while(head) { Node* toDelete = head; head = head->next; delete toDelete; } } template bool DoublyLinkedList::empty() const { return head == nullptr; } template void DoublyLinkedList::pushBack(const T& elem) { Node* toInsert = new Node(elem); if(empty()) { head = tail = toInsert; } else { toInsert->prev = tail; tail->next = toInsert; tail = toInsert; } } template void DoublyLinkedList::pushFront(const T& elem) { Node* toInsert = new Node(elem); if(empty()) { head = tail = toInsert; } else { toInsert->next = head; head->prev = toInsert; head = toInsert; } } template void DoublyLinkedList::popBack() { if(empty()) throw std::exception(); if(tail == head) { delete head; tail = head = nullptr; return; } tail->prev->next = nullptr; Node* toDelete = tail; tail = tail->prev; delete toDelete; } template void DoublyLinkedList::popFront() { if(empty()) throw std::exception(); Node* toDelete = head; if(head == tail) { delete toDelete; head = tail = nullptr; return; } head->next->prev = nullptr; head = head->next; delete toDelete; } template typename DoublyLinkedList::Iterator DoublyLinkedList::begin() { return Iterator(head); } template typename DoublyLinkedList::Iterator DoublyLinkedList::end() { return Iterator(nullptr); } template void DoublyLinkedList::insert(Iterator at, const T& elem) { // Ако е nullptr предполагам, че са подали .end() и добавям в края if(at.current == nullptr) { tail->next = new Node(elem, nullptr, tail); tail = tail->next; return; } Node* toInsert = new Node(elem, at.current, at.current->prev); if(at.current->prev != nullptr) at.current->prev->next = toInsert; at.current->prev = toInsert; if(at.current == head) head = toInsert; if(at.current == tail) tail = toInsert; at.current = toInsert; } template const T& DoublyLinkedList::back() const { if(empty()) throw std::exception(); return tail->data; } template const T& DoublyLinkedList::front() const { if(empty()) throw std::exception(); return head->data; } template DoublyLinkedList::~DoublyLinkedList(){ free(); } #endif