| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450 |
- /**
- * @file BHeap.h
- * @author Ambroz Bizjak <ambrop7@gmail.com>
- *
- * @section LICENSE
- *
- * This file is part of BadVPN.
- *
- * BadVPN is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * BadVPN is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * @section DESCRIPTION
- *
- * Binary heap.
- */
- #ifndef BADVPN_STRUCTURE_BHEAP_H
- #define BADVPN_STRUCTURE_BHEAP_H
- //#define BHEAP_DEBUG
- #include <stdint.h>
- #include <stddef.h>
- #include <misc/debug.h>
- /**
- * Handler function called by heap algorithms to compare two values.
- * For any two values, the comparator must always return the same result.
- * The <= relation defined by the comparator must be a total order.
- * Values are obtained like that:
- * - The value of a node in the heap, or a node that is being inserted is:
- * (uint8_t *)node + offset.
- * - The value being looked up is the same as given to the lookup function.
- *
- * @param user as in {@link BHeap_Init}
- * @param val1 first value
- * @param val2 second value
- * @return -1 if val1 < val2, 0 if val1 = val2, 1 if val1 > val2
- */
- typedef int (*BHeap_comparator) (void *user, void *val1, void *val2);
- struct BHeapNode;
- /**
- * Binary heap.
- */
- typedef struct {
- int offset;
- BHeap_comparator comparator;
- void *user;
- struct BHeapNode *root;
- struct BHeapNode *last;
- #ifndef NDEBUG
- int in_handler;
- #endif
- } BHeap;
- /**
- * Binary heap node.
- */
- typedef struct BHeapNode {
- struct BHeapNode *parent;
- struct BHeapNode *link[2];
- } BHeapNode;
- /**
- * Initializes the heap.
- *
- * @param o heap to initialize
- * @param offset offset of a value from its node
- * @param comparator value comparator handler function
- * @param user value to pass to comparator
- */
- static void BHeap_Init (BHeap *h, int offset, BHeap_comparator comparator, void *user);
- /**
- * Inserts a node into the heap.
- * Must not be called from comparator.
- *
- * @param o the heap
- * @param node uninitialized node to insert. Must have a valid value (its value
- * may be passed to the comparator during insertion).
- */
- static void BHeap_Insert (BHeap *h, BHeapNode *node);
- /**
- * Removes a node from the heap.
- * Must not be called from comparator.
- *
- * @param o the heap
- * @param node node to remove
- */
- static void BHeap_Remove (BHeap *h, BHeapNode *node);
- /**
- * Returns one of the smallest nodes in the heap.
- * Must not be called from comparator.
- *
- * @param o the heap
- * @return one of the smallest nodes in the heap, or NULL if there
- * are no nodes
- */
- static BHeapNode * BHeap_GetFirst (BHeap *h);
- static void * _BHeap_node_value (BHeap *o, BHeapNode *n)
- {
- return ((uint8_t *)n + o->offset);
- }
- static int _BHeap_compare_values (BHeap *o, void *v1, void *v2)
- {
- #ifndef NDEBUG
- o->in_handler = 1;
- #endif
-
- int res = o->comparator(o->user, v1, v2);
-
- #ifndef NDEBUG
- o->in_handler = 0;
- #endif
-
- ASSERT(res == -1 || res == 0 || res == 1)
-
- return res;
- }
- static int _BHeap_compare_nodes (BHeap *o, BHeapNode *n1, BHeapNode *n2)
- {
- return _BHeap_compare_values(o, _BHeap_node_value(o, n1), _BHeap_node_value(o, n2));
- }
- #ifdef BHEAP_DEBUG
- #define BHEAP_ASSERT(_h) _BHeap_assert(_h);
- #else
- #define BHEAP_ASSERT(_h)
- #endif
- #ifdef BHEAP_DEBUG
- struct _BHeap_assert_data {
- int state;
- int level;
- BHeapNode *prev_leaf;
- };
- #define BHEAP_ASSERT_STATE_NODEPTH 1
- #define BHEAP_ASSERT_STATE_LOWEST 2
- #define BHEAP_ASSERT_STATE_LOWESTEND 3
- static void _BHeap_assert_recurser (BHeap *h, BHeapNode *n, struct _BHeap_assert_data *ad, int level)
- {
- if (!n->link[0] && !n->link[1]) {
- if (ad->state == BHEAP_ASSERT_STATE_NODEPTH) {
- // leftmost none, remember depth
- ad->state = BHEAP_ASSERT_STATE_LOWEST;
- ad->level = level;
- }
- } else {
- // drop down
- if (n->link[0]) {
- ASSERT(_BHeap_compare_nodes(h, n, n->link[0]) <= 0)
- ASSERT(n->link[0]->parent == n)
- _BHeap_assert_recurser(h, n->link[0], ad, level + 1);
- }
- if (n->link[1]) {
- ASSERT(_BHeap_compare_nodes(h, n, n->link[1]) <= 0)
- ASSERT(n->link[1]->parent == n)
- _BHeap_assert_recurser(h, n->link[1], ad, level + 1);
- }
- }
-
- ASSERT(ad->state == BHEAP_ASSERT_STATE_LOWEST || ad->state == BHEAP_ASSERT_STATE_LOWESTEND)
-
- if (level < ad->level - 1) {
- ASSERT(n->link[0] && n->link[1])
- }
- else if (level == ad->level - 1) {
- switch (ad->state) {
- case BHEAP_ASSERT_STATE_LOWEST:
- if (!n->link[0]) {
- ad->state = BHEAP_ASSERT_STATE_LOWESTEND;
- ASSERT(!n->link[1])
- ASSERT(ad->prev_leaf == h->last)
- } else {
- if (!n->link[1]) {
- ad->state = BHEAP_ASSERT_STATE_LOWESTEND;
- ASSERT(ad->prev_leaf == h->last)
- }
- }
- break;
- case BHEAP_ASSERT_STATE_LOWESTEND:
- ASSERT(!n->link[0] && !n->link[1])
- break;
- }
- }
- else if (level == ad->level) {
- ASSERT(ad->state == BHEAP_ASSERT_STATE_LOWEST)
- ASSERT(!n->link[0] && !n->link[1])
- ad->prev_leaf = n;
- }
- else {
- ASSERT(0)
- }
- }
- static void _BHeap_assert (BHeap *h)
- {
- struct _BHeap_assert_data ad;
- ad.state = BHEAP_ASSERT_STATE_NODEPTH;
- ad.prev_leaf = NULL;
-
- if (h->root) {
- ASSERT(h->last)
- ASSERT(!h->root->parent)
- _BHeap_assert_recurser(h, h->root, &ad, 0);
- if (ad.state == BHEAP_ASSERT_STATE_LOWEST) {
- ASSERT(ad.prev_leaf == h->last)
- }
- } else {
- ASSERT(!h->last)
- }
- }
- #endif
- static void _BHeap_move_one_up (BHeap *h, BHeapNode *n)
- {
- ASSERT(n->parent)
-
- BHeapNode *p = n->parent;
-
- if (p->parent) {
- p->parent->link[p == p->parent->link[1]] = n;
- } else {
- h->root = n;
- }
- n->parent = p->parent;
-
- int nside = (n == p->link[1]);
- BHeapNode *c = p->link[!nside];
-
- p->link[0] = n->link[0];
- if (p->link[0]) {
- p->link[0]->parent = p;
- }
-
- p->link[1] = n->link[1];
- if (p->link[1]) {
- p->link[1]->parent = p;
- }
-
- n->link[nside] = p;
- p->parent = n;
-
- n->link[!nside] = c;
- if (c) {
- c->parent = n;
- }
-
- if (n == h->last) {
- h->last = p;
- }
- }
- static void _BHeap_replace_node (BHeap *h, BHeapNode *d, BHeapNode *s)
- {
- if (d->parent) {
- d->parent->link[d == d->parent->link[1]] = s;
- } else {
- h->root = s;
- }
- s->parent = d->parent;
-
- s->link[0] = d->link[0];
- if (s->link[0]) {
- s->link[0]->parent = s;
- }
-
- s->link[1] = d->link[1];
- if (s->link[1]) {
- s->link[1]->parent = s;
- }
- }
- void BHeap_Init (BHeap *h, int offset, BHeap_comparator comparator, void *user)
- {
- h->offset = offset;
- h->comparator = comparator;
- h->user = user;
- h->root = NULL;
- h->last = NULL;
-
- #ifndef NDEBUG
- h->in_handler = 0;
- #endif
-
- BHEAP_ASSERT(h)
- }
- void BHeap_Insert (BHeap *h, BHeapNode *node)
- {
- ASSERT(!h->in_handler)
-
- if (!h->root) {
- // insert to root
- h->root = node;
- h->last = node;
- node->parent = NULL;
- node->link[0] = NULL;
- node->link[1] = NULL;
-
- BHEAP_ASSERT(h)
- return;
- }
-
- // find the node to insert to
-
- // start with current last node and walk up left as much as possible.
- // That is, keep replacing the current node with the parent as long as it
- // exists and the current node is its right child.
- BHeapNode *cur = h->last;
- while (cur->parent && cur == cur->parent->link[1]) {
- cur = cur->parent;
- }
-
- if (cur->parent) {
- if (cur->parent->link[1]) {
- // have parent and parent has right child. Attach the new node
- // to the leftmost node of the parent's right subtree.
- cur = cur->parent->link[1];
- while (cur->link[0]) {
- cur = cur->link[0];
- }
- } else {
- // have parent, but parent has no right child. This can
- // only happen when the last node is a right child. So
- // attach the new node to its parent.
- cur = cur->parent;
- }
- } else {
- // have no parent, attach the new node to a new level. We're at the
- // root, so drop down left to obtain the node where we'll attach
- // the new node.
- while (cur->link[0]) {
- cur = cur->link[0];
- }
- }
-
- ASSERT((!cur->link[0] && !cur->link[1]) || (cur->link[0] && !cur->link[1]))
-
- // attach new node
- // the new node becomes the new last node
- h->last = node;
- cur->link[!!cur->link[0]] = node;
- node->parent = cur;
- node->link[0] = NULL;
- node->link[1] = NULL;
-
- // restore heap property
- while (node->parent && _BHeap_compare_nodes(h, node->parent, node) > 0) {
- _BHeap_move_one_up(h, node);
- }
-
- BHEAP_ASSERT(h)
- }
- void BHeap_Remove (BHeap *h, BHeapNode *node)
- {
- ASSERT(!h->in_handler)
-
- if (!node->parent && !node->link[0] && !node->link[1]) {
- h->root = NULL;
- h->last = NULL;
-
- BHEAP_ASSERT(h)
- return;
- }
-
- // locate the node before the last node
- BHeapNode *cur = h->last;
- while (cur->parent && cur == cur->parent->link[0]) {
- cur = cur->parent;
- }
- if (cur->parent) {
- ASSERT(cur->parent->link[0])
- cur = cur->parent->link[0];
- while (cur->link[1]) {
- cur = cur->link[1];
- }
- } else {
- while (cur->link[1]) {
- cur = cur->link[1];
- }
- }
-
- // disconnect last
- ASSERT(h->last->parent)
- h->last->parent->link[h->last == h->last->parent->link[1]] = NULL;
-
- if (node == h->last) {
- // deleting last; set new last
- h->last = cur;
- } else {
- // not deleting last; move last to node's place
- BHeapNode *srcnode = h->last;
- _BHeap_replace_node(h, node, srcnode);
- // set new last unless node=cur; in this case it stays the same
- if (node != cur) {
- h->last = cur;
- }
-
- // restore heap property
- if (srcnode->parent && _BHeap_compare_nodes(h, srcnode, srcnode->parent) < 0) {
- do {
- _BHeap_move_one_up(h, srcnode);
- } while (srcnode->parent && _BHeap_compare_nodes(h, srcnode, srcnode->parent) < 0);
- } else {
- while (srcnode->link[0] || srcnode->link[1]) {
- int side = (srcnode->link[1] && (_BHeap_compare_nodes(h, srcnode->link[0], srcnode->link[1]) >= 0));
- if (_BHeap_compare_nodes(h, srcnode, srcnode->link[side]) > 0) {
- _BHeap_move_one_up(h, srcnode->link[side]);
- } else {
- break;
- }
- }
- }
- }
-
- BHEAP_ASSERT(h)
- }
- BHeapNode * BHeap_GetFirst (BHeap *h)
- {
- ASSERT(!h->in_handler)
-
- return h->root;
- }
- #endif
|