Kylin/DataStructure/LinkedList.h
2023-12-27 10:29:16 +08:00

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