From 1945b716ad53b8b07419cdb464e78274ff9670c7 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Wed, 1 Feb 2023 01:22:41 +0200 Subject: [PATCH] BAN: Implement basic LinkedList --- BAN/include/BAN/LinkedList.h | 313 +++++++++++++++++++++++++++++++++++ 1 file changed, 313 insertions(+) create mode 100644 BAN/include/BAN/LinkedList.h diff --git a/BAN/include/BAN/LinkedList.h b/BAN/include/BAN/LinkedList.h new file mode 100644 index 000000000..b81802f08 --- /dev/null +++ b/BAN/include/BAN/LinkedList.h @@ -0,0 +1,313 @@ +#pragma once + +#include +#include +#include + +namespace BAN +{ + + template + class LinkedListIterator; + template + class LinkedListConstIterator; + + template + class LinkedList + { + BAN_NON_COPYABLE(LinkedList); + BAN_NON_MOVABLE(LinkedList); + + public: + using size_type = size_t; + using value_type = T; + using iterator = LinkedListIterator; + using const_iterator = LinkedListConstIterator; + + public: + LinkedList() = default; + ~LinkedList(); + + [[nodiscard]] ErrorOr PushBack(const T&); + [[nodiscard]] ErrorOr PushBack(T&&); + [[nodiscard]] ErrorOr Insert(const_iterator, const T&); + [[nodiscard]] ErrorOr Insert(const_iterator, T&&); + template + [[nodiscard]] ErrorOr EmplaceBack(Args...); + template + [[nodiscard]] ErrorOr Emplace(const_iterator, Args...); + + void PopBack(); + void Remove(const_iterator); + void Clear(); + + iterator begin() { return iterator(m_data, false); } + const_iterator begin() const { return const_iterator(m_data, false); } + iterator end() { return iterator(m_last, true); } + const_iterator end() const { return const_iterator(m_last, true); } + + const T& Back() const; + T& Back(); + const T& Front() const; + T& Front(); + + size_type Size() const; + bool Empty() const; + + private: + struct Node + { + T value; + Node* next; + Node* prev; + }; + + [[nodiscard]] ErrorOr allocate_node() const; + + Node* m_data = nullptr; + Node* m_last = nullptr; + size_type m_size = 0; + + friend class LinkedListIterator; + friend class LinkedListConstIterator; + }; + + template + class LinkedListIterator + { + public: + using value_type = T; + + public: + LinkedListIterator() = default; + LinkedListIterator(const LinkedListIterator& other) : m_current(other.m_current), m_past_end(other.m_past_end) {} + LinkedListIterator& operator++() + { + ASSERT(m_current); + ASSERT(m_current->next || !m_past_end); + if (m_current->next) + m_current = m_current->next; + else + m_past_end = true; + return *this; + } + LinkedListIterator& operator--() + { + ASSERT(m_current); + ASSERT(m_current->prev || m_past_end); + if (m_past_end) + m_past_end = false; + else + m_current = m_current->prev; + return *this; + } + LinkedListIterator operator++(int) { auto temp = *this; ++(*this); return temp; } + LinkedListIterator operator--(int) { auto temp = *this; --(*this); return temp; } + T& operator*() { ASSERT(m_current); return m_current->value; } + const T& operator*() const { ASSERT(m_current); return m_current->value; } + bool operator==(const LinkedListIterator& other) const { return m_current && m_current == other.m_current && m_past_end == other.m_past_end; } + bool operator!=(const LinkedListIterator& other) const { return !(*this == other); } + operator bool() const { return m_current; } + private: + LinkedListIterator(typename LinkedList::Node* node, bool past_end) : m_current(node), m_past_end(past_end) { } + private: + typename LinkedList::Node* m_current = nullptr; + bool m_past_end = false; + + friend class LinkedList; + friend class LinkedListConstIterator; + }; + + template + class LinkedListConstIterator + { + public: + using value_type = T; + + public: + LinkedListConstIterator() = default; + LinkedListConstIterator(const LinkedListIterator& other) : m_current(other.m_current), m_past_end(other.m_past_end) {} + LinkedListConstIterator(const LinkedListConstIterator& other) : m_current(other.m_current), m_past_end(other.m_past_end) {} + LinkedListConstIterator& operator++() + { + ASSERT(m_current); + ASSERT(m_current->next || !m_past_end); + if (m_current->next) + m_current = m_current->next; + else + m_past_end = true; + return *this; + } + LinkedListConstIterator& operator--() + { + ASSERT(m_current); + ASSERT(m_current->prev || m_past_end); + if (m_past_end) + m_past_end = false; + else + m_current = m_current->prev; + return *this; + } + LinkedListConstIterator operator++(int) { auto temp = *this; ++(*this); return temp; } + LinkedListConstIterator operator--(int) { auto temp = *this; --(*this); return temp; } + const T& operator*() const { ASSERT(m_current); return m_current->value; } + bool operator==(const LinkedListConstIterator& other) const { return m_current && m_current == other.m_current && m_past_end == other.m_past_end; } + bool operator!=(const LinkedListConstIterator& other) const { return !(*this == other); } + operator bool() const { return m_current; } + private: + LinkedListConstIterator(typename LinkedList::Node* node, bool past_end) : m_current(node), m_past_end(past_end) {} + private: + typename LinkedList::Node* m_current = nullptr; + bool m_past_end = false; + + friend class LinkedList; + }; + + template + LinkedList::~LinkedList() + { + Clear(); + } + + template + ErrorOr LinkedList::PushBack(const T& value) + { + return PushBack(Move(T(value))); + } + + template + ErrorOr LinkedList::PushBack(T&& value) + { + return Insert(end(), Move(value)); + } + + template + ErrorOr LinkedList::Insert(const_iterator iter, const T& value) + { + return Insert(iter, Move(T(value))); + } + + template + ErrorOr LinkedList::Insert(const_iterator iter, T&& value) + { + Node* next = iter.m_past_end ? nullptr : iter.m_current; + Node* prev = next ? next->prev : m_last; + Node* new_node = TRY(allocate_node()); + new (&new_node->value) T(Move(value)); + new_node->next = next; + new_node->prev = prev; + (prev ? prev->next : m_data) = new_node; + (next ? next->prev : m_last) = new_node; + m_size++; + return {}; + } + + template + template + ErrorOr LinkedList::EmplaceBack(Args... args) + { + return Emplace(end(), Forward(args)...); + } + + template + template + ErrorOr LinkedList::Emplace(const_iterator iter, Args... args) + { + Node* next = iter.m_past_end ? nullptr : iter.m_current; + Node* prev = next ? next->prev : m_last; + Node* new_node = TRY(allocate_node()); + new (&new_node->value) T(Forward(args)...); + new_node->next = next; + new_node->prev = prev; + (prev ? prev->next : m_data) = new_node; + (next ? next->prev : m_last) = new_node; + m_size++; + return {}; + } + + template + void LinkedList::PopBack() + { + return Remove(m_last); + } + + template + void LinkedList::Remove(const_iterator iter) + { + ASSERT(m_size > 0); + Node* node = iter.m_current; + Node* prev = node->prev; + Node* next = node->next; + node->value.~T(); + BAN::deallocator(node); + (prev ? prev->next : m_data) = next; + (next ? next->prev : m_last) = prev; + m_size--; + } + + template + void LinkedList::Clear() + { + Node* ptr = m_data; + while (ptr) + { + Node* next = ptr->next; + ptr->value.~T(); + BAN::deallocator(ptr); + ptr = next; + } + m_data = nullptr; + m_last = nullptr; + m_size = 0; + } + + template + const T& LinkedList::Back() const + { + ASSERT(m_size > 0); + return *const_iterator(m_last); + } + + template + T& LinkedList::Back() + { + ASSERT(m_size > 0); + return *iterator(m_last); + } + + template + const T& LinkedList::Front() const + { + ASSERT(m_size > 0); + return *const_iterator(m_data); + } + + template + T& LinkedList::Front() + { + ASSERT(m_size > 0); + return *iterator(m_data); + } + + template + typename LinkedList::size_type LinkedList::Size() const + { + return m_size; + } + + template + bool LinkedList::Empty() const + { + return m_size == 0; + } + + template + ErrorOr::Node*> LinkedList::allocate_node() const + { + Node* node = (Node*)BAN::allocator(sizeof(Node)); + if (node == nullptr) + return Error::FromString("LinkedList: Could not allocate memory"); + return node; + } + +} \ No newline at end of file