From b286c0c85d659c16937d5c5c15ff2f89a017b0d4 Mon Sep 17 00:00:00 2001 From: Jeremiah Morgan Date: Tue, 19 Nov 2024 12:45:18 +0000 Subject: [PATCH] Pathfinding: Precomputeportal nodes for A Star --- libopenage/datastructure/pairing_heap.h | 282 +++++++++++------------- 1 file changed, 126 insertions(+), 156 deletions(-) diff --git a/libopenage/datastructure/pairing_heap.h b/libopenage/datastructure/pairing_heap.h index 662a683ee6..d7b2d745ab 100644 --- a/libopenage/datastructure/pairing_heap.h +++ b/libopenage/datastructure/pairing_heap.h @@ -81,13 +81,13 @@ class PairingHeapNode { // it must not have siblings as they will get lost. new_child->prev_sibling = nullptr; - new_child->next_sibling = this->child; + new_child->next_sibling = this->first_child; - if (this->child != nullptr) { - this->child->prev_sibling = new_child; + if (this->first_child != nullptr) { + this->first_child->prev_sibling = new_child; } - this->child = new_child; + this->first_child = new_child; new_child->parent = this; } @@ -156,10 +156,10 @@ class PairingHeapNode { */ void loosen() { // release us from some other node - if (this->parent and this->parent->child == this) { + if (this->parent and this->parent->first_child == this) { // we are child // make the next sibling child - this->parent->child = this->next_sibling; + this->parent->first_child = this->next_sibling; } // if we have a previous sibling if (this->prev_sibling != nullptr) { @@ -179,7 +179,7 @@ class PairingHeapNode { } private: - this_type *child = nullptr; + this_type *first_child = nullptr; this_type *prev_sibling = nullptr; this_type *next_sibling = nullptr; this_type *parent = nullptr; // for decrease-key and delete @@ -230,12 +230,89 @@ class PairingHeap final { } /** - * returns and removes the smallest item on the heap. + * returns the smallest item on the heap and deletes it. + * also known as delete_min. + * _________ + * Ω(log log n), O(2^(2*√log log n')) + * caller must eventually either add node back to heap or delete it */ T pop() { - element_t poped_node = this->pop_node(); - T data = std::move(poped_node->data); - delete poped_node; + if (this->root_node == nullptr) { + throw Error{MSG(err) << "Can't pop an empty heap!"}; + } + + // 0. remove tree root, it's the minimum. + element_t ret = this->root_node; + + if (!this->nodes.erase(ret)) { + throw Error{MSG(err) << "didn't remove node"}; + } + + this->node_count -= 1; + element_t current_sibling = this->root_node->first_child; + this->root_node = nullptr; + + // 1. link root children pairwise, last node may be alone + element_t first_pair = nullptr; + element_t previous_pair = nullptr; + + while (current_sibling != nullptr) [[unlikely]] { + element_t link0 = current_sibling; + element_t link1 = current_sibling->next_sibling; + + // pair link0 and link1 + if (link1 != nullptr) { + // get the first sibling for next pair, just in advance. + current_sibling = link1->next_sibling; + + // do the link: merges two nodes, smaller one = root. + element_t link_root = link0->link_with(link1); + link_root->parent = nullptr; + + if (previous_pair == nullptr) { + // this was the first pair + first_pair = link_root; + first_pair->prev_sibling = nullptr; + } + else { + // store node as next sibling in previous pair + previous_pair->next_sibling = link_root; + link_root->prev_sibling = previous_pair; + } + + previous_pair = link_root; + link_root->next_sibling = nullptr; + } + else { + // link0 is the last and unpaired root child. + link0->parent = nullptr; + if (previous_pair == nullptr) { + // link0 was the only node + first_pair = link0; + link0->prev_sibling = nullptr; + } + else { + previous_pair->next_sibling = link0; + link0->prev_sibling = previous_pair; + } + link0->next_sibling = nullptr; + current_sibling = nullptr; + } + } + + + // 2. then link remaining trees to the last one, from right to left + if (first_pair != nullptr) { + this->root_node = first_pair->link_backwards(); + } + + // (to find those two lines, 14h of debugging passed) + ret->loosen(); + ret->first_child = nullptr; + + // and it's done! + T data = std::move(ret->data); + delete ret; return data; } @@ -283,27 +360,44 @@ class PairingHeap final { * * O(1) (but slower than decrease), and O(pop) when node is the root. */ - void update(const element_t &node) { + void update(element_t &node) { if (node != this->root_node) [[likely]] { - this->unlink_node(node); - this->push_node(node); + node = this->push(this->remove_node(node)); } else { // it's the root node, so we just pop and push it. - this->push_node(this->pop_node()); + node = this->push(this->pop()); } } - /** - * Remove node from tree, return its data and destroy the node. - * O(pop_node) + * remove a node from the heap. Return its data. + * + * If the item is the current root, just pop(). + * else, cut the node from its parent, pop() that subtree + * and merge these trees. + * + * O(pop_node) */ - T remove_node(element_t &node) { - this->unlink_node(node); - T data = std::move(node->data); - delete node; - return data; + T remove_node(const element_t &node) { + if (node == this->root_node) { + return this->pop(); + } + else { + node->loosen(); + + element_t real_root = this->root_node; + this->root_node = node; + T data = this->pop(); + + element_t new_root = this->root_node; + this->root_node = real_root; + + if (new_root != nullptr) { + this->root_insert(new_root); + } + return data; + } } /** @@ -316,9 +410,6 @@ class PairingHeap final { delete node; } this->nodes.clear(); - -#if OPENAGE_PAIRINGHEAP_DEBUG -#endif } /** @@ -378,15 +469,15 @@ class PairingHeap final { } } - if (root->child) { - if (root->child == root->next_sibling) { - throw Error{ERR << "child is next_sibling"}; + if (root->first_child) { + if (root->first_child == root->next_sibling) { + throw Error{ERR << "first_child is next_sibling"}; } - if (root->child == root->prev_sibling) { - throw Error{ERR << "child is prev_sibling"}; + if (root->first_child == root->prev_sibling) { + throw Error{ERR << "first_child is prev_sibling"}; } - if (root->child == root->parent) { - throw Error{ERR << "child is parent"}; + if (root->first_child == root->parent) { + throw Error{ERR << "first_child is parent"}; } } @@ -394,7 +485,7 @@ class PairingHeap final { if (found_nodes.find(root->parent) == std::end(found_nodes)) { throw Error{ERR << "parent node is not known"}; } - element_t child = root->parent->child; + element_t child = root->parent->first_child; element_t lastchild; bool foundvianext = false, foundviaprev = false; @@ -492,43 +583,12 @@ class PairingHeap final { } private: - /** - * Unlink a node from the heap. - * - * If the item is the current root, just pop(). - * else, cut the node from its parent, pop() that subtree - * and merge these trees. - * - * O(pop_node) - * caller must eventually add node back to heap or delete node - */ - void unlink_node(const element_t &node) { - if (node == this->root_node) { - this->pop_node(); - } - else { - node->loosen(); - - element_t real_root = this->root_node; - this->root_node = node; - this->pop_node(); - - element_t new_root = this->root_node; - this->root_node = real_root; - - if (new_root != nullptr) { - this->root_insert(new_root); - } - } - } - - void walk_tree(const element_t &root, const std::function &func) const { func(root); if (root) { - auto node = root->child; + auto node = root->first_child; while (true) { if (not node) { break; @@ -560,96 +620,6 @@ class PairingHeap final { } - /** - * returns the smallest item on the heap and deletes it. - * also known as delete_min. - * _________ - * Ω(log log n), O(2^(2*√log log n')) - * caller must eventually either add node back to heap or delete it - */ - element_t pop_node() { - if (this->root_node == nullptr) { - throw Error{MSG(err) << "Can't pop an empty heap!"}; - } - - // 0. remove tree root, it's the minimum. - element_t ret = this->root_node; - element_t current_sibling = this->root_node->child; - this->root_node = nullptr; - - // 1. link root children pairwise, last node may be alone - element_t first_pair = nullptr; - element_t previous_pair = nullptr; - - while (current_sibling != nullptr) [[unlikely]] { - element_t link0 = current_sibling; - element_t link1 = current_sibling->next_sibling; - - // pair link0 and link1 - if (link1 != nullptr) { - // get the first sibling for next pair, just in advance. - current_sibling = link1->next_sibling; - - // do the link: merges two nodes, smaller one = root. - element_t link_root = link0->link_with(link1); - link_root->parent = nullptr; - - if (previous_pair == nullptr) { - // this was the first pair - first_pair = link_root; - first_pair->prev_sibling = nullptr; - } - else { - // store node as next sibling in previous pair - previous_pair->next_sibling = link_root; - link_root->prev_sibling = previous_pair; - } - - previous_pair = link_root; - link_root->next_sibling = nullptr; - } - else { - // link0 is the last and unpaired root child. - link0->parent = nullptr; - if (previous_pair == nullptr) { - // link0 was the only node - first_pair = link0; - link0->prev_sibling = nullptr; - } - else { - previous_pair->next_sibling = link0; - link0->prev_sibling = previous_pair; - } - link0->next_sibling = nullptr; - current_sibling = nullptr; - } - } - - - // 2. then link remaining trees to the last one, from right to left - if (first_pair != nullptr) { - this->root_node = first_pair->link_backwards(); - } - - this->node_count -= 1; - size_t erase_result = this->nodes.erase(ret); - - -#if OPENAGE_PAIRINGHEAP_DEBUG - if (1 != erase_result) { - throw Error{ERR << "didn't remove node"}; - } -#endif - - // (to find those two lines, 14h of debugging passed) - ret->loosen(); - ret->child = nullptr; - - // and it's done! - return ret; - } - - /** * insert a node into the heap. */