/* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2020 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "py/pairheap.h" // The mp_pairheap_t.next pointer can take one of the following values: // - NULL: the node is the top of the heap // - LSB set: the node is the last of the children and points to its parent node // - other: the node is a child and not the last child // The macros below help manage this pointer. #define NEXT_MAKE_RIGHTMOST_PARENT(parent) ((void *)((uintptr_t)(parent) | 1)) #define NEXT_IS_RIGHTMOST_PARENT(next) ((uintptr_t)(next) & 1) #define NEXT_GET_RIGHTMOST_PARENT(next) ((void *)((uintptr_t)(next) & ~1)) // O(1), stable mp_pairheap_t *mp_pairheap_meld(mp_pairheap_lt_t lt, mp_pairheap_t *heap1, mp_pairheap_t *heap2) { if (heap1 == NULL) { return heap2; } if (heap2 == NULL) { return heap1; } if (lt(heap1, heap2)) { if (heap1->child == NULL) { heap1->child = heap2; } else { heap1->child_last->next = heap2; } heap1->child_last = heap2; heap2->next = NEXT_MAKE_RIGHTMOST_PARENT(heap1); return heap1; } else { heap1->next = heap2->child; heap2->child = heap1; if (heap1->next == NULL) { heap2->child_last = heap1; heap1->next = NEXT_MAKE_RIGHTMOST_PARENT(heap2); } return heap2; } } // amortised O(log N), stable mp_pairheap_t *mp_pairheap_pairing(mp_pairheap_lt_t lt, mp_pairheap_t *child) { if (child == NULL) { return NULL; } mp_pairheap_t *heap = NULL; while (!NEXT_IS_RIGHTMOST_PARENT(child)) { mp_pairheap_t *n1 = child; child = child->next; n1->next = NULL; if (!NEXT_IS_RIGHTMOST_PARENT(child)) { mp_pairheap_t *n2 = child; child = child->next; n2->next = NULL; n1 = mp_pairheap_meld(lt, n1, n2); } heap = mp_pairheap_meld(lt, heap, n1); } heap->next = NULL; return heap; } // amortised O(log N), stable mp_pairheap_t *mp_pairheap_delete(mp_pairheap_lt_t lt, mp_pairheap_t *heap, mp_pairheap_t *node) { // Simple case of the top being the node to delete if (node == heap) { mp_pairheap_t *child = heap->child; node->child = NULL; return mp_pairheap_pairing(lt, child); } // Case where node is not in the heap if (node->next == NULL) { return heap; } // Find parent of node mp_pairheap_t *parent = node; while (!NEXT_IS_RIGHTMOST_PARENT(parent->next)) { parent = parent->next; } parent = NEXT_GET_RIGHTMOST_PARENT(parent->next); // Replace node with pairing of its children mp_pairheap_t *next; if (node == parent->child && node->child == NULL) { if (NEXT_IS_RIGHTMOST_PARENT(node->next)) { parent->child = NULL; } else { parent->child = node->next; } node->next = NULL; return heap; } else if (node == parent->child) { mp_pairheap_t *child = node->child; next = node->next; node->child = NULL; node->next = NULL; node = mp_pairheap_pairing(lt, child); parent->child = node; } else { mp_pairheap_t *n = parent->child; while (node != n->next) { n = n->next; } mp_pairheap_t *child = node->child; next = node->next; node->child = NULL; node->next = NULL; node = mp_pairheap_pairing(lt, child); if (node == NULL) { node = n; } else { n->next = node; } } node->next = next; if (NEXT_IS_RIGHTMOST_PARENT(next)) { parent->child_last = node; } return heap; }