195 lines
5.6 KiB
C
195 lines
5.6 KiB
C
|
#ifndef LINKEDLIST_H
|
||
|
#define LINKEDLIST_H
|
||
|
|
||
|
#include "Exception.h"
|
||
|
#include "List.h"
|
||
|
#include <initializer_list>
|
||
|
|
||
|
namespace Kylin {
|
||
|
|
||
|
template <typename T>
|
||
|
class LinkedList : public List<T> {
|
||
|
protected:
|
||
|
struct Node : public Object {
|
||
|
T value;
|
||
|
Node *next = nullptr;
|
||
|
};
|
||
|
|
||
|
struct : public Object {
|
||
|
char reserved[sizeof(T)];
|
||
|
Node *next = nullptr;
|
||
|
} mutable m_header;
|
||
|
|
||
|
public:
|
||
|
class Iterator : public Object {
|
||
|
friend class LinkedList;
|
||
|
|
||
|
public:
|
||
|
Iterator() = default;
|
||
|
Iterator(Node *pos) : pos(pos) {}
|
||
|
Iterator &operator++() {
|
||
|
pos = pos->next;
|
||
|
return *this;
|
||
|
}
|
||
|
Iterator operator++(int) {
|
||
|
auto old = *this;
|
||
|
pos = pos->next;
|
||
|
return old;
|
||
|
}
|
||
|
|
||
|
Iterator operator+=(size_t size) {
|
||
|
for (size_t i = 0; (i < size) && (pos != nullptr); i++) {
|
||
|
pos = &(*pos)->next;
|
||
|
}
|
||
|
}
|
||
|
T *operator->() const { return &pos->value; }
|
||
|
T &operator*() const { return pos->value; }
|
||
|
bool operator!=(const Iterator &iter) { return pos != iter.pos; }
|
||
|
bool operator==(const Iterator &iter) { return pos == iter.pos; }
|
||
|
|
||
|
private:
|
||
|
Node *pos = nullptr;
|
||
|
};
|
||
|
|
||
|
LinkedList() { m_last = reinterpret_cast<Node *>(&m_header); }
|
||
|
|
||
|
LinkedList(std::initializer_list<T> init) {
|
||
|
m_last = reinterpret_cast<Node *>(&m_header);
|
||
|
for (auto &value : init) {
|
||
|
append(value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LinkedList(const LinkedList &other) {
|
||
|
auto sourceNode = other.m_header.next;
|
||
|
auto targetNode = reinterpret_cast<Node *>(&m_header);
|
||
|
while (sourceNode != nullptr) {
|
||
|
auto newNode = create();
|
||
|
if (newNode == nullptr) THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create node ...");
|
||
|
newNode->value = sourceNode->value;
|
||
|
targetNode->next = newNode;
|
||
|
targetNode = newNode;
|
||
|
sourceNode = sourceNode->next;
|
||
|
m_size++;
|
||
|
targetNode->next = nullptr;
|
||
|
m_last = targetNode;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LinkedList(LinkedList &&other) {
|
||
|
m_size = other.m_size;
|
||
|
m_header = other.m_header;
|
||
|
m_last = other.m_last;
|
||
|
|
||
|
other.m_size = 0;
|
||
|
other.m_header.next = nullptr;
|
||
|
other.m_last = reinterpret_cast<Node *>(&other.m_header);
|
||
|
}
|
||
|
|
||
|
~LinkedList() { clear(); }
|
||
|
|
||
|
void swap(LinkedList &other) {
|
||
|
if (this == &other) return;
|
||
|
auto tempSize = other.m_size;
|
||
|
auto tempHeader = other.m_header;
|
||
|
auto tempLast = other.m_last;
|
||
|
|
||
|
other.m_header = m_header;
|
||
|
other.m_size = m_size;
|
||
|
other.m_last = m_last;
|
||
|
|
||
|
m_header = tempHeader;
|
||
|
m_size = tempSize;
|
||
|
m_last = tempLast;
|
||
|
}
|
||
|
|
||
|
virtual void append(const T &value) {
|
||
|
auto node = create();
|
||
|
if (node == nullptr) THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create node ...");
|
||
|
node->value = value;
|
||
|
|
||
|
node->next = m_last->next; // for circular linked list
|
||
|
m_last->next = node;
|
||
|
m_last = node;
|
||
|
m_size++;
|
||
|
}
|
||
|
|
||
|
virtual void insert(size_t index, const T &value) {
|
||
|
if (index >= m_size) return append(value);
|
||
|
Node *prev = position(index);
|
||
|
Node *node = create();
|
||
|
if (node == nullptr) THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create node ...");
|
||
|
node->value = value;
|
||
|
node->next = prev->next;
|
||
|
prev->next = node;
|
||
|
m_size += 1;
|
||
|
}
|
||
|
|
||
|
T &last() override {
|
||
|
if (m_size <= 0) THROW_EXCEPTION(InvalidOperationException, "There is no element in the container.");
|
||
|
return m_last->value;
|
||
|
}
|
||
|
|
||
|
void removeAt(size_t index) override {
|
||
|
if (index >= m_size) THROW_EXCEPTION(IndexOutOfBoundsException, "The index is out of range.");
|
||
|
Node *prev = position(index);
|
||
|
Node *toDel = prev->next;
|
||
|
prev->next = toDel->next;
|
||
|
if (index == m_size - 1) m_last = prev;
|
||
|
m_size--;
|
||
|
destroy(toDel);
|
||
|
}
|
||
|
|
||
|
virtual void clear() {
|
||
|
while (m_header.next != nullptr) {
|
||
|
Node *del = m_header.next;
|
||
|
m_header.next = del->next;
|
||
|
m_size--;
|
||
|
destroy(del);
|
||
|
}
|
||
|
m_last = reinterpret_cast<Node *>(&m_header);
|
||
|
}
|
||
|
|
||
|
virtual size_t size() const noexcept { return m_size; }
|
||
|
|
||
|
virtual size_t indexOf(const T &value, size_t from = 0) const final {
|
||
|
auto node = position(from)->next;
|
||
|
for (size_t i = from; i < m_size; i++, node = node->next) {
|
||
|
if (node->value == value) return i;
|
||
|
}
|
||
|
return LinkedList::npos;
|
||
|
}
|
||
|
|
||
|
Iterator begin() { return Iterator(m_header.next); }
|
||
|
|
||
|
Iterator begin() const { return Iterator(m_header.next); }
|
||
|
|
||
|
virtual Iterator end() { return Iterator(); }
|
||
|
|
||
|
virtual Iterator end() const { return Iterator(); }
|
||
|
|
||
|
T &operator[](size_t index) override {
|
||
|
if (index >= m_size) THROW_EXCEPTION(IndexOutOfBoundsException, "Index out of bounds...");
|
||
|
return position(index)->next->value;
|
||
|
}
|
||
|
|
||
|
protected:
|
||
|
Node *position(size_t index) const {
|
||
|
Node *ret = reinterpret_cast<Node *>(&m_header);
|
||
|
for (size_t i = 0; i < index; i++) {
|
||
|
ret = ret->next;
|
||
|
}
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
virtual Node *create() { return new Node(); }
|
||
|
|
||
|
virtual void destroy(Node *p) { delete p; }
|
||
|
|
||
|
size_t m_size = 0;
|
||
|
|
||
|
Node *m_last = nullptr;
|
||
|
};
|
||
|
} // namespace Kylin
|
||
|
#endif // LINKEDLIST_H
|