110 lines
3.6 KiB
C
110 lines
3.6 KiB
C
|
#ifndef CIRCULARLIST_H
|
||
|
#define CIRCULARLIST_H
|
||
|
|
||
|
#include "LinkedList.h"
|
||
|
|
||
|
namespace Kylin {
|
||
|
template <typename T>
|
||
|
class CircularLinkedList : public LinkedList<T> {
|
||
|
using Node = typename LinkedList<T>::Node;
|
||
|
using Iterator = typename LinkedList<T>::Iterator;
|
||
|
|
||
|
public:
|
||
|
CircularLinkedList() = default;
|
||
|
CircularLinkedList(std::initializer_list<T> init) {
|
||
|
this->m_header.next = reinterpret_cast<Node *>(&this->m_header);
|
||
|
this->m_last = reinterpret_cast<Node *>(&this->m_header);
|
||
|
|
||
|
for (auto &value : init) {
|
||
|
this->append(value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CircularLinkedList(const CircularLinkedList &other) {
|
||
|
this->m_header.next = reinterpret_cast<Node *>(&this->m_header);
|
||
|
this->m_last = reinterpret_cast<Node *>(&this->m_header);
|
||
|
|
||
|
auto sourceNode = other.m_header.next;
|
||
|
auto targetNode = reinterpret_cast<Node *>(&this->m_header);
|
||
|
for (size_t i = 0; i < other.m_size; i++) {
|
||
|
auto newNode = this->create();
|
||
|
if (newNode == nullptr) THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create node ...");
|
||
|
newNode->value = sourceNode->value;
|
||
|
targetNode->next = newNode;
|
||
|
targetNode = newNode;
|
||
|
sourceNode = sourceNode->next;
|
||
|
this->m_size++;
|
||
|
targetNode->next = this->m_header.next;
|
||
|
this->m_last = targetNode;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CircularLinkedList(CircularLinkedList &&other) {
|
||
|
this->m_size = other.m_size;
|
||
|
this->m_header = other.m_header;
|
||
|
this->m_last = other.m_last;
|
||
|
|
||
|
other.m_size = 0;
|
||
|
other.m_header.next = nullptr;
|
||
|
other.m_last = reinterpret_cast<Node *>(&other.m_header);
|
||
|
}
|
||
|
|
||
|
void insert(size_t index, const T &value) override {
|
||
|
index = index % (this->m_size + 1);
|
||
|
if (index == this->m_size) return this->append(value);
|
||
|
LinkedList<T>::insert(index, value);
|
||
|
if (index == 0) lastToFirst();
|
||
|
}
|
||
|
|
||
|
void removeAt(size_t index) override {
|
||
|
if (this->size() <= 0)
|
||
|
THROW_EXCEPTION(IndexOutOfBoundsException, "There is no element in the container.");
|
||
|
index = mod(index);
|
||
|
if (index == 0) {
|
||
|
auto toDel = this->m_header.next;
|
||
|
this->m_header.next = toDel->next;
|
||
|
this->m_size--;
|
||
|
if (this->m_size == 0) {
|
||
|
this->m_header.next = nullptr;
|
||
|
} else {
|
||
|
lastToFirst();
|
||
|
}
|
||
|
this->destroy(toDel);
|
||
|
} else {
|
||
|
LinkedList<T>::removeAt(index);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
virtual void clear() {
|
||
|
while (this->m_size > 1) {
|
||
|
removeAt(1);
|
||
|
}
|
||
|
if (this->m_size == 1) {
|
||
|
auto del = this->m_header.next;
|
||
|
this->m_header.next = nullptr;
|
||
|
this->m_size = 0;
|
||
|
this->destroy(del);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Iterator end() override { return Iterator(reinterpret_cast<Node *>(&this->m_header)); }
|
||
|
|
||
|
Iterator end() const override { return Iterator(reinterpret_cast<Node *>(&this->m_header)); }
|
||
|
|
||
|
T &operator[](size_t index) override {
|
||
|
if (this->m_size <= 0)
|
||
|
THROW_EXCEPTION(InvalidOperationException, "There is no element in the container...");
|
||
|
index = mod(index);
|
||
|
return this->position(index)->next->value;
|
||
|
}
|
||
|
|
||
|
virtual ~CircularLinkedList() { clear(); }
|
||
|
|
||
|
protected:
|
||
|
size_t mod(size_t index) const { return (this->m_size == 0) ? 0 : (index % this->m_size); }
|
||
|
|
||
|
void lastToFirst() { this->position(this->m_size - 1)->next->next = this->m_header.next; }
|
||
|
};
|
||
|
} // namespace Kylin
|
||
|
#endif // CIRCULARLIST_H
|