BHeap.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. /**
  2. * @file BHeap.h
  3. * @author Ambroz Bizjak <ambrop7@gmail.com>
  4. *
  5. * @section LICENSE
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. Neither the name of the author nor the
  15. * names of its contributors may be used to endorse or promote products
  16. * derived from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  19. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  22. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  25. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  27. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. *
  29. * @section DESCRIPTION
  30. *
  31. * Binary heap.
  32. */
  33. #ifndef BADVPN_STRUCTURE_BHEAP_H
  34. #define BADVPN_STRUCTURE_BHEAP_H
  35. //#define BHEAP_DEBUG
  36. #include <stdint.h>
  37. #include <stddef.h>
  38. #include <misc/debug.h>
  39. /**
  40. * Handler function called by heap algorithms to compare two values.
  41. * For any two values, the comparator must always return the same result.
  42. * The <= relation defined by the comparator must be a total order.
  43. * Values are obtained like that:
  44. * - The value of a node in the heap, or a node that is being inserted is:
  45. * (uint8_t *)node + offset.
  46. * - The value being looked up is the same as given to the lookup function.
  47. *
  48. * @param user as in {@link BHeap_Init}
  49. * @param val1 first value
  50. * @param val2 second value
  51. * @return -1 if val1 < val2, 0 if val1 = val2, 1 if val1 > val2
  52. */
  53. typedef int (*BHeap_comparator) (void *user, void *val1, void *val2);
  54. struct BHeapNode;
  55. /**
  56. * Binary heap.
  57. */
  58. typedef struct {
  59. int offset;
  60. BHeap_comparator comparator;
  61. void *user;
  62. struct BHeapNode *root;
  63. struct BHeapNode *last;
  64. #ifndef NDEBUG
  65. int in_handler;
  66. #endif
  67. } BHeap;
  68. /**
  69. * Binary heap node.
  70. */
  71. typedef struct BHeapNode {
  72. struct BHeapNode *parent;
  73. struct BHeapNode *link[2];
  74. } BHeapNode;
  75. /**
  76. * Initializes the heap.
  77. *
  78. * @param o heap to initialize
  79. * @param offset offset of a value from its node
  80. * @param comparator value comparator handler function
  81. * @param user value to pass to comparator
  82. */
  83. static void BHeap_Init (BHeap *h, int offset, BHeap_comparator comparator, void *user);
  84. /**
  85. * Inserts a node into the heap.
  86. * Must not be called from comparator.
  87. *
  88. * @param o the heap
  89. * @param node uninitialized node to insert. Must have a valid value (its value
  90. * may be passed to the comparator during insertion).
  91. */
  92. static void BHeap_Insert (BHeap *h, BHeapNode *node);
  93. /**
  94. * Removes a node from the heap.
  95. * Must not be called from comparator.
  96. *
  97. * @param o the heap
  98. * @param node node to remove
  99. */
  100. static void BHeap_Remove (BHeap *h, BHeapNode *node);
  101. /**
  102. * Returns one of the smallest nodes in the heap.
  103. * Must not be called from comparator.
  104. *
  105. * @param o the heap
  106. * @return one of the smallest nodes in the heap, or NULL if there
  107. * are no nodes
  108. */
  109. static BHeapNode * BHeap_GetFirst (BHeap *h);
  110. static void * _BHeap_node_value (BHeap *o, BHeapNode *n)
  111. {
  112. return ((uint8_t *)n + o->offset);
  113. }
  114. static int _BHeap_compare_values (BHeap *o, void *v1, void *v2)
  115. {
  116. #ifndef NDEBUG
  117. o->in_handler = 1;
  118. #endif
  119. int res = o->comparator(o->user, v1, v2);
  120. #ifndef NDEBUG
  121. o->in_handler = 0;
  122. #endif
  123. ASSERT(res == -1 || res == 0 || res == 1)
  124. return res;
  125. }
  126. static int _BHeap_compare_nodes (BHeap *o, BHeapNode *n1, BHeapNode *n2)
  127. {
  128. return _BHeap_compare_values(o, _BHeap_node_value(o, n1), _BHeap_node_value(o, n2));
  129. }
  130. #ifdef BHEAP_DEBUG
  131. #define BHEAP_ASSERT(_h) _BHeap_assert(_h);
  132. #else
  133. #define BHEAP_ASSERT(_h)
  134. #endif
  135. #ifdef BHEAP_DEBUG
  136. struct _BHeap_assert_data {
  137. int state;
  138. int level;
  139. BHeapNode *prev_leaf;
  140. };
  141. #define BHEAP_ASSERT_STATE_NODEPTH 1
  142. #define BHEAP_ASSERT_STATE_LOWEST 2
  143. #define BHEAP_ASSERT_STATE_LOWESTEND 3
  144. static void _BHeap_assert_recurser (BHeap *h, BHeapNode *n, struct _BHeap_assert_data *ad, int level)
  145. {
  146. if (!n->link[0] && !n->link[1]) {
  147. if (ad->state == BHEAP_ASSERT_STATE_NODEPTH) {
  148. // leftmost none, remember depth
  149. ad->state = BHEAP_ASSERT_STATE_LOWEST;
  150. ad->level = level;
  151. }
  152. } else {
  153. // drop down
  154. if (n->link[0]) {
  155. ASSERT(_BHeap_compare_nodes(h, n, n->link[0]) <= 0)
  156. ASSERT(n->link[0]->parent == n)
  157. _BHeap_assert_recurser(h, n->link[0], ad, level + 1);
  158. }
  159. if (n->link[1]) {
  160. ASSERT(_BHeap_compare_nodes(h, n, n->link[1]) <= 0)
  161. ASSERT(n->link[1]->parent == n)
  162. _BHeap_assert_recurser(h, n->link[1], ad, level + 1);
  163. }
  164. }
  165. ASSERT(ad->state == BHEAP_ASSERT_STATE_LOWEST || ad->state == BHEAP_ASSERT_STATE_LOWESTEND)
  166. if (level < ad->level - 1) {
  167. ASSERT(n->link[0] && n->link[1])
  168. }
  169. else if (level == ad->level - 1) {
  170. switch (ad->state) {
  171. case BHEAP_ASSERT_STATE_LOWEST:
  172. if (!n->link[0]) {
  173. ad->state = BHEAP_ASSERT_STATE_LOWESTEND;
  174. ASSERT(!n->link[1])
  175. ASSERT(ad->prev_leaf == h->last)
  176. } else {
  177. if (!n->link[1]) {
  178. ad->state = BHEAP_ASSERT_STATE_LOWESTEND;
  179. ASSERT(ad->prev_leaf == h->last)
  180. }
  181. }
  182. break;
  183. case BHEAP_ASSERT_STATE_LOWESTEND:
  184. ASSERT(!n->link[0] && !n->link[1])
  185. break;
  186. }
  187. }
  188. else if (level == ad->level) {
  189. ASSERT(ad->state == BHEAP_ASSERT_STATE_LOWEST)
  190. ASSERT(!n->link[0] && !n->link[1])
  191. ad->prev_leaf = n;
  192. }
  193. else {
  194. ASSERT(0)
  195. }
  196. }
  197. static void _BHeap_assert (BHeap *h)
  198. {
  199. struct _BHeap_assert_data ad;
  200. ad.state = BHEAP_ASSERT_STATE_NODEPTH;
  201. ad.prev_leaf = NULL;
  202. if (h->root) {
  203. ASSERT(h->last)
  204. ASSERT(!h->root->parent)
  205. _BHeap_assert_recurser(h, h->root, &ad, 0);
  206. if (ad.state == BHEAP_ASSERT_STATE_LOWEST) {
  207. ASSERT(ad.prev_leaf == h->last)
  208. }
  209. } else {
  210. ASSERT(!h->last)
  211. }
  212. }
  213. #endif
  214. static void _BHeap_move_one_up (BHeap *h, BHeapNode *n)
  215. {
  216. ASSERT(n->parent)
  217. BHeapNode *p = n->parent;
  218. if (p->parent) {
  219. p->parent->link[p == p->parent->link[1]] = n;
  220. } else {
  221. h->root = n;
  222. }
  223. n->parent = p->parent;
  224. int nside = (n == p->link[1]);
  225. BHeapNode *c = p->link[!nside];
  226. p->link[0] = n->link[0];
  227. if (p->link[0]) {
  228. p->link[0]->parent = p;
  229. }
  230. p->link[1] = n->link[1];
  231. if (p->link[1]) {
  232. p->link[1]->parent = p;
  233. }
  234. n->link[nside] = p;
  235. p->parent = n;
  236. n->link[!nside] = c;
  237. if (c) {
  238. c->parent = n;
  239. }
  240. if (n == h->last) {
  241. h->last = p;
  242. }
  243. }
  244. static void _BHeap_replace_node (BHeap *h, BHeapNode *d, BHeapNode *s)
  245. {
  246. if (d->parent) {
  247. d->parent->link[d == d->parent->link[1]] = s;
  248. } else {
  249. h->root = s;
  250. }
  251. s->parent = d->parent;
  252. s->link[0] = d->link[0];
  253. if (s->link[0]) {
  254. s->link[0]->parent = s;
  255. }
  256. s->link[1] = d->link[1];
  257. if (s->link[1]) {
  258. s->link[1]->parent = s;
  259. }
  260. }
  261. void BHeap_Init (BHeap *h, int offset, BHeap_comparator comparator, void *user)
  262. {
  263. h->offset = offset;
  264. h->comparator = comparator;
  265. h->user = user;
  266. h->root = NULL;
  267. h->last = NULL;
  268. #ifndef NDEBUG
  269. h->in_handler = 0;
  270. #endif
  271. BHEAP_ASSERT(h)
  272. }
  273. void BHeap_Insert (BHeap *h, BHeapNode *node)
  274. {
  275. ASSERT(!h->in_handler)
  276. if (!h->root) {
  277. // insert to root
  278. h->root = node;
  279. h->last = node;
  280. node->parent = NULL;
  281. node->link[0] = NULL;
  282. node->link[1] = NULL;
  283. BHEAP_ASSERT(h)
  284. return;
  285. }
  286. // find the node to insert to
  287. // start with current last node and walk up left as much as possible.
  288. // That is, keep replacing the current node with the parent as long as it
  289. // exists and the current node is its right child.
  290. BHeapNode *cur = h->last;
  291. while (cur->parent && cur == cur->parent->link[1]) {
  292. cur = cur->parent;
  293. }
  294. if (cur->parent) {
  295. if (cur->parent->link[1]) {
  296. // have parent and parent has right child. Attach the new node
  297. // to the leftmost node of the parent's right subtree.
  298. cur = cur->parent->link[1];
  299. while (cur->link[0]) {
  300. cur = cur->link[0];
  301. }
  302. } else {
  303. // have parent, but parent has no right child. This can
  304. // only happen when the last node is a right child. So
  305. // attach the new node to its parent.
  306. cur = cur->parent;
  307. }
  308. } else {
  309. // have no parent, attach the new node to a new level. We're at the
  310. // root, so drop down left to obtain the node where we'll attach
  311. // the new node.
  312. while (cur->link[0]) {
  313. cur = cur->link[0];
  314. }
  315. }
  316. ASSERT((!cur->link[0] && !cur->link[1]) || (cur->link[0] && !cur->link[1]))
  317. // attach new node
  318. // the new node becomes the new last node
  319. h->last = node;
  320. cur->link[!!cur->link[0]] = node;
  321. node->parent = cur;
  322. node->link[0] = NULL;
  323. node->link[1] = NULL;
  324. // restore heap property
  325. while (node->parent && _BHeap_compare_nodes(h, node->parent, node) > 0) {
  326. _BHeap_move_one_up(h, node);
  327. }
  328. BHEAP_ASSERT(h)
  329. }
  330. void BHeap_Remove (BHeap *h, BHeapNode *node)
  331. {
  332. ASSERT(!h->in_handler)
  333. if (!node->parent && !node->link[0] && !node->link[1]) {
  334. h->root = NULL;
  335. h->last = NULL;
  336. BHEAP_ASSERT(h)
  337. return;
  338. }
  339. // locate the node before the last node
  340. BHeapNode *cur = h->last;
  341. while (cur->parent && cur == cur->parent->link[0]) {
  342. cur = cur->parent;
  343. }
  344. if (cur->parent) {
  345. ASSERT(cur->parent->link[0])
  346. cur = cur->parent->link[0];
  347. while (cur->link[1]) {
  348. cur = cur->link[1];
  349. }
  350. } else {
  351. while (cur->link[1]) {
  352. cur = cur->link[1];
  353. }
  354. }
  355. // disconnect last
  356. ASSERT(h->last->parent)
  357. h->last->parent->link[h->last == h->last->parent->link[1]] = NULL;
  358. if (node == h->last) {
  359. // deleting last; set new last
  360. h->last = cur;
  361. } else {
  362. // not deleting last; move last to node's place
  363. BHeapNode *srcnode = h->last;
  364. _BHeap_replace_node(h, node, srcnode);
  365. // set new last unless node=cur; in this case it stays the same
  366. if (node != cur) {
  367. h->last = cur;
  368. }
  369. // restore heap property
  370. if (srcnode->parent && _BHeap_compare_nodes(h, srcnode, srcnode->parent) < 0) {
  371. do {
  372. _BHeap_move_one_up(h, srcnode);
  373. } while (srcnode->parent && _BHeap_compare_nodes(h, srcnode, srcnode->parent) < 0);
  374. } else {
  375. while (srcnode->link[0] || srcnode->link[1]) {
  376. int side = (srcnode->link[1] && (_BHeap_compare_nodes(h, srcnode->link[0], srcnode->link[1]) >= 0));
  377. if (_BHeap_compare_nodes(h, srcnode, srcnode->link[side]) > 0) {
  378. _BHeap_move_one_up(h, srcnode->link[side]);
  379. } else {
  380. break;
  381. }
  382. }
  383. }
  384. }
  385. BHEAP_ASSERT(h)
  386. }
  387. BHeapNode * BHeap_GetFirst (BHeap *h)
  388. {
  389. ASSERT(!h->in_handler)
  390. return h->root;
  391. }
  392. #endif