#pragma once #include #include #include #include namespace BAN { template class LinkedListIterator; template class LinkedList { public: using size_type = size_t; using value_type = T; using iterator = LinkedListIterator; using const_iterator = LinkedListIterator; public: LinkedList() = default; LinkedList(const LinkedList& other) requires is_copy_constructible_v { *this = other; } LinkedList(LinkedList&& other) { *this = move(other); } ~LinkedList() { clear(); } LinkedList& operator=(const LinkedList&) requires is_copy_constructible_v; LinkedList& operator=(LinkedList&&); ErrorOr push_back(const T&); ErrorOr push_back(T&&); ErrorOr insert(iterator, const T&); ErrorOr insert(iterator, T&&); template ErrorOr emplace_back(Args&&...); template ErrorOr emplace(iterator, Args&&...); void pop_back(); iterator remove(iterator); void clear(); iterator move_element_to_other_linked_list(LinkedList& dest_list, iterator dest_iter, iterator src_iter); iterator begin() { return iterator(m_data, empty()); } const_iterator begin() const { return const_iterator(m_data, empty()); } 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(); bool contains(const T&) const; size_type size() const; bool empty() const; private: struct Node { T value; Node* next; Node* prev; }; template ErrorOr allocate_node(Args&&...) const; Node* remove_node(iterator); void insert_node(iterator, Node*); Node* m_data = nullptr; Node* m_last = nullptr; size_type m_size = 0; friend class LinkedListIterator; friend class LinkedListIterator; }; template class LinkedListIterator { public: using value_type = T; using data_type = maybe_const_t::Node>; public: LinkedListIterator() = default; template LinkedListIterator(const LinkedListIterator&, enable_if_t* = 0); LinkedListIterator& operator++(); LinkedListIterator& operator--(); LinkedListIterator operator++(int); LinkedListIterator operator--(int); template enable_if_t operator*(); const T& operator*() const; template enable_if_t operator->(); const T* operator->() const; bool operator==(const LinkedListIterator&) const; bool operator!=(const LinkedListIterator&) const; operator bool() const; private: LinkedListIterator(data_type*, bool); private: data_type* m_current = nullptr; bool m_past_end = false; friend class LinkedList; friend class LinkedListIterator; }; template LinkedList& LinkedList::operator=(const LinkedList& other) requires is_copy_constructible_v { clear(); for (const T& elem : other) MUST(push_back(elem)); return *this; } template LinkedList& LinkedList::operator=(LinkedList&& other) { clear(); m_data = other.m_data; m_last = other.m_last; m_size = other.m_size; other.m_data = nullptr; other.m_last = nullptr; other.m_size = 0; return *this; } template LinkedList::Node* LinkedList::remove_node(iterator iter) { ASSERT(!empty() && iter); Node* node = iter.m_current; Node* prev = node->prev; Node* next = node->next; (prev ? prev->next : m_data) = next; (next ? next->prev : m_last) = prev; m_size--; return node; } template void LinkedList::insert_node(iterator iter, Node* node) { Node* next = iter.m_past_end ? nullptr : iter.m_current; Node* prev = next ? next->prev : m_last; node->next = next; node->prev = prev; (prev ? prev->next : m_data) = node; (next ? next->prev : m_last) = node; m_size++; } template ErrorOr LinkedList::push_back(const T& value) { return push_back(move(T(value))); } template ErrorOr LinkedList::push_back(T&& value) { return insert(end(), move(value)); } template ErrorOr LinkedList::insert(iterator iter, const T& value) { return insert(iter, move(T(value))); } template ErrorOr LinkedList::insert(iterator iter, T&& value) { Node* new_node = TRY(allocate_node(move(value))); insert_node(iter, new_node); return {}; } template template ErrorOr LinkedList::emplace_back(Args&&... args) { return emplace(end(), forward(args)...); } template template ErrorOr LinkedList::emplace(iterator iter, Args&&... args) { Node* new_node = TRY(allocate_node(forward(args)...)); insert_node(iter, new_node); return {}; } template void LinkedList::pop_back() { ASSERT(!empty()); remove(iterator(m_last, false)); } template LinkedList::iterator LinkedList::remove(iterator iter) { ASSERT(!empty() && iter); Node* node = remove_node(iter); Node* next = node->next; node->value.~T(); BAN::deallocator(node); return next ? iterator(next, false) : iterator(m_last, true); } 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 LinkedList::iterator LinkedList::move_element_to_other_linked_list(LinkedList& dest_list, iterator dest_iter, iterator src_iter) { ASSERT(!empty() && src_iter); Node* node = remove_node(src_iter); iterator ret = node->next ? iterator(node->next, false) : iterator(m_last, true); dest_list.insert_node(dest_iter, node); return ret; } template const T& LinkedList::back() const { ASSERT(!empty()); return *const_iterator(m_last, false); } template T& LinkedList::back() { ASSERT(!empty()); return *iterator(m_last, false); } template const T& LinkedList::front() const { ASSERT(!empty()); return *const_iterator(m_data, false); } template T& LinkedList::front() { ASSERT(!empty()); return *iterator(m_data, false); } template bool LinkedList::contains(const T& value) const { if (empty()) return false; for (Node* node = m_data;; node = node->next) { if (node->value == value) return true; if (node == m_last) return false; } } template typename LinkedList::size_type LinkedList::size() const { return m_size; } template bool LinkedList::empty() const { return m_size == 0; } template template ErrorOr::Node*> LinkedList::allocate_node(Args&&... args) const { Node* node = (Node*)BAN::allocator(sizeof(Node)); if (node == nullptr) return Error::from_errno(ENOMEM); new (&node->value) T(forward(args)...); return node; } template template LinkedListIterator::LinkedListIterator(const LinkedListIterator& other, enable_if_t*) : m_current(other.m_current) , m_past_end(other.m_past_end) { } template LinkedListIterator::LinkedListIterator(data_type* node, bool past_end) : m_current(node) , m_past_end(past_end) { } template LinkedListIterator& 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; } template LinkedListIterator& 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; } template LinkedListIterator LinkedListIterator::operator++(int) { auto temp = *this; ++(*this); return temp; } template LinkedListIterator LinkedListIterator::operator--(int) { auto temp = *this; --(*this); return temp; } template template enable_if_t LinkedListIterator::operator*() { ASSERT(m_current); return m_current->value; } template const T& LinkedListIterator::operator*() const { ASSERT(m_current); return m_current->value; } template template enable_if_t LinkedListIterator::operator->() { ASSERT(m_current); return &m_current->value; } template const T* LinkedListIterator::operator->() const { ASSERT(m_current); return &m_current->value; } template bool LinkedListIterator::operator==(const LinkedListIterator& other) const { if (m_current != other.m_current) return false; return m_past_end == other.m_past_end; } template bool LinkedListIterator::operator!=(const LinkedListIterator& other) const { return !(*this == other); } template LinkedListIterator::operator bool() const { return m_current; } }