From c4bf1641bd28b492eadba197e6f9149e6601399d Mon Sep 17 00:00:00 2001 From: Bananymous Date: Thu, 1 Feb 2024 14:19:02 +0200 Subject: [PATCH] BAN: Add cool API for LinkedList You can now move elements between LinkedLists without allocations or deallocations. Same node moves from source to destination --- BAN/include/BAN/LinkedList.h | 76 ++++++++++++++++++++++++------------ 1 file changed, 51 insertions(+), 25 deletions(-) diff --git a/BAN/include/BAN/LinkedList.h b/BAN/include/BAN/LinkedList.h index aefb1e0f..79161f37 100644 --- a/BAN/include/BAN/LinkedList.h +++ b/BAN/include/BAN/LinkedList.h @@ -42,6 +42,8 @@ namespace BAN 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); } @@ -65,7 +67,11 @@ namespace BAN Node* prev; }; - ErrorOr allocate_node() const; + template + ErrorOr allocate_node(Args&&...) const; + + Node* remove_node(iterator); + void insert_node(iterator, Node*); Node* m_data = nullptr; Node* m_last = nullptr; @@ -137,6 +143,31 @@ namespace BAN 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) { @@ -158,15 +189,8 @@ namespace BAN template ErrorOr LinkedList::insert(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++; + Node* new_node = TRY(allocate_node(move(value))); + insert_node(iter, new_node); return {}; } @@ -181,21 +205,15 @@ namespace BAN template ErrorOr LinkedList::emplace(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++; + 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)); } @@ -203,14 +221,10 @@ namespace BAN LinkedList::iterator LinkedList::remove(iterator iter) { ASSERT(!empty() && iter); - Node* node = iter.m_current; - Node* prev = node->prev; + Node* node = remove_node(iter); Node* next = node->next; node->value.~T(); BAN::deallocator(node); - (prev ? prev->next : m_data) = next; - (next ? next->prev : m_last) = prev; - m_size--; return next ? iterator(next, false) : iterator(m_last, true); } @@ -230,6 +244,16 @@ namespace BAN 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 { @@ -284,11 +308,13 @@ namespace BAN } template - ErrorOr::Node*> LinkedList::allocate_node() const + 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; }