Source File: ex61_dlist.hpp
#include <functional>
void my_assert(bool test, const std::string& message) {
if(!test) throw std::runtime_error(message);
}
template<typename T>
struct DListNode {
T data;
DListNode<T> *next = nullptr;
DListNode<T> *prev = nullptr;
};
template<typename T>
class DList {
DListNode<T> *head = nullptr;
DListNode<T> *tail = nullptr;
public:
DListNode<T>* first() {
return head;
}
DListNode<T>* last() {
return tail;
}
void push_back(const T& data) {
auto* temp = new DListNode<T>{.data = data};
if(tail == nullptr) {
// empty list
head = temp;
tail = temp;
} else {
// has elements
tail->next = temp;
temp->prev = tail;
tail = temp;
}
}
void push_front(const T& data) {
auto* temp = new DListNode<T>{.data = data};
if(head == nullptr) {
// empty list
head = temp;
tail = temp;
} else {
// has elements
head->prev = temp;
temp->next = head;
head = temp;
}
}
T pop_front() {
my_assert(head != nullptr, "empty list!");
auto result = head->data;
if(head->next == nullptr) {
// one
delete head;
head = nullptr;
tail = nullptr;
} else {
// many, shuffle head down
head = head->next; // move down one
delete head->prev; // delete the old head
head->prev = nullptr; // close it off
}
return result;
}
T pop_back() {
// zero, abort
my_assert(tail != nullptr, "empty list!");
// has either one or many, aways return result
auto result = tail->data;
// different operation for one vs many
if(tail->prev == nullptr) {
// one, delete tail and clear head/tail
delete tail;
head = nullptr;
tail = nullptr;
} else {
// many, shuffle tail around
tail = tail->prev; // move back one
delete tail->next; // delete old tail
tail->next = nullptr; // close it off
}
return result;
}
void for_each(std::function<void(const T&)> cb) {
for(auto* cur = head; cur != nullptr; cur = cur->next) {
cb(cur->data);
}
}
int count() {
int res = 0;
for_each([&](const auto& val) { res++; });
return res;
}
};